Skip to content

Commit c173cab

Browse files
Merge pull request #53 from FritzBlignaut/bug/fix-plugin-keyup-handler
fix: correct keyUp handler for plugin actions
2 parents 02fca26 + ed5d6fc commit c173cab

3 files changed

Lines changed: 80 additions & 12 deletions

File tree

discord-plugin/com.discord.streamdeck.sdPlugin/bin/plugin.cjs

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,27 +34,89 @@ try {
3434
console.warn(`[${pluginUUID}] WARNING: xdotool not found. Install it with: sudo apt install xdotool`)
3535
}
3636

37+
/**
38+
* Find Discord's X11 window ID.
39+
* Returns the window ID string, or null if Discord is not running / not found.
40+
*/
41+
function getDiscordWindowId() {
42+
// Try by window class first (most reliable)
43+
const byClass = spawnSync('xdotool', ['search', '--class', 'discord'], { stdio: 'pipe' })
44+
if (byClass.status === 0) {
45+
const ids = byClass.stdout.toString().trim().split('\n').filter(Boolean)
46+
if (ids.length > 0) return ids[ids.length - 1]
47+
}
48+
// Fallback: search by window title
49+
const byName = spawnSync('xdotool', ['search', '--name', 'Discord'], { stdio: 'pipe' })
50+
if (byName.status === 0) {
51+
const ids = byName.stdout.toString().trim().split('\n').filter(Boolean)
52+
if (ids.length > 0) return ids[ids.length - 1]
53+
}
54+
console.warn(`[${pluginUUID}] Could not find Discord window — sending key to focused window instead`)
55+
return null
56+
}
57+
58+
/**
59+
* Focus `winId`, run `action()`, then restore focus to the previously active
60+
* window. Uses XTestFakeKeyEvent (not XSendEvent) so Electron/Chromium treats
61+
* the event as a trusted hardware input (isTrusted=true in JavaScript).
62+
* xdotool key --window uses XSendEvent which Discord ignores.
63+
*/
64+
function withDiscordFocus(winId, action) {
65+
const prevResult = spawnSync('xdotool', ['getactivewindow'], { stdio: 'pipe' })
66+
const prevWinId = prevResult.status === 0 ? prevResult.stdout.toString().trim() : null
67+
68+
spawnSync('xdotool', ['windowfocus', '--sync', winId], { stdio: 'pipe' })
69+
action()
70+
if (prevWinId && prevWinId !== winId) {
71+
spawnSync('xdotool', ['windowfocus', '--sync', prevWinId], { stdio: 'pipe' })
72+
}
73+
}
74+
3775
function xdotoolKey(hotkey) {
3876
if (!xdotoolAvailable) return
39-
const result = spawnSync('xdotool', ['key', hotkey], { stdio: 'pipe' })
40-
if (result.status !== 0) {
41-
console.warn(`[${pluginUUID}] xdotool key failed for "${hotkey}":`, result.stderr?.toString().trim())
77+
const winId = getDiscordWindowId()
78+
const args = ['key', '--clearmodifiers', hotkey]
79+
console.log(`[${pluginUUID}] xdotool${winId ? ' (via Discord focus)' : ''} ${args.join(' ')}`)
80+
if (winId) {
81+
withDiscordFocus(winId, () => {
82+
const r = spawnSync('xdotool', args, { stdio: 'pipe' })
83+
if (r.status !== 0) console.warn(`[${pluginUUID}] xdotool key failed:`, r.stderr?.toString().trim())
84+
})
85+
} else {
86+
const r = spawnSync('xdotool', args, { stdio: 'pipe' })
87+
if (r.status !== 0) console.warn(`[${pluginUUID}] xdotool key failed:`, r.stderr?.toString().trim())
4288
}
4389
}
4490

4591
function xdotoolKeyDown(hotkey) {
4692
if (!xdotoolAvailable) return
47-
const result = spawnSync('xdotool', ['keydown', hotkey], { stdio: 'pipe' })
48-
if (result.status !== 0) {
49-
console.warn(`[${pluginUUID}] xdotool keydown failed for "${hotkey}":`, result.stderr?.toString().trim())
93+
const winId = getDiscordWindowId()
94+
const args = ['keydown', '--clearmodifiers', hotkey]
95+
console.log(`[${pluginUUID}] xdotool${winId ? ' (via Discord focus)' : ''} ${args.join(' ')}`)
96+
if (winId) {
97+
withDiscordFocus(winId, () => {
98+
const r = spawnSync('xdotool', args, { stdio: 'pipe' })
99+
if (r.status !== 0) console.warn(`[${pluginUUID}] xdotool keydown failed:`, r.stderr?.toString().trim())
100+
})
101+
} else {
102+
const r = spawnSync('xdotool', args, { stdio: 'pipe' })
103+
if (r.status !== 0) console.warn(`[${pluginUUID}] xdotool keydown failed:`, r.stderr?.toString().trim())
50104
}
51105
}
52106

53107
function xdotoolKeyUp(hotkey) {
54108
if (!xdotoolAvailable) return
55-
const result = spawnSync('xdotool', ['keyup', hotkey], { stdio: 'pipe' })
56-
if (result.status !== 0) {
57-
console.warn(`[${pluginUUID}] xdotool keyup failed for "${hotkey}":`, result.stderr?.toString().trim())
109+
const winId = getDiscordWindowId()
110+
const args = ['keyup', '--clearmodifiers', hotkey]
111+
console.log(`[${pluginUUID}] xdotool${winId ? ' (via Discord focus)' : ''} ${args.join(' ')}`)
112+
if (winId) {
113+
withDiscordFocus(winId, () => {
114+
const r = spawnSync('xdotool', args, { stdio: 'pipe' })
115+
if (r.status !== 0) console.warn(`[${pluginUUID}] xdotool keyup failed:`, r.stderr?.toString().trim())
116+
})
117+
} else {
118+
const r = spawnSync('xdotool', args, { stdio: 'pipe' })
119+
if (r.status !== 0) console.warn(`[${pluginUUID}] xdotool keyup failed:`, r.stderr?.toString().trim())
58120
}
59121
}
60122

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@
3636
"electron/**",
3737
"package.json"
3838
],
39+
"extraResources": [
40+
{
41+
"from": "public/bridge/sdpi-bridge.js",
42+
"to": "bridge/sdpi-bridge.js"
43+
}
44+
],
3945
"linux": {
4046
"target": [
4147
{

src/App.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2479,9 +2479,9 @@ export default function App() {
24792479
setPressedKey(p => p === index ? null : p)
24802480
const config = buttonConfigsRef.current[index]
24812481
// Forward keyUp to plugin processes (needed for Push-to-Talk / Push-to-Mute)
2482-
if (config?.type?.includes('.')) {
2483-
const context = JSON.stringify({ index, actionUUID: config.type, pluginUUID: config.pluginUUID })
2484-
window.streamDeck?.sendToPlugin?.(config.pluginUUID, config.type, 'keyUp', { ...config }, context)
2482+
if (config?.action?.type?.includes('.')) {
2483+
const context = JSON.stringify({ index, actionUUID: config.action.type, pluginUUID: config.action.pluginUUID })
2484+
window.streamDeck?.sendToPlugin?.(config.action.pluginUUID, config.action.type, 'keyUp', { ...config.action }, context)
24852485
}
24862486

24872487
if (config?.pressedIconDataUrl) {

0 commit comments

Comments
 (0)