qdesk 1.0.12 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bank/key-bindings.js +7 -1
- package/dist/index.js +8 -3
- package/dist/koffi/chord-utils.js +99 -29
- package/dist/process/cli.js +1 -1
- package/package.json +34 -34
|
@@ -18,6 +18,12 @@ export class KeyBindings {
|
|
|
18
18
|
console.log(`[add] Bound ${chord} -> "${info.name}"`);
|
|
19
19
|
save(this.bindings);
|
|
20
20
|
}
|
|
21
|
+
reportMissing(chord) {
|
|
22
|
+
const info = this.bindings.get(chord);
|
|
23
|
+
if (info) {
|
|
24
|
+
info.missing = true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
21
27
|
delete(chord) {
|
|
22
28
|
const output = this.bindings.delete(chord);
|
|
23
29
|
if (output) {
|
|
@@ -33,7 +39,7 @@ export class KeyBindings {
|
|
|
33
39
|
return this.bindings.size;
|
|
34
40
|
}
|
|
35
41
|
entries() {
|
|
36
|
-
return this.bindings.entries();
|
|
42
|
+
return [...this.bindings.entries()].sort(([chordA], [chordB]) => chordA.localeCompare(chordB));
|
|
37
43
|
}
|
|
38
44
|
}
|
|
39
45
|
function load() {
|
package/dist/index.js
CHANGED
|
@@ -93,7 +93,11 @@ startListening({
|
|
|
93
93
|
name: binding.name,
|
|
94
94
|
type: "missing",
|
|
95
95
|
});
|
|
96
|
-
bindings.
|
|
96
|
+
bindings.reportMissing(chord);
|
|
97
|
+
setScreenHue("remove");
|
|
98
|
+
setTimeout(() => {
|
|
99
|
+
setScreenHue("off");
|
|
100
|
+
}, 50);
|
|
97
101
|
}
|
|
98
102
|
else if (result === "activated") {
|
|
99
103
|
logSwitch({
|
|
@@ -119,8 +123,9 @@ function printBindings() {
|
|
|
119
123
|
console.log(" (none)");
|
|
120
124
|
}
|
|
121
125
|
else {
|
|
126
|
+
const maxBindingLength = Math.max(...Array.from(bindings.entries()).map(([chord]) => chord.length));
|
|
122
127
|
for (const [chord, window] of bindings.entries()) {
|
|
123
|
-
console.log(` ${chord}
|
|
128
|
+
console.log(` ${chord.padEnd(maxBindingLength)} ->${window.missing ? "❓" : " "} "${window.name}"`);
|
|
124
129
|
}
|
|
125
130
|
}
|
|
126
131
|
console.log("");
|
|
@@ -131,7 +136,7 @@ console.log(` Dropping a chord: ${DROP_CHORD}`);
|
|
|
131
136
|
console.log(" CLI overrides: -a <combo>, -d <combo>");
|
|
132
137
|
for (const [chord, window] of bindings.entries()) {
|
|
133
138
|
if (!checkIfWindowExists(window.handle)) {
|
|
134
|
-
bindings.
|
|
139
|
+
bindings.reportMissing(chord);
|
|
135
140
|
}
|
|
136
141
|
}
|
|
137
142
|
if (bindings.size > 0) {
|
|
@@ -14,22 +14,104 @@ export const WH_KEYBOARD_LL = 13;
|
|
|
14
14
|
export const WM_KEYDOWN = 0x0100;
|
|
15
15
|
export const WM_SYSKEYDOWN = 0x0104;
|
|
16
16
|
export const PM_REMOVE = 0x0001;
|
|
17
|
+
const VK_TOKEN_TO_CODE = {
|
|
18
|
+
backspace: 0x08,
|
|
19
|
+
tab: 0x09,
|
|
20
|
+
clear: 0x0c,
|
|
21
|
+
enter: 0x0d,
|
|
22
|
+
return: 0x0d,
|
|
23
|
+
pause: 0x13,
|
|
24
|
+
capslock: 0x14,
|
|
25
|
+
esc: VK_ESCAPE,
|
|
26
|
+
escape: VK_ESCAPE,
|
|
27
|
+
space: 0x20,
|
|
28
|
+
pageup: 0x21,
|
|
29
|
+
pagedown: 0x22,
|
|
30
|
+
end: 0x23,
|
|
31
|
+
home: 0x24,
|
|
32
|
+
left: 0x25,
|
|
33
|
+
up: 0x26,
|
|
34
|
+
right: 0x27,
|
|
35
|
+
down: 0x28,
|
|
36
|
+
printscreen: 0x2c,
|
|
37
|
+
prtsc: 0x2c,
|
|
38
|
+
snapshot: 0x2c,
|
|
39
|
+
insert: 0x2d,
|
|
40
|
+
delete: 0x2e,
|
|
41
|
+
num0: 0x60,
|
|
42
|
+
num1: 0x61,
|
|
43
|
+
num2: 0x62,
|
|
44
|
+
num3: 0x63,
|
|
45
|
+
num4: 0x64,
|
|
46
|
+
num5: 0x65,
|
|
47
|
+
num6: 0x66,
|
|
48
|
+
num7: 0x67,
|
|
49
|
+
num8: 0x68,
|
|
50
|
+
num9: 0x69,
|
|
51
|
+
num_mul: 0x6a,
|
|
52
|
+
num_add: 0x6b,
|
|
53
|
+
num_sub: 0x6d,
|
|
54
|
+
num_dec: 0x6e,
|
|
55
|
+
num_div: 0x6f,
|
|
56
|
+
};
|
|
57
|
+
const VK_CODE_TO_TOKEN = new Map(Object.entries(VK_TOKEN_TO_CODE).map(([token, code]) => [code, token]));
|
|
58
|
+
VK_CODE_TO_TOKEN.set(VK_ESCAPE, "esc");
|
|
59
|
+
VK_CODE_TO_TOKEN.set(0x0d, "enter");
|
|
60
|
+
VK_CODE_TO_TOKEN.set(0x2c, "printscreen");
|
|
61
|
+
const MODIFIER_TOKENS = new Set([
|
|
62
|
+
"ctrl",
|
|
63
|
+
"control",
|
|
64
|
+
"alt",
|
|
65
|
+
"shift",
|
|
66
|
+
"win",
|
|
67
|
+
"meta",
|
|
68
|
+
]);
|
|
69
|
+
function normalizeKeyToken(rawKey) {
|
|
70
|
+
const key = rawKey.trim().toLowerCase();
|
|
71
|
+
if (!key) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
if (/^[0-9a-z]$/.test(key)) {
|
|
75
|
+
return key;
|
|
76
|
+
}
|
|
77
|
+
if (/^f([1-9]|1[0-9]|2[0-4])$/.test(key)) {
|
|
78
|
+
return key;
|
|
79
|
+
}
|
|
80
|
+
if (VK_TOKEN_TO_CODE[key] !== undefined) {
|
|
81
|
+
return VK_CODE_TO_TOKEN.get(VK_TOKEN_TO_CODE[key]) ?? key;
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
function keyTokenToVk(key) {
|
|
86
|
+
if (/^[0-9]$/.test(key)) {
|
|
87
|
+
return key.charCodeAt(0);
|
|
88
|
+
}
|
|
89
|
+
if (/^[a-z]$/.test(key)) {
|
|
90
|
+
return key.toUpperCase().charCodeAt(0);
|
|
91
|
+
}
|
|
92
|
+
const functionMatch = /^f([1-9]|1[0-9]|2[0-4])$/.exec(key);
|
|
93
|
+
if (functionMatch) {
|
|
94
|
+
const fn = Number(functionMatch[1]);
|
|
95
|
+
return 0x70 + (fn - 1);
|
|
96
|
+
}
|
|
97
|
+
return VK_TOKEN_TO_CODE[key] ?? -1;
|
|
98
|
+
}
|
|
17
99
|
export function normalizeChord(chord) {
|
|
18
100
|
chord = chord.trim().toLowerCase();
|
|
19
101
|
const parts = chord
|
|
20
102
|
.split("+")
|
|
21
103
|
.map((part) => part.trim().toLowerCase())
|
|
22
104
|
.filter(Boolean);
|
|
23
|
-
if (parts.length
|
|
105
|
+
if (parts.length === 0) {
|
|
24
106
|
return null;
|
|
25
107
|
}
|
|
26
|
-
const key = parts[parts.length - 1];
|
|
27
|
-
if (
|
|
108
|
+
const key = normalizeKeyToken(parts[parts.length - 1]);
|
|
109
|
+
if (!key) {
|
|
28
110
|
return null;
|
|
29
111
|
}
|
|
30
112
|
const modifiers = new Set(parts.slice(0, -1));
|
|
31
113
|
for (const mod of modifiers) {
|
|
32
|
-
if (!
|
|
114
|
+
if (!MODIFIER_TOKENS.has(mod)) {
|
|
33
115
|
return null;
|
|
34
116
|
}
|
|
35
117
|
}
|
|
@@ -46,20 +128,20 @@ export function normalizeChord(chord) {
|
|
|
46
128
|
if (modifiers.has("win") || modifiers.has("meta")) {
|
|
47
129
|
normalizedMods.push("win");
|
|
48
130
|
}
|
|
49
|
-
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
return `${normalizedMods.join("+")}+${key}`;
|
|
131
|
+
return normalizedMods.length > 0 ? `${normalizedMods.join("+")}+${key}` : key;
|
|
53
132
|
}
|
|
54
133
|
export function parseHotkeyCombo(combo) {
|
|
55
134
|
const parts = combo
|
|
56
135
|
.split("+")
|
|
57
136
|
.map((part) => part.trim().toLowerCase())
|
|
58
137
|
.filter(Boolean);
|
|
59
|
-
if (parts.length
|
|
138
|
+
if (parts.length === 0) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
const key = normalizeKeyToken(parts[parts.length - 1]);
|
|
142
|
+
if (!key) {
|
|
60
143
|
return null;
|
|
61
144
|
}
|
|
62
|
-
const key = parts[parts.length - 1];
|
|
63
145
|
const modifiers = parts.slice(0, -1);
|
|
64
146
|
let modMask = 0;
|
|
65
147
|
const normalizedModifiers = [];
|
|
@@ -84,21 +166,8 @@ export function parseHotkeyCombo(combo) {
|
|
|
84
166
|
return null;
|
|
85
167
|
}
|
|
86
168
|
}
|
|
87
|
-
|
|
88
|
-
if (
|
|
89
|
-
vk = key.charCodeAt(0);
|
|
90
|
-
}
|
|
91
|
-
else if (/^[a-z]$/.test(key)) {
|
|
92
|
-
vk = key.toUpperCase().charCodeAt(0);
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
const functionMatch = /^f([1-9]|1[0-9]|2[0-4])$/.exec(key);
|
|
96
|
-
if (functionMatch) {
|
|
97
|
-
const fn = Number(functionMatch[1]);
|
|
98
|
-
vk = 0x70 + (fn - 1);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if (vk < 0 || modMask === 0) {
|
|
169
|
+
const vk = keyTokenToVk(key);
|
|
170
|
+
if (vk < 0) {
|
|
102
171
|
return null;
|
|
103
172
|
}
|
|
104
173
|
const canonicalModifiers = ["ctrl", "alt", "shift", "win"].filter((mod) => normalizedModifiers.includes(mod));
|
|
@@ -121,6 +190,10 @@ function vkToKeyToken(vkCode) {
|
|
|
121
190
|
if (vkCode >= 0x70 && vkCode <= 0x87) {
|
|
122
191
|
return `f${vkCode - 0x6f}`;
|
|
123
192
|
}
|
|
193
|
+
const named = VK_CODE_TO_TOKEN.get(vkCode);
|
|
194
|
+
if (named) {
|
|
195
|
+
return named;
|
|
196
|
+
}
|
|
124
197
|
return null;
|
|
125
198
|
}
|
|
126
199
|
export function buildCurrentChord(vkCode) {
|
|
@@ -141,8 +214,5 @@ export function buildCurrentChord(vkCode) {
|
|
|
141
214
|
if (isPressed(VK_LWIN) || isPressed(VK_RWIN)) {
|
|
142
215
|
parts.push("win");
|
|
143
216
|
}
|
|
144
|
-
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
return `${parts.join("+")}+${key}`;
|
|
217
|
+
return parts.length > 0 ? `${parts.join("+")}+${key}` : key;
|
|
148
218
|
}
|
package/dist/process/cli.js
CHANGED
|
@@ -17,7 +17,7 @@ function hasCliFlag(flag) {
|
|
|
17
17
|
}
|
|
18
18
|
function getPackageVersion() {
|
|
19
19
|
try {
|
|
20
|
-
const packageJson = readFileSync(new URL("
|
|
20
|
+
const packageJson = readFileSync(new URL("../../package.json", import.meta.url), "utf8");
|
|
21
21
|
const parsed = JSON.parse(packageJson);
|
|
22
22
|
return parsed.version ?? "unknown";
|
|
23
23
|
}
|
package/package.json
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "qdesk",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"type": "module",
|
|
5
|
-
"repository": {
|
|
6
|
-
"type": "git",
|
|
7
|
-
"url": "git+https://github.com/JakeBeaver/qdesk.git"
|
|
8
|
-
},
|
|
9
|
-
"bugs": {
|
|
10
|
-
"url": "https://github.com/JakeBeaver/qdesk/issues"
|
|
11
|
-
},
|
|
12
|
-
"homepage": "https://github.com/JakeBeaver/qdesk#readme",
|
|
13
|
-
"bin": {
|
|
14
|
-
"qdesk": "dist/index.js"
|
|
15
|
-
},
|
|
16
|
-
"files": [
|
|
17
|
-
"dist"
|
|
18
|
-
],
|
|
19
|
-
"scripts": {
|
|
20
|
-
"dev": "tsx src/index.ts",
|
|
21
|
-
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
22
|
-
"build": "pnpm clean && tsc -p tsconfig.json",
|
|
23
|
-
"start": "node dist/index.js",
|
|
24
|
-
"prepack": "pnpm build"
|
|
25
|
-
},
|
|
26
|
-
"dependencies": {
|
|
27
|
-
"koffi": "^3.0.2"
|
|
28
|
-
},
|
|
29
|
-
"devDependencies": {
|
|
30
|
-
"@types/node": "^22.15.30",
|
|
31
|
-
"tsx": "^4.19.4",
|
|
32
|
-
"typescript": "^5.8.3"
|
|
33
|
-
}
|
|
34
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "qdesk",
|
|
3
|
+
"version": "1.0.14",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/JakeBeaver/qdesk.git"
|
|
8
|
+
},
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/JakeBeaver/qdesk/issues"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/JakeBeaver/qdesk#readme",
|
|
13
|
+
"bin": {
|
|
14
|
+
"qdesk": "dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "tsx src/index.ts",
|
|
21
|
+
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
22
|
+
"build": "pnpm clean && tsc -p tsconfig.json",
|
|
23
|
+
"start": "node dist/index.js",
|
|
24
|
+
"prepack": "pnpm build"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"koffi": "^3.0.2"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^22.15.30",
|
|
31
|
+
"tsx": "^4.19.4",
|
|
32
|
+
"typescript": "^5.8.3"
|
|
33
|
+
}
|
|
34
|
+
}
|