|
| 1 | +# Input Mapping V2 Haptics + Shortcut Suppression Report |
| 2 | + |
| 3 | +PR: PR_26140_104-add-input-mapping-v2-haptics-and-shortcut-suppression |
| 4 | + |
| 5 | +## Source of Truth |
| 6 | + |
| 7 | +- Read `docs/dev/PROJECT_INSTRUCTIONS.md` before implementation. |
| 8 | +- Active `docs/pr/BUILD_PR.md` is an unrelated Level 18 rebase note, so this report follows the explicit PR104 user request as the current BUILD scope. |
| 9 | +- One PR purpose: add engine-backed game controller haptics support and scoped Input Mapping V2 shortcut suppression. |
| 10 | + |
| 11 | +## Changes |
| 12 | + |
| 13 | +- Added `src/engine/input/GamepadHapticsService.js` as a reusable engine input service for game controller haptics. |
| 14 | +- Uses browser Gamepad API haptics only when available: |
| 15 | + - `gamepad.vibrationActuator.playEffect("dual-rumble", ...)`. |
| 16 | + - `gamepad.hapticActuators[].pulse(...)`. |
| 17 | + - `gamepad.hapticActuators[].playEffect(...)` when present. |
| 18 | +- Does not fake rumble when unsupported; unsupported, unavailable, or blocked haptics return actionable WARN messages. |
| 19 | +- Wired Input Mapping V2 through `EngineInputSourceService` so the tool consumes the engine haptics service rather than owning local haptics runtime logic. |
| 20 | +- Moved haptics UI into the Game Controller device section: |
| 21 | + - support state per detected controller, |
| 22 | + - selected-action `Enable Rumble` checkbox, |
| 23 | + - strength and duration controls, |
| 24 | + - `Test Rumble` button only for supported controllers. |
| 25 | +- Added scoped `Suppress Shortcuts` checkbox in the Capture accordion header. |
| 26 | +- Suppression is scoped to the Input Mapping V2 workspace root only: |
| 27 | + - Ctrl/Meta + Wheel is prevented inside the tool area when enabled, |
| 28 | + - Alt/Ctrl/Meta key browser/page shortcuts are suppressed inside the tool area when enabled where the browser permits, |
| 29 | + - shortcuts are not suppressed when the checkbox is disabled, |
| 30 | + - behavior outside the tool area is not suppressed. |
| 31 | +- Preserved `Disable Context` behavior. |
| 32 | +- Preserved capture, combo, gesture, tile selection, and selected-input highlighting behavior. |
| 33 | +- Adjusted combo polling so held game controller input repeats do not overwrite the first captured combo prompt with a duplicate-input warning while waiting for the second input. |
| 34 | + |
| 35 | +## ToolState / Schema |
| 36 | + |
| 37 | +- No schemas changed. |
| 38 | +- No sample JSON changed. |
| 39 | +- Haptics settings are kept UI-local per selected action because the existing Input Mapping V2 tool-local mapping/toolState contract does not expose a compatible action-options field for persisting rumble settings without schema drift. |
| 40 | + |
| 41 | +## Playwright Impact |
| 42 | + |
| 43 | +Playwright impacted: Yes. |
| 44 | + |
| 45 | +Focused Workspace V2 coverage now validates: |
| 46 | + |
| 47 | +- haptics support state is displayed for mocked gamepads, |
| 48 | +- `Test Rumble` calls a mocked supported actuator, |
| 49 | +- unsupported haptics logs an actionable WARN, |
| 50 | +- `Enable Rumble` can be toggled for the selected mapping/action, |
| 51 | +- shortcut suppression checkbox appears, |
| 52 | +- Ctrl + Wheel is prevented inside Input Mapping V2 when enabled, |
| 53 | +- Alt key suppression is applied inside Input Mapping V2 when enabled, |
| 54 | +- shortcuts are not suppressed when the checkbox is disabled, |
| 55 | +- `Disable Context` still works. |
| 56 | + |
| 57 | +## Validation |
| 58 | + |
| 59 | +Passed: |
| 60 | + |
| 61 | +- `node --check src/engine/input/GamepadHapticsService.js` |
| 62 | +- `node --check tools/input-mapping-v2/js/services/EngineInputSourceService.js` |
| 63 | +- `node --check tools/input-mapping-v2/js/ToolStarterApp.js` |
| 64 | +- `node --check tools/input-mapping-v2/js/bootstrap.js` |
| 65 | +- `node --check tools/input-mapping-v2/js/controls/CaptureControl.js` |
| 66 | +- `node --check tools/input-mapping-v2/js/controls/DeviceListControl.js` |
| 67 | +- `node --check tests/input/GamepadHapticsService.test.mjs` |
| 68 | +- `node --check tests/run-tests.mjs` |
| 69 | +- `node --check tests/playwright/tools/WorkspaceManagerV2.spec.mjs` |
| 70 | +- `node -e "const module = await import('./src/engine/input/GamepadHapticsService.js'); if (typeof module.default !== 'function') throw new Error('GamepadHapticsService default export missing');"` |
| 71 | +- `node -e "const test = await import('./tests/input/GamepadHapticsService.test.mjs'); await test.run();"` |
| 72 | +- `npx playwright test tests/playwright/tools/WorkspaceManagerV2.spec.mjs -g "Input Mapping V2" --project=playwright --workers=1 --reporter=list` - 2 passed. |
| 73 | +- `npm run test:workspace-v2` - 61 passed. |
| 74 | +- `git diff --check` - passed; Git reported LF-to-CRLF working-copy warnings only. |
| 75 | +- `git status --short -- samples games` - no sample/game JSON changes. |
| 76 | +- `rg "imageDataUrl" tools/input-mapping-v2 src/engine/input tests/input tests/playwright/tools/WorkspaceManagerV2.spec.mjs` - no matches. |
| 77 | + |
| 78 | +Notes: |
| 79 | + |
| 80 | +- An initial full `npm run test:workspace-v2` run reached 60/61 and exposed a duplicate held-gamepad combo polling issue in the updated Input Mapping V2 test path. The app was fixed to ignore silent duplicate gamepad repeats during combo polling, the focused Input Mapping V2 slice passed, and the full suite was rerun successfully with 61/61 passing. |
| 81 | +- Full samples smoke test was skipped by explicit PR instruction. |
| 82 | +- Playwright V8 coverage was produced at `docs/dev/reports/playwright_v8_coverage_report.txt`; `docs/dev/reports/coverage_changed_js_guardrail.txt` reports no changed runtime JS coverage warnings. |
| 83 | + |
| 84 | +## Manual Validation |
| 85 | + |
| 86 | +1. Open Input Mapping V2 in Workspace V2. |
| 87 | +2. Connect or mock a game controller with haptics support. |
| 88 | +3. Confirm the Game Controller device section shows haptics support state and a `Test Rumble` button for supported controllers only. |
| 89 | +4. Select an action tile, enable `Enable Rumble`, adjust strength/duration, and click `Test Rumble`. |
| 90 | +5. Confirm unsupported controllers log a WARN instead of faking rumble. |
| 91 | +6. Enable `Suppress Shortcuts` and verify Ctrl + Wheel does not zoom the page while the pointer is inside Input Mapping V2. |
| 92 | +7. Verify right-click context suppression still follows only the separate `Disable Context` checkbox. |
| 93 | +8. Disable `Suppress Shortcuts` and confirm browser/page shortcuts behave normally again. |
| 94 | + |
| 95 | +## Files Changed |
| 96 | + |
| 97 | +- `src/engine/input/GamepadHapticsService.js` |
| 98 | +- `tests/input/GamepadHapticsService.test.mjs` |
| 99 | +- `tests/run-tests.mjs` |
| 100 | +- `tests/playwright/tools/WorkspaceManagerV2.spec.mjs` |
| 101 | +- `tools/input-mapping-v2/index.html` |
| 102 | +- `tools/input-mapping-v2/js/ToolStarterApp.js` |
| 103 | +- `tools/input-mapping-v2/js/bootstrap.js` |
| 104 | +- `tools/input-mapping-v2/js/controls/CaptureControl.js` |
| 105 | +- `tools/input-mapping-v2/js/controls/DeviceListControl.js` |
| 106 | +- `tools/input-mapping-v2/js/services/EngineInputSourceService.js` |
| 107 | +- `tools/input-mapping-v2/styles/inputMappingV2.css` |
0 commit comments