mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-10-21 17:01:25 -07:00
feat(overlay): forward mpv mouse and wheel bindings through overlay
- Accept WHEEL_UP/DOWN/LEFT/RIGHT (with modifiers) in keybindings, the plugin, and the settings key editor - Forward mpv's MBTN_* and WHEEL_* bindings from the overlay so double-click fullscreen, wheel volume, and similar inputs work on Hyprland; SubMiner bindings and right-click pause still win - Notify the overlay via mpv-input-bindings:changed when mpv's key set changes, fixing dead imported keys when the overlay loads before mpv connects - Sync README requirements/quick start with the installation guide and fix the Arch MeCab install command (AUR mecab-git)
This commit is contained in:
29 files changed
+643
-157
No files matched your search
@@ -71,6 +71,45 @@ test('persistSessionBindings keeps saved bindings when mpv reload notification f
|
||||
}
|
||||
});
|
||||
|
||||
test('mpv input binding discovery notifies the overlay when the native key set changes', async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-session-native-keys-'));
|
||||
let nativeKeys: unknown = [{ key: '9', cmd: 'add volume -5', priority: 25 }];
|
||||
let notifications = 0;
|
||||
const client = {
|
||||
connected: false,
|
||||
send: () => {},
|
||||
requestProperty: async () => nativeKeys,
|
||||
};
|
||||
const runtime = createSessionBindingsRuntime({
|
||||
configDir: root,
|
||||
getKeybindings: () => [],
|
||||
getConfiguredShortcuts: () => ({ multiCopyTimeoutMs: 1500 }) as never,
|
||||
getResolvedConfig: () => ({ stats: { toggleKey: 's', markWatchedKey: 'w' } }) as ResolvedConfig,
|
||||
getMpvClient: () => client,
|
||||
setSessionBindings: () => {},
|
||||
setSessionBindingsInitialized: () => {},
|
||||
logWarn: () => {},
|
||||
onMpvInputBindingsChanged: () => {
|
||||
notifications += 1;
|
||||
},
|
||||
});
|
||||
try {
|
||||
runtime.persistSessionBindings([]);
|
||||
await runtime.refreshMpvSessionBindings();
|
||||
assert.equal(notifications, 0, 'nothing to announce before mpv connects');
|
||||
client.connected = true;
|
||||
await runtime.refreshMpvSessionBindings();
|
||||
assert.equal(notifications, 1, 'first discovery after connecting must reach the overlay');
|
||||
await runtime.refreshMpvSessionBindings();
|
||||
assert.equal(notifications, 1, 'unchanged discovery must not create a refresh loop');
|
||||
nativeKeys = [{ key: '0', cmd: 'ignore', priority: 25 }];
|
||||
await runtime.refreshMpvSessionBindings();
|
||||
assert.equal(notifications, 2, 'ignored keys still change what the overlay may forward');
|
||||
} finally {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('native prefix conflicts publish the same effective bindings to the overlay and plugin and recover', async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-session-conflict-'));
|
||||
const sequence: CompiledSessionBinding = {
|
||||
|
||||
@@ -25,6 +25,10 @@ export interface SessionBindingsRuntimeDeps {
|
||||
setSessionBindingsInitialized: (initialized: boolean) => void;
|
||||
logWarn: (message: string, details?: unknown) => void;
|
||||
onBindingsChanged?: (bindings: CompiledSessionBinding[]) => void;
|
||||
// Fires when mpv's own key bindings change, including the first discovery after
|
||||
// connecting. The overlay's imported mpv keys depend on them even when the
|
||||
// compiled session bindings stay identical.
|
||||
onMpvInputBindingsChanged?: () => void;
|
||||
onWarning?: (warning: SessionBindingWarning) => void;
|
||||
}
|
||||
|
||||
@@ -41,6 +45,7 @@ export function createSessionBindingsRuntime(deps: SessionBindingsRuntimeDeps):
|
||||
let nativeSnapshot: {
|
||||
client: ReturnType<SessionBindingsRuntimeDeps['getMpvClient']>;
|
||||
keys: string[];
|
||||
signature: string;
|
||||
} | null = null;
|
||||
let pending: {
|
||||
client: ReturnType<SessionBindingsRuntimeDeps['getMpvClient']>;
|
||||
@@ -135,8 +140,15 @@ export function createSessionBindingsRuntime(deps: SessionBindingsRuntimeDeps):
|
||||
try {
|
||||
const raw = await client.requestProperty('input-bindings');
|
||||
if (client !== deps.getMpvClient() || !client.connected) return;
|
||||
nativeSnapshot = { client, keys: parseMpvInputBindingKeys(raw, { includeIgnored: false }) };
|
||||
const signature = JSON.stringify(parseMpvInputBindingKeys(raw));
|
||||
const changed = nativeSnapshot?.client !== client || nativeSnapshot.signature !== signature;
|
||||
nativeSnapshot = {
|
||||
client,
|
||||
keys: parseMpvInputBindingKeys(raw, { includeIgnored: false }),
|
||||
signature,
|
||||
};
|
||||
publishBindings();
|
||||
if (changed) deps.onMpvInputBindingsChanged?.();
|
||||
} catch {
|
||||
// Keep the last successful snapshot if discovery is temporarily unavailable.
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user