Keybind setting change (#480)

This commit is contained in:
Jake 2025-11-05 19:44:15 +00:00 • committed by GitHub
parent a659624fec
commit 871de99ad7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 201 additions and 14 deletions

View file

@ -5,23 +5,145 @@
*/
import { definePluginSettings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
import { EquicordDevs, IS_MAC } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { useState } from "@webpack/common";
import { cleanupCommandPaletteRuntime, registerBuiltInCommands, wrapChatBarChildren } from "./registry";
import { CommandPaletteSettingsPanel } from "./settingsPanel";
import { openCommandPalette } from "./ui";
const DEFAULT_KEYS = IS_MAC ? ["Meta", "Shift", "P"] : ["Control", "Shift", "P"];
const DEFAULT_HOTKEY = DEFAULT_KEYS.join("+");
const cl = classNameFactory("vc-cp-");
let isRecordingGlobal = false;
let openScheduled = false;
export const settings = definePluginSettings({
hotkey: {
description: "Hotkey used to open the command palette (format: Ctrl+Shift+P)",
type: OptionType.STRING,
default: DEFAULT_HOTKEY
description: "Hotkey used to open the command palette",
type: OptionType.COMPONENT,
default: DEFAULT_KEYS,
component: () => {
const [isRecording, setIsRecording] = useState(false);
const [currentKeys, setCurrentKeys] = useState<string[]>([]);
const recordKeybind = (setIsRecording: (value: boolean) => void) => {
const pressedKeys: Set<string> = new Set();
const keyLists: string[][] = [];
let recordingTimeout: number | null = null;
setIsRecording(true);
setCurrentKeys([]);
isRecordingGlobal = true;
const updateKeys = () => {
const currentKeyArray = Array.from(pressedKeys);
setCurrentKeys(currentKeyArray);
keyLists.push(currentKeyArray);
if (recordingTimeout) {
clearTimeout(recordingTimeout);
}
recordingTimeout = window.setTimeout(() => {
const longestArray = keyLists.reduce((a, b) => a.length > b.length ? a : b);
if (longestArray.length > 0) {
settings.store.hotkey = longestArray.map(key => key.toLowerCase());
}
setIsRecording(false);
setCurrentKeys([]);
isRecordingGlobal = false;
document.removeEventListener("keydown", keydownListener);
document.removeEventListener("keyup", keyupListener);
}, 500);
};
const getKeyName = (key: string) => {
const keyMap: Record<string, string> = {
"Control": "Control",
"Shift": "Shift",
"Alt": "Alt",
"Meta": "Meta"
};
return keyMap[key] || key;
};
const keydownListener = (e: KeyboardEvent) => {
if (e.ctrlKey) pressedKeys.add("Control");
else pressedKeys.delete("Control");
if (e.shiftKey) pressedKeys.add("Shift");
else pressedKeys.delete("Shift");
if (e.altKey) pressedKeys.add("Alt");
else pressedKeys.delete("Alt");
if (e.metaKey) pressedKeys.add("Meta");
else pressedKeys.delete("Meta");
const keyName = getKeyName(e.key);
pressedKeys.add(keyName);
updateKeys();
};
const keyupListener = (e: KeyboardEvent) => {
if (e.ctrlKey) pressedKeys.add("Control");
else pressedKeys.delete("Control");
if (e.shiftKey) pressedKeys.add("Shift");
else pressedKeys.delete("Shift");
if (e.altKey) pressedKeys.add("Alt");
else pressedKeys.delete("Alt");
if (e.metaKey) pressedKeys.add("Meta");
else pressedKeys.delete("Meta");
const keyName = getKeyName(e.key);
pressedKeys.delete(keyName);
updateKeys();
};
document.addEventListener("keydown", keydownListener);
document.addEventListener("keyup", keyupListener);
};
const getKeySymbol = (key: string) => {
const normalizedKey = key.charAt(0).toUpperCase() + key.slice(1).toLowerCase();
const keySymbols: Record<string, string> = {
"Control": "⌃",
"Shift": "⇧",
"Alt": "⌥",
"Meta": "⌘"
};
return keySymbols[normalizedKey] || "";
};
const displayKeys = isRecording ? currentKeys : settings.store.hotkey;
const displayText = displayKeys.length > 0
? displayKeys.map(word => {
const symbol = getKeySymbol(word);
const displayWord = word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
return symbol ? `${symbol}${displayWord}` : displayWord;
}).join(" + ")
: "No keybind set";
return (
<>
<div className={cl("key-recorder-container")}>
<div className={`${cl("key-recorder")} ${isRecording ? cl("recording") : ""}`}>
<span className={cl("key-display")}>{displayText}</span>
<button className={`${cl("key-recorder-button")} ${isRecording ? cl("recording-button") : ""}`} onClick={() => recordKeybind(setIsRecording)} disabled={isRecording}>
{isRecording ? "Recording..." : "Record keybind"}
</button>
</div>
</div>
</>
);
}
},
visualStyle: {
description: "Palette appearance",
@ -50,16 +172,13 @@ export const settings = definePluginSettings({
function getConfiguredHotkey() {
const raw = settings.store.hotkey;
const hotkeyString = typeof raw === "string" ? raw.trim() : "";
if (!hotkeyString) return DEFAULT_KEYS;
const parts = hotkeyString
.split("+")
.map(part => part.trim())
.filter(Boolean);
return parts.length > 0 ? parts : DEFAULT_KEYS;
if (Array.isArray(raw) && raw.length > 0) {
return raw;
}
if (typeof raw === "string" && (raw as string).trim()) {
return (raw as string).split("+").map(part => part.trim()).filter(Boolean);
}
return DEFAULT_KEYS;
}
function matchesHotkey(e: KeyboardEvent) {
@ -142,6 +261,7 @@ export default definePlugin({
},
handleKeydown(e: KeyboardEvent) {
if (isRecordingGlobal) return;
if (!matchesHotkey(e)) return;
if (shouldIgnoreTarget(e.target) && !hotkeyUsesModifiers()) return;
e.preventDefault();

View file

@ -681,6 +681,73 @@
background: rgb(255 255 255 / 12%);
}
/* Keybind recorder styles */
.vc-cp-key-recorder-container {
position: relative;
display: block;
cursor: pointer;
height: 40px;
width: 20rem;
}
.vc-cp-key-recorder {
display: flex;
align-items: center;
justify-content: space-between;
border-radius: 3px;
background-color: hsl(var(--black-500-hsl) / 10%);
color: var(--header-primary);
line-height: 22px;
font-weight: 600;
padding: 10px;
text-overflow: ellipsis;
overflow: hidden;
border: 1px solid;
border-color: hsl(var(--black-500-hsl) / 30%);
transition: border .15s ease;
user-select: none;
font-family: var(--font-primary);
}
.vc-cp-key-display {
flex: 1;
text-overflow: ellipsis;
overflow: hidden;
margin-right: 10px;
}
.vc-cp-recording {
animation: shadowPulse_b16790 1s ease-in infinite;
box-shadow: 0 0 6px hsl(var(--red-400-hsl) / 30%);
border-color: hsl(var(--red-400-hsl) / 30%);
color: var(--status-danger);
}
.vc-cp-key-recorder:hover {
border-color: hsl(var(--red-400-hsl) / 30%);
}
.vc-cp-recording-button {
color: var(--status-danger) !important;
background-color: hsl(var(--red-400-hsl) / 10%) !important;
opacity: 1;
transition: opacity .2s ease-in-out, transform .2s ease-in-out;
}
.vc-cp-key-recorder-button {
flex-shrink: 0;
height: 30px;
width: 128px;
color: var(--white-500);
background-color: var(--button-secondary-background);
border-radius: 10px;
transition: background-color 0.15s ease;
}
.vc-cp-key-recorder-button:hover {
background-color: var(--button-secondary-background-hover);
}
/* stylelint-enable no-descending-specificity */
/* fuck you css */