mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-04-09 16:19:25 -07:00
Add inline controller remap modal and descriptor-based bindings
- Expand `Alt+C` from controller selection to config/remap UI with learn, clear, and reset flows - Persist full controller binding descriptors through IPC/config (buttons, axes, directions, D-pad fallback) - Update runtime/tests/docs/config examples for new binding schema; keep `Alt+Shift+C` debug modal
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
- Added Chrome Gamepad API controller support for keyboard-only overlay mode.
|
||||
- Added configurable controller bindings for lookup, mining, popup navigation, Yomitan audio, mpv pause, and d-pad fallback navigation.
|
||||
- Added smooth, slower popup scrolling for controller navigation.
|
||||
- Added `Alt+C` controller selection and `Alt+Shift+C` controller debug modals, with preferred controller persistence and live raw input inspection.
|
||||
- Expanded `Alt+C` into a controller config/remap modal with preferred-controller saving, inline learn mode, and kept `Alt+Shift+C` for raw input debugging.
|
||||
- Added a transient in-overlay controller-detected indicator when a controller is first found.
|
||||
- Fixed cleanup of stale keyboard-only token highlights when keyboard-only mode is disabled or when the Yomitan popup closes.
|
||||
- Added an enforced `verify:config-example` gate so checked-in example config artifacts cannot drift silently.
|
||||
|
||||
@@ -514,7 +514,8 @@ Important behavior:
|
||||
- Controller input is only active while keyboard-only mode is enabled.
|
||||
- Keyboard-only mode continues to work normally without a controller.
|
||||
- By default SubMiner uses the first connected controller.
|
||||
- `Alt+C` opens the controller selection modal and saves the selected controller for future launches.
|
||||
- `Alt+C` opens the controller config modal, where you can save the selected controller and remap actions inline.
|
||||
- Click `Learn`, then press the next fresh button, trigger, or stick direction you want to bind for that overlay action.
|
||||
- `Alt+Shift+C` opens a live debug modal showing raw axes/button values plus a ready-to-copy `buttonIndices` config block.
|
||||
- Turning keyboard-only mode off clears the keyboard-only token highlight state.
|
||||
- Closing the Yomitan popup clears the temporary native text-selection fill, but keeps controller token selection active.
|
||||
@@ -547,19 +548,19 @@ Important behavior:
|
||||
"rightTrigger": 7
|
||||
},
|
||||
"bindings": {
|
||||
"toggleLookup": "buttonSouth",
|
||||
"closeLookup": "buttonEast",
|
||||
"toggleKeyboardOnlyMode": "buttonNorth",
|
||||
"mineCard": "buttonWest",
|
||||
"quitMpv": "select",
|
||||
"previousAudio": "none",
|
||||
"nextAudio": "rightShoulder",
|
||||
"playCurrentAudio": "leftShoulder",
|
||||
"toggleMpvPause": "leftStickPress",
|
||||
"leftStickHorizontal": "leftStickX",
|
||||
"leftStickVertical": "leftStickY",
|
||||
"rightStickHorizontal": "rightStickX",
|
||||
"rightStickVertical": "rightStickY"
|
||||
"toggleLookup": { "kind": "button", "buttonIndex": 0 },
|
||||
"closeLookup": { "kind": "button", "buttonIndex": 1 },
|
||||
"toggleKeyboardOnlyMode": { "kind": "button", "buttonIndex": 3 },
|
||||
"mineCard": { "kind": "button", "buttonIndex": 2 },
|
||||
"quitMpv": { "kind": "button", "buttonIndex": 6 },
|
||||
"previousAudio": { "kind": "none" },
|
||||
"nextAudio": { "kind": "button", "buttonIndex": 5 },
|
||||
"playCurrentAudio": { "kind": "button", "buttonIndex": 4 },
|
||||
"toggleMpvPause": { "kind": "button", "buttonIndex": 9 },
|
||||
"leftStickHorizontal": { "kind": "axis", "axisIndex": 0, "dpadFallback": "horizontal" },
|
||||
"leftStickVertical": { "kind": "axis", "axisIndex": 1, "dpadFallback": "vertical" },
|
||||
"rightStickHorizontal": { "kind": "axis", "axisIndex": 3, "dpadFallback": "none" },
|
||||
"rightStickVertical": { "kind": "axis", "axisIndex": 4, "dpadFallback": "none" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -581,6 +582,8 @@ Default logical mapping:
|
||||
- `L3`: toggle mpv pause
|
||||
- `L2` / `R2`: unbound by default
|
||||
|
||||
Discrete bindings may use raw button indices or raw axis directions, and analog bindings use raw axis indices with optional D-pad fallback. The `Alt+C` learn flow writes those descriptors for you, so manual edits are only needed when you want to script or copy exact mappings.
|
||||
|
||||
If you choose to bind `L2` or `R2` manually, set `triggerInputMode` to `analog` and tune `triggerDeadzone` when your controller reports triggers as analog values instead of digital pressed/not-pressed buttons. `auto` accepts either style and remains the default.
|
||||
|
||||
If your controller reports non-standard raw button numbers, override `controller.buttonIndices` using values from the `Alt+Shift+C` debug modal.
|
||||
|
||||
@@ -53,13 +53,13 @@
|
||||
// ==========================================
|
||||
// Controller Support
|
||||
// Gamepad support for the visible overlay while keyboard-only mode is active.
|
||||
// Use the selection modal to save a preferred controller by id for future launches.
|
||||
// Use Alt+C to pick a preferred controller and remap actions inline with learn mode.
|
||||
// Trigger input mode can be auto, digital-only, or analog-thresholded depending on the controller.
|
||||
// Override controller.buttonIndices when your pad reports non-standard raw button numbers.
|
||||
// ==========================================
|
||||
"controller": {
|
||||
"enabled": true, // Enable overlay controller support through the Chrome Gamepad API. Values: true | false
|
||||
"preferredGamepadId": "", // Preferred controller id saved from the controller selection modal.
|
||||
"preferredGamepadId": "", // Preferred controller id saved from the controller config modal.
|
||||
"preferredGamepadLabel": "", // Preferred controller display label saved for diagnostics.
|
||||
"smoothScroll": true, // Use smooth scrolling for controller-driven popup scroll input. Values: true | false
|
||||
"scrollPixelsPerSecond": 900, // Base popup scroll speed for controller stick input.
|
||||
@@ -83,19 +83,61 @@
|
||||
"rightTrigger": 7 // Raw button index used for controller R2 input.
|
||||
}, // Button indices setting.
|
||||
"bindings": {
|
||||
"toggleLookup": "buttonSouth", // Controller binding for toggling lookup. Values: none | select | buttonSouth | buttonEast | buttonNorth | buttonWest | leftShoulder | rightShoulder | leftStickPress | rightStickPress | leftTrigger | rightTrigger
|
||||
"closeLookup": "buttonEast", // Controller binding for closing lookup. Values: none | select | buttonSouth | buttonEast | buttonNorth | buttonWest | leftShoulder | rightShoulder | leftStickPress | rightStickPress | leftTrigger | rightTrigger
|
||||
"toggleKeyboardOnlyMode": "buttonNorth", // Controller binding for toggling keyboard-only mode. Values: none | select | buttonSouth | buttonEast | buttonNorth | buttonWest | leftShoulder | rightShoulder | leftStickPress | rightStickPress | leftTrigger | rightTrigger
|
||||
"mineCard": "buttonWest", // Controller binding for mining the active card. Values: none | select | buttonSouth | buttonEast | buttonNorth | buttonWest | leftShoulder | rightShoulder | leftStickPress | rightStickPress | leftTrigger | rightTrigger
|
||||
"quitMpv": "select", // Controller binding for quitting mpv. Values: none | select | buttonSouth | buttonEast | buttonNorth | buttonWest | leftShoulder | rightShoulder | leftStickPress | rightStickPress | leftTrigger | rightTrigger
|
||||
"previousAudio": "none", // Controller binding for previous Yomitan audio. Values: none | select | buttonSouth | buttonEast | buttonNorth | buttonWest | leftShoulder | rightShoulder | leftStickPress | rightStickPress | leftTrigger | rightTrigger
|
||||
"nextAudio": "rightShoulder", // Controller binding for next Yomitan audio. Values: none | select | buttonSouth | buttonEast | buttonNorth | buttonWest | leftShoulder | rightShoulder | leftStickPress | rightStickPress | leftTrigger | rightTrigger
|
||||
"playCurrentAudio": "leftShoulder", // Controller binding for playing the current Yomitan audio. Values: none | select | buttonSouth | buttonEast | buttonNorth | buttonWest | leftShoulder | rightShoulder | leftStickPress | rightStickPress | leftTrigger | rightTrigger
|
||||
"toggleMpvPause": "leftStickPress", // Controller binding for toggling mpv play/pause. Values: none | select | buttonSouth | buttonEast | buttonNorth | buttonWest | leftShoulder | rightShoulder | leftStickPress | rightStickPress | leftTrigger | rightTrigger
|
||||
"leftStickHorizontal": "leftStickX", // Axis binding used for left/right token selection. Values: leftStickX | leftStickY | rightStickX | rightStickY
|
||||
"leftStickVertical": "leftStickY", // Axis binding used for primary popup scrolling. Values: leftStickX | leftStickY | rightStickX | rightStickY
|
||||
"rightStickHorizontal": "rightStickX", // Axis binding reserved for alternate right-stick mappings. Values: leftStickX | leftStickY | rightStickX | rightStickY
|
||||
"rightStickVertical": "rightStickY" // Axis binding used for popup page jumps. Values: leftStickX | leftStickY | rightStickX | rightStickY
|
||||
"toggleLookup": {
|
||||
"kind": "button", // Discrete binding input source kind. Values: none | button | axis
|
||||
"buttonIndex": 0 // Raw button index captured for this discrete controller action.
|
||||
}, // Controller binding descriptor for toggling lookup. Use Alt+C learn mode or set a raw button/axis descriptor manually.
|
||||
"closeLookup": {
|
||||
"kind": "button", // Discrete binding input source kind. Values: none | button | axis
|
||||
"buttonIndex": 1 // Raw button index captured for this discrete controller action.
|
||||
}, // Controller binding descriptor for closing lookup. Use Alt+C learn mode or set a raw button/axis descriptor manually.
|
||||
"toggleKeyboardOnlyMode": {
|
||||
"kind": "button", // Discrete binding input source kind. Values: none | button | axis
|
||||
"buttonIndex": 3 // Raw button index captured for this discrete controller action.
|
||||
}, // Controller binding descriptor for toggling keyboard-only mode. Use Alt+C learn mode or set a raw button/axis descriptor manually.
|
||||
"mineCard": {
|
||||
"kind": "button", // Discrete binding input source kind. Values: none | button | axis
|
||||
"buttonIndex": 2 // Raw button index captured for this discrete controller action.
|
||||
}, // Controller binding descriptor for mining the active card. Use Alt+C learn mode or set a raw button/axis descriptor manually.
|
||||
"quitMpv": {
|
||||
"kind": "button", // Discrete binding input source kind. Values: none | button | axis
|
||||
"buttonIndex": 6 // Raw button index captured for this discrete controller action.
|
||||
}, // Controller binding descriptor for quitting mpv. Use Alt+C learn mode or set a raw button/axis descriptor manually.
|
||||
"previousAudio": {
|
||||
"kind": "none" // Discrete binding input source kind. Values: none | button | axis
|
||||
}, // Controller binding descriptor for previous Yomitan audio. Use Alt+C learn mode or set a raw button/axis descriptor manually.
|
||||
"nextAudio": {
|
||||
"kind": "button", // Discrete binding input source kind. Values: none | button | axis
|
||||
"buttonIndex": 5 // Raw button index captured for this discrete controller action.
|
||||
}, // Controller binding descriptor for next Yomitan audio. Use Alt+C learn mode or set a raw button/axis descriptor manually.
|
||||
"playCurrentAudio": {
|
||||
"kind": "button", // Discrete binding input source kind. Values: none | button | axis
|
||||
"buttonIndex": 4 // Raw button index captured for this discrete controller action.
|
||||
}, // Controller binding descriptor for playing the current Yomitan audio. Use Alt+C learn mode or set a raw button/axis descriptor manually.
|
||||
"toggleMpvPause": {
|
||||
"kind": "button", // Discrete binding input source kind. Values: none | button | axis
|
||||
"buttonIndex": 9 // Raw button index captured for this discrete controller action.
|
||||
}, // Controller binding descriptor for toggling mpv play/pause. Use Alt+C learn mode or set a raw button/axis descriptor manually.
|
||||
"leftStickHorizontal": {
|
||||
"kind": "axis", // Analog binding input source kind. Values: none | axis
|
||||
"axisIndex": 0, // Raw axis index captured for this analog controller action.
|
||||
"dpadFallback": "horizontal" // Optional D-pad fallback used when this analog controller action should also read D-pad input. Values: none | horizontal | vertical
|
||||
}, // Axis binding descriptor used for left/right token selection. Use Alt+C learn mode or set a raw axis descriptor manually.
|
||||
"leftStickVertical": {
|
||||
"kind": "axis", // Analog binding input source kind. Values: none | axis
|
||||
"axisIndex": 1, // Raw axis index captured for this analog controller action.
|
||||
"dpadFallback": "vertical" // Optional D-pad fallback used when this analog controller action should also read D-pad input. Values: none | horizontal | vertical
|
||||
}, // Axis binding descriptor used for primary popup scrolling. Use Alt+C learn mode or set a raw axis descriptor manually.
|
||||
"rightStickHorizontal": {
|
||||
"kind": "axis", // Analog binding input source kind. Values: none | axis
|
||||
"axisIndex": 3, // Raw axis index captured for this analog controller action.
|
||||
"dpadFallback": "none" // Optional D-pad fallback used when this analog controller action should also read D-pad input. Values: none | horizontal | vertical
|
||||
}, // Axis binding descriptor reserved for alternate right-stick mappings. Use Alt+C learn mode or set a raw axis descriptor manually.
|
||||
"rightStickVertical": {
|
||||
"kind": "axis", // Analog binding input source kind. Values: none | axis
|
||||
"axisIndex": 4, // Raw axis index captured for this analog controller action.
|
||||
"dpadFallback": "none" // Optional D-pad fallback used when this analog controller action should also read D-pad input. Values: none | horizontal | vertical
|
||||
} // Axis binding descriptor used for popup page jumps. Use Alt+C learn mode or set a raw axis descriptor manually.
|
||||
} // Bindings setting.
|
||||
}, // Gamepad support for the visible overlay while keyboard-only mode is active.
|
||||
|
||||
|
||||
@@ -75,8 +75,8 @@ These overlay-local shortcuts are fixed and open controller utilities for the Ch
|
||||
|
||||
| Shortcut | Action | Configurable |
|
||||
| ------------- | ------------------------------ | ------------ |
|
||||
| `Alt+C` | Open controller selection modal | Fixed |
|
||||
| `Alt+Shift+C` | Open controller debug modal | Fixed |
|
||||
| `Alt+C` | Open controller config + remap modal | Fixed |
|
||||
| `Alt+Shift+C` | Open controller debug modal | Fixed |
|
||||
|
||||
Controller input only drives the overlay while keyboard-only mode is enabled. The controller mapping and tuning live under the top-level `controller` config block; keyboard-only mode still works normally without a controller.
|
||||
|
||||
|
||||
@@ -254,10 +254,12 @@ SubMiner supports gamepad/controller input for couch-friendly usage via the Chro
|
||||
|
||||
1. Connect a controller before or after launching SubMiner.
|
||||
2. Enable keyboard-only mode — press `Y` on the controller (default binding) or use the overlay keybinding.
|
||||
3. Use the left stick to navigate subtitle tokens and the right stick to scroll the Yomitan popup.
|
||||
4. Press `A` to look up the selected word, `X` to mine a card, `B` to close the popup.
|
||||
3. Press `Alt+C` in the overlay to pick the controller you want to save and remap any action inline.
|
||||
4. Click `Learn` on the overlay action you want, then press the matching button, trigger, or stick direction on the controller.
|
||||
5. Use the left stick to navigate subtitle tokens and scroll the popup; use the right stick vertically for popup page jumps.
|
||||
6. Press `A` to look up the selected word, `X` to mine a card, `B` to close the popup.
|
||||
|
||||
By default SubMiner uses the first connected controller. Press `Alt+C` in the overlay to open the controller selection modal and persist your preferred controller across sessions. Press `Alt+Shift+C` to open a live debug modal showing raw axes and button values.
|
||||
By default SubMiner uses the first connected controller. `Alt+C` opens the controller config modal, where you can save the preferred controller and remap bindings inline. `Alt+Shift+C` still opens the live debug modal with raw axes/button values for non-standard pads.
|
||||
|
||||
### Default Button Mapping
|
||||
|
||||
@@ -278,10 +280,11 @@ By default SubMiner uses the first connected controller. Press `Alt+C` in the ov
|
||||
| Input | Action |
|
||||
| ----- | ------ |
|
||||
| Left stick horizontal | Move token selection left/right |
|
||||
| Left stick vertical | Smooth scroll Yomitan popup |
|
||||
| Right stick horizontal | Jump inside popup (horizontal) |
|
||||
| Right stick vertical | Smooth scroll popup (vertical) |
|
||||
| D-pad | Fallback for stick navigation |
|
||||
| Left stick vertical | Scroll Yomitan popup |
|
||||
| Right stick vertical | Jump through Yomitan popup |
|
||||
| D-pad | Fallback for stick navigation when configured |
|
||||
|
||||
Learn mode ignores already-held inputs and waits for the next fresh button press or axis direction, which avoids accidental captures when you open the modal mid-input.
|
||||
|
||||
All button and axis mappings are configurable under the `controller` config block. See [Configuration — Controller Support](/configuration#controller-support) for the full options.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user