Skip to content

feat(frontend): live host-input capture for Mouse/Super Scope#114

Merged
doublegate merged 2 commits into
mainfrom
feat/v1.20.0-peripheral-input
Jul 15, 2026
Merged

feat(frontend): live host-input capture for Mouse/Super Scope#114
doublegate merged 2 commits into
mainfrom
feat/v1.20.0-peripheral-input

Conversation

@doublegate

Copy link
Copy Markdown
Owner

Summary

Phase A.2 of the new UI/UX-parity plan (RustySNES ↔ RustyNES).

  • New crate::peripherals module: egui::Context's pointer state now drives
    EmuCore::set_mouse/set_superscope once per frame (both the synchronous and emu-thread
    render paths) — the Settings → Input port-2 device selector already wired the emulated hardware
    correctly since v0.9.0, but nothing fed it real host input until now.
  • Super Scope's absolute aim position is mapped from window pixels through the present path's own
    letterbox transform (Gfx::letterbox_scale, exposed pub(crate) for reuse rather than
    re-derived) into SNES pixel space; trigger/cursor/turbo map to left/right/middle mouse buttons.
    Mirrors rustysnes-libretro's own already-verified poll_port_input translation.
  • Portable to wasm on purpose (no target_arch gate) — both the pointer API and the EmuCore
    calls are already platform-agnostic, so the hosted demo gets this too.
  • Found and corrected a real, separate doc inaccuracy while scoping this: docs/frontend.md
    claimed controller port 1 has "keyboard + gilrs gamepad" input, but gilrs::Gilrs is never
    actually instantiated anywhere in this crate — port 1 is keyboard-only today. This is also why
    Super Multitap sub-pad host input stays unwired: it needs that same, separate, larger
    prerequisite (a live Gilrs instance + event polling), not a small addition on top of this fix.
    Tracked in the UI/UX-parity plan's Phase B/C backlog, not silently expanded into this PR.

Test plan

  • cargo test --workspace --exclude rustysnes-android — all green
  • cargo clippy --workspace --exclude rustysnes-android --all-targets -- -D warnings — clean
  • cargo clippy -p rustysnes-frontend --features full -- -D warnings — clean
  • cargo clippy -p rustysnes-frontend --target wasm32-unknown-unknown --features wasm-winit -- -D warnings — clean
  • cargo check/clippy for emu-thread — clean
  • cargo fmt --check — clean
  • RUSTDOCFLAGS="-D warnings" cargo doc --workspace --exclude rustysnes-android --no-deps — clean
  • cargo deny check — clean
  • 5 real unit tests on the pure coordinate-mapping math (peripherals.rs's own
    #[cfg(test)] module): centered/corner/pillarboxed-inside/pillarboxed-outside/off-window cases
    — not just "compiles."

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings July 15, 2026 04:30

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements live host-input capture for the SNES Mouse and Super Scope peripherals in the rustysnes-frontend crate, utilizing egui's pointer state and reusing the existing letterbox scale calculation from Gfx to map absolute coordinates. It also corrects documentation in docs/frontend.md regarding the currently unimplemented gamepad support. The review feedback correctly identifies that relative mouse movement deltas are not scaled to the emulated SNES screen space, causing mouse sensitivity to vary with the host window size and resolution, and suggests scaling these deltas using the active letterbox scale factor.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread crates/rustysnes-frontend/src/peripherals.rs
Comment thread crates/rustysnes-frontend/src/peripherals.rs Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds live host-pointer input capture for port-2 Mouse and Super Scope peripherals in rustysnes-frontend, wiring egui’s per-frame pointer state into the existing EmuCore::set_mouse / EmuCore::set_superscope paths and updating docs/changelog to reflect the new behavior and a corrected gamepad-support claim.

Changes:

  • Introduces crate::peripherals to sync Mouse (relative deltas + buttons) and Super Scope (absolute aim + buttons) once per frame.
  • Exposes Gfx::letterbox_scale as pub(crate) so input mapping can reuse the exact present-path letterbox transform.
  • Updates docs/frontend.md and CHANGELOG.md to document the new live capture behavior and correct the prior “gilrs gamepad” claim.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
docs/frontend.md Updates frontend documentation to reflect live Mouse/Super Scope capture and corrects the prior port-1 “gilrs gamepad” statement.
crates/rustysnes-frontend/src/peripherals.rs New module implementing per-frame host pointer → SNES peripheral input sync, with unit tests for mapping math.
crates/rustysnes-frontend/src/lib.rs Exposes the new peripherals module from the frontend crate.
crates/rustysnes-frontend/src/gfx.rs Makes letterbox_scale pub(crate) and documents why it’s reused by input mapping.
crates/rustysnes-frontend/src/app.rs Calls crate::peripherals::sync in both synchronous and emu-thread present paths.
CHANGELOG.md Adds an Unreleased entry describing the new live host-input capture and the doc correction.

Comment thread crates/rustysnes-frontend/src/peripherals.rs Outdated
Comment thread crates/rustysnes-frontend/src/peripherals.rs Outdated
@doublegate

Copy link
Copy Markdown
Owner Author

Closing and reopening to retrigger CI — the pull_request webhook event never fired for this PR (confirmed: only copilot-pull-request-reviewer's check-run exists on the head commit, no ci.yml run at all).

doublegate and others added 2 commits July 15, 2026 01:37
New crate::peripherals module: egui::Context's pointer state now
drives EmuCore::set_mouse (delta + left/right buttons) and
set_superscope (absolute aim mapped through Gfx::letterbox_scale into
SNES pixel space, trigger/cursor/turbo on left/right/middle mouse
buttons) once per frame, on both the synchronous and emu-thread render
paths. Mirrors rustysnes-libretro's own already-verified
poll_port_input translation. Portable to wasm on purpose - no
target_arch gate, since both the pointer API and the EmuCore calls are
already platform-agnostic.

5 real unit tests cover the pure coordinate-mapping math directly.

Also found and corrected a real, separate doc inaccuracy while
scoping this: docs/frontend.md claimed controller port 1 has "keyboard
+ gilrs gamepad" input, but gilrs::Gilrs is never actually
instantiated anywhere in this crate - port 1 is keyboard-only today.
This is also why Super Multitap sub-pad host input stays unwired here:
it needs that same, separate, larger prerequisite (a live Gilrs
instance + event polling), not a small addition on top of this fix.

Phase A.2 of the new UI/UX-parity ladder.
Two real bugs both bots independently flagged:

- Mouse deltas were passed through raw (egui points, unscaled), so
  sensitivity varied with window scale and host display DPI (a 3x
  window scale felt 3x too fast). Convert to physical pixels via
  pixels_per_point, then rescale through the same letterbox transform
  Super Scope already used.
- Super Scope mapped into the PPU's raw fb_dims, which can be
  pixel-doubled (512-wide hi-res, up to 448-tall interlaced) while
  SuperScopeState::set_input always clamps/offscreen-checks against
  the SNES's fixed base 256x224/239 screen space. Map into a new
  logical_snes_dims() instead, and apply the same pixels_per_point
  conversion the mouse path needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@doublegate
doublegate force-pushed the feat/v1.20.0-peripheral-input branch from 65a118d to 1560e51 Compare July 15, 2026 05:39
@doublegate
doublegate merged commit a6d23cf into main Jul 15, 2026
26 checks passed
@doublegate
doublegate deleted the feat/v1.20.0-peripheral-input branch July 15, 2026 06:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants