Wip/keyboard and mouse#7
Draft
RobertGiesecke wants to merge 39 commits into
Draft
Conversation
Introduce HID-based Key and MouseButton value types (with curated NamedKey / NamedMouseButton enums and a closed OutputMouseButton), their binding records, and an empty IInputDevice marker that IJoystickDevice now extends. Keyboard and Mouse get their own sub-namespaces. No backend or routing yet.
New PressKey/ReleaseKey/PressMouseButton/ReleaseMouseButton macro actions drive an injected IInputSynthesizer directly, bypassing the vJoy output-button refcount path. The synthesizer is optional on the runtime (exposed via IRuntimeContext, flushed once per frame); a key/mouse action without one fails fast at build. Includes an in-memory FakeInputSynthesizer and tests.
WindowsInputSynthesizer dispatches keys by HID usage page: keyboard-page keys go through a scancode emitter (what games read), consumer-page keys through a virtual-key emitter; mouse buttons map onto SendInput mouse flags. It is the platform default via a new IOutputDeviceWithFactory.DefaultInputSynthesizer that VJoyDevice overrides, threaded through the console build options.
Replace the FrozenDictionary lookups in the scancode and consumer-key emitters with switch expressions — faster for these small fixed sets and no per-process build cost. Rename the INPUT union field to Union and use target-typed new.
Emitters become pure builders (TryBuild -> INPUT?) and the synthesizer sends through an injected delegate, defaulting to real SendInput. Tests capture the INPUT structs to assert the scancode/VK tables, up/down + extended flags, page dispatch and mouse flags without driving the OS, via InternalsVisibleTo.
Move Key/NamedKey/MouseButton and their bindings plus IInputSynthesizer out of InputAbstractions into a new standalone SharpSticks.InputSynthesis project with no dependencies, so keyboard/mouse can be used without any joystick coupling. InputAbstractions now references it; the Windows backend references it directly instead of InputAbstractions.
… to InputAbstractions
Brings the merge extensions alongside IMergeableObject. Shared takes the Collections.Pooled reference (now transitive into InputAbstractions, which drops its direct one) and a GlobalUsings, so the moved file and the other Shared types shed their explicit usings.
Mirror the Windows backend with a uinput-backed IInputSynthesizer that dispatches keys by HID usage page to evdev KEY_* codes and mouse buttons to BTN_*, wired as the Linux platform default and tested via an injectable event sink. Add IInputSynthesizer.EnsureInitialized, called at runtime start (with a build opt-out), so the uinput device is created up front rather than on first keypress; Windows and the fakes are no-ops.
…xpression for improved performance and zero allocation.
Move the platform synthesizer onto IOutputDeviceFactory.InputSynthesizer (vJoy => SendInput, uinput => uinput; combined factory forwards; fakes inject). The runtime builder takes an explicit synthesizer if given, else the factory used. Retire the now-redundant static IOutputDeviceWithFactory.DefaultInputSynthesizer.
Route a joystick axis to pointer velocity via AxisToMouseRoute / RouteToMouse, reusing the AxisBinding + modifier pipeline. Each frame integrates value times sensitivity times elapsed seconds with a sub-pixel remainder and combines X and Y into one MoveMouseRelative. Adds MoveMouseRelative to IInputSynthesizer (Windows SendInput, Linux uinput EV_REL); absolute movement throws until implemented.
Route right stick axes to mouse X/Y movement and bind thumbstick press/release to left mouse button actions. Rename related button for clarity.
Route an input button to a synthesized mouse button (held while the source is held) via ButtonToMouseRoute / RouteToMouse. The runtime ORs sources per button, edge-detects, and drives MouseButtonDown/Up on the synthesizer, committed on the per-frame flush — outside the vJoy output-button refcount.
…Fast` for optimized zero-allocation axis, key, and mouse button enum lookups.
…urceKey` record struct for improved clarity and type safety
be9d862 to
2bf2002
Compare
- Introduced `CoverageExclude.Undeterministic.props` and `.cs` to mark code paths that cannot be tested deterministically. - Applied `[ExcludeFromCodeCoverage]` where required across the codebase. - Added global using directive for `System.Diagnostics.CodeAnalysis`. - Removed unused or unnecessary `using` directives for improved clarity.
- Introduce comprehensive black-box tests covering formatting behavior for `NumberFormattingDebugInterpolatedStringHandler`. - Validate handling of numeric types, strings, Guids, DateTimes, enums, literals, alignment, and nested handlers. - Ensure edge cases like oversized formats and the `Clear` method are tested thoroughly.
2bf2002 to
957efed
Compare
IInputSynthesizer.Scroll(vertical, horizontal, unit) with Notch and HighResolution units. Windows uses WHEEL/HWHEEL, Linux uses REL_WHEEL with hi-res accumulation to a legacy notch; the fake records scroll events.
A source button routes to any IButtonTarget (vJoy button, mouse button, or scroll increment); axis and button RouteToScroll plus the runtime steps that emit them.
Macros.Scroll emits a wheel increment through the synthesizer.
Inverting one route off a source axis leaves other routes from the same axis unaffected, across split-to-axes and split-to-scroll.
ButtonTarget abstract record (vJoy button, mouse button, scroll) builds both its route and its runtime IButtonStateSink from the sink context; OutputButtonSink applies output buttons through the generic OutputDevice.SetButtonState. Also lands axis-zone-to-mouse-button routing via SplitIntoButtons and drops the unused IBoundRoute.OutputDeviceId.
The button apply loop now calls _Sinks[index].SetButtonState (OutputButtonSink) instead of OutputDevice.SetButtonState inline, so every output-button state index has a uniform apply. Behavior unchanged.
Mouse-button targets get an OutputButtonState slot and an IButtonStateSink like vJoy buttons; their button sources OR-merge and their zones feed the same presser counter, so StepMouseButtons is gone. The apply loop now fires sinks on change only, since key and mouse sinks emit edge events rather than idempotent state.
…d keyboard Every button source becomes a ButtonToTargetRoute and every axis zone an AxisZoneRoute, each carrying a ButtonTarget that decides the runtime sink. This removes ButtonRoute, ButtonToMouseRoute, ButtonToScrollRoute, AxisToButtonRoute and AxisToMouseButtonRoute, and folds scroll buttons into the shared presser counter. KeyTarget then needs no new route type: button-to-key and zone-to-key route through the same path. The output-device request now carries OutputButtonBinding directly rather than routes.
Abstract `ButtonTarget<T>` enables button targets like `KeyTarget`, `MouseButtonTarget`, and `OutputButtonBinding` to implement merge behavior via `IMergeableObject<T>`.
…mouse operations
…usable route abstractions Extracted reusable types (e.g., `AxisSplitIntoButtons`, `AxesWithZones`, `ButtonsRoutedToOutput`, `AxesRoutedToOutput`) to encapsulate routing logic. Simplified usages by replacing inline `SplitIntoButtons` logic with its new abstraction, improving modularity and clarity.
…plement it Introduced `IConfigurableRoute` as a new interface for configurable routing. Updated all route types and relevant tests to adopt this abstraction, ensuring consistency and improved modularity across the codebase.
Macros.MoveMouse(dx, dy) drives the synthesizer relative mouse move, like the key/mouse-button/scroll actions. Relative only; absolute is not implemented yet.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.