Commit Graph

21 Commits

Author SHA1 Message Date
bicarus 47d886306e rawinput: handle midi scanning asynchronously, fix midi hotplug (#793)
## Link to GitHub Issue or related Pull Request, if one exists
Fixes #603

## Description of change
Scanning for midi devices can take a while on Windows 11 with MIDI 2.0
service. Sometimes it'll take a couple seconds. Sometimes, on a PC with
zero MIDI devices, it takes 10-11 seconds.

This was causing two issues:

1. slow startup time
2. crash on invalid memory access due to a race condition

Address both.

Also fix a bug: when a device change event fires, we do a MIDI scan, and
invalidated all existing MIDI devices in favor of creating new handles.
Stop doing this, and instead check for duplicates by matching the ID and
keep existing device handles alone. Properly clean up devices on unplug.

Also: fix MIDI buttons being stuck on when unplugged while holding a
key.

## Testing
Tested with Nostroller in MIDI mode. rtpMIDI works too.
2026-07-11 21:57:55 -07:00
drmext 0511dfb6ca rawinput: fix spicecfg close delay (#715)
## Link to GitHub Issue or related Pull Request, if one exists
#0

## Description of change
Closing spicecfg was blocked for up to ~495 ms. Runtime behavior is
unchanged: same flush interval and same output path during normal
operation. Only shutdown teardown is faster.

## Testing
Opened and closed spicecfg.exe repeatedly; the window closes immediately
with no hang
2026-05-29 09:33:08 -07:00
bicarus 71ba9b6b47 os: implement win10 high-resolution timer as replacement for Sleep() / sleep_for() (#682)
## Link to GitHub Issue or related Pull Request, if one exists
Fixes #681 

## Description of change
`Sleep` and `sleep_for()` can be very inaccurate and varies depending on
what the OS gives us...

### `timeBeginPeriod(1)`
On boot, we are now calling `timeBeginPeriod(1)`, which affects the
whole process but makes `Sleep` more accurate. There is some risk here
if any game was relying on doing things like `Sleep(1)` and expecting it
to run for 15.6ms. Most games already call `timeBeginPeriod(1)` in the
game engine, though not the whole time, so I'm hoping that this is not
too impactful.

### Opt out of Win11 power throttling
Ensure that timer resolution change above is respected even when the
window is occluded / minimized by opting out of throttling via
`PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION`.

### Use Win10 high resolution timer instead of Sleep

On Win10 1803 and above, there is a new OS-level API for high resolution
timers; if this is available, use it
(`CREATE_WAITABLE_TIMER_HIGH_RESOLUTION`). Worth noting that WINE
doesn't support this currently.

If not, fall back to `Sleep`, which is significantly better than
`sleep_for()` in my experiments.

Callers of Sleep / sleep_for were replaced with this new timer. Most of
them anyway; calls to Sleep() with more than 100ms+ was left alone.

### Add an option as a chicken bit

To opt out I'm adding a new option called `Use Legacy Timers` which will
revert to behavior before this PR. The code paths that switched from
`sleep_for` to `Sleep` will remain in place though, not affected by the
option.

## Expected changes
In some I/O emulation modules, poll threads may run more frequently,
resulting in lower latency.

It also means that spice overall may use more CPU resources and power.
If you don't like this, you can always enable the option to opt out;
e.g., if you're on old arcade cab PC.

## Testing

DDR p4io - ok
drs touch hook - ok
IIDX camera hook - ok
CCJ trackball - ok
2026-05-08 02:25:20 -07:00
bicarus 678e11eade rawinput: fix up devices that report invalid max values (#658)
## Link to GitHub Issue or related Pull Request, if one exists
regression caused by #653

## Description of change
Some controllers - like the Xbox One controller I have - reports
0xffffffff as the max range value for analog, despite reporting 16-bit
width. This causes us to consider 0xffffffff as -1 so the range became
[0, -1] which is invalid.

Our automatic calibration does eventually fix this (-1 will fix itself
to become the highest actual value reported, which would be 0xffff).

This seems to be a common issue with XInput-based controllers in
general: see `Correct_Axis_Max` in
https://github.com/argonlefou/DemulShooter/blob/master/DsCore/RawInput/RawInputController.cs

#653 removed the fix that was masking this issue. Put in a new fix that
fixes these up.

## Testing
Tested with Xbox One controller.
2026-04-27 01:41:44 -07:00
bicarus 1147ed9858 rawinput: fix signed range values (#653)
## Link to GitHub Issue or related Pull Request, if one exists
n/a

## Description of change
Official GuitarFreaks controller has the motion sensor values with
`valuemin=-127` to `valuemax=127` and we don't deal with negative values
correctly.

## Testing
tbd
2026-04-21 22:56:27 -07:00
bicarus 727b99effd rawinput: fix ID for rawinput devices (#627)
## Link to GitHub Issue or related Pull Request, if one exists
#616 

## Description of change
The IDs don't really get used anywhere if it's not a real HID or MIDI
device, but putting them for completeness since they show up in Controls
overlay menu.

## Testing
2026-04-11 12:04:12 -07:00
bicarus a159691097 xinput: bind UI, vibration, hotplug (#620)
## Link to GitHub Issue or related Pull Request, if one exists
#616 

## Description of change
`Naive` button is now called `Naive/XInput` and detects XInput
controllers

Add vibration output as "Lights"

Add proper hotplug support and multiple controllers

Fix misc bugs on x86

## Testing
I tested with two xbox controllers.
2026-04-10 01:04:20 -07:00
bicarus 7b4227d2a9 rawinput: add basic support for xinput (#617)
## Link to GitHub Issue or related Pull Request, if one exists
#616 

## Description of change
Adds preliminary support for XInput controllers. Enough to manually bind
buttons and map analogs.
2026-04-09 02:49:20 -07:00
bicarus-dev b1ee828457 add some logging to device reload 2026-04-01 02:51:03 -07:00
bicarus e4b08064b7 rawinput: fix incorrect usage of HidP_GetUsages when descriptor is not range (#565)
## Link to GitHub Issue or related Pull Request, if one exists
Fixes #563 

## Description of change
When buttons are presented as NotRange and instead an array of single
buttons, we are calling `HidP_GetUsages` expecting at most one result
back, but in reality we need to expect all possible buttons on that
usage page since `HidP_GetUsages` returns all buttons in the usage page
+ link collection which would be the entire array of buttons - see
documentation for `HidP_GetUsages` on MSDN.

## Testing
Tested with my own controller modifying USB descriptors... more
controller testing is needed.
2026-03-05 20:41:47 -08:00
bicarus dc6850e479 overlay: helper modal dialog for picking option values (#561)
## Link to GitHub Issue or related Pull Request, if one exists

## Description of change
Introduce a new modal dialog for picking out some of the options to
improve UX.

Implemented a few for now:

1. UI for picking ASIO drivers from a list (for -iidxasio, -sdvxasio,
-asioconvert, etc)
2. Button to generate card numbers for -card0 and card1
3. Processor Affinity selector (very similar to what's in Windows Task
Manager, list of checkboxes)
4. file selector (file open dialog for various file path overrides like
log file)
5. folder selector (folder override)

I wrote a selector for COM ports as well but how we use the value was
inconsistent (\\\\.\\COMx vs. COMx) and didn't see a huge point in it so
I didn't check it in.

## Testing
2026-03-02 12:08:20 -08:00
bicarus a0a04ab62f gitadora: various fixes for wailing (#513)
## Link to GitHub Issue, if one exists
Fixes #512

## Description of change
Fix digital wailing not being recognized consistently.

Also address the fact that wailing was completely broken when lefty mode
was on. This requires a new option that the user needs to check off in
the configurator since we can't magically guess if the user is holding
the guitar in lefty mode.

- [x] fix downward wail
- [x] digital lefty mode
- [x] implement all of this for arena model i/o
- [x] test dx cab 2p
- [x] lefty toggle in overlay
- [x] fix analog not working for 2p guitar
- [ ] analog lefty mode?

## Testing
Checked GW and GW Delta
2026-01-12 21:52:48 -08:00
cchike f113eb4f52 MDX: Merged Thread and Backfill Implementations (P4IO Timing Fix) (#460)
## Link to GitHub Issue, if one exists
#452 

## Description of change
(Another extension of #450)
Merged the old threading implementation into the current backfill
implementation because it was showing signs of having slightly better
timing performance. The following description is taken from the
strikethrough text from the referenced PR above:
>When the module is booted, it counts how many times
ac_io_mdxf_update_control_status_buffer was called in the first three
seconds, then calculates the approximate refresh rate of the current
game instance. If the refresh rate is under THRESHOLD_REFRESH_RATE
(120Hz), a low-priority thread dedicated to inserting polls into the
ring buffers is started and run at THREAD_REFRESH_RATE_HZ (125Hz).
Combined with the polls inserted by the main arkmdxp4 thread and
rawinput real-time events, the 125Hz update cadence is enough to bring
the span of poll history represented by the ring buffers closer to
parity with what arkmdxp4 expects.

The default mode is `THREAD_MODE` but can be switched to `BACKFILL_MODE`
(which could possibly be made as a `spicecfg` option).

There was also a fixed bug in the `ac_io_mdxf_get_control_status_buffer`
function, which should not have been writing to the `head` pointer. This
was allowing for an edge case situation where the `head` pointer was
advanced in another thread then rewound back to the previous `head` in
this thread. The real implementation only reads the pointer and returns
it.

## Testing
- Logged the ring buffer states after many iterations and verified
regular structure
- Same playtesting as the prior PRs
2025-12-18 09:27:33 -08:00
llm96 83aa907b13 rawinput: append HID product string to description (#458)
## Link to GitHub Issue, if one exists
N/A

## Description of change
Append product strings to descriptions. Useful for differentiating
devices in the analog binding dialog.

Before | After
------ | ------

![0](https://github.com/user-attachments/assets/803c5a69-2ed9-40f8-a147-f1b4f3a7e220)
|
![1](https://github.com/user-attachments/assets/7407a3cc-eebb-4529-be43-2eb177645bb7)

## Testing
`spice64 -iidx -cfg` ⟶ Analogs ⟶ Bind
2025-12-17 15:03:16 -08:00
bicarus-dev 71b144918c rawinput: stop iterating devices if one was found (#457)
## Link to GitHub Issue, if one exists
n/a

## Description of change
This would save a handful of instructions at best but it was bothering
me

## Testing
Tested with two controllers + naive with ddr
2025-12-17 05:40:27 -08:00
cchike e618a05b08 MDX: Updated Ring Buffer Backfill Implementation (P4IO Timing Fix) (#456)
## Link to GitHub Issue, if one exists
#452  

## Description of change
- Extension of #450 
- Moved the call to `arkGetTickTime64()` outside the update function to
bring the timestamps closer to real-time
- Changed the update function to only call `getState()` if called from
`rawinput`, otherwise just fill the ring buffer entries with the last
known state
- Changed the update function to only write one ring buffer entry if
called from `rawinput`
- Moved the call to `mdxf_poll()` within `rawinput.cpp` outside the loop
that iterates over all devices

## Testing
- Logging was done to verify the span of poll history covered by each
request for 7 ring buffer entries was ~28ms, as the game expects
- Observed some improvement in timing precision since the prior
implementation
2025-12-17 02:45:22 -08:00
cchike 6f58d9ab68 MDX: Decoupled Input Polling Rate From Game Refresh Rate (P4IO Timing Fix) (#446)
## Context
In the real implementation of `ac_io_mdxf_update_control_status_buffer`,
it doesn't actually add entries to the pad state ring buffers (it only
marks the head entry as the "last consumed" entry), and `arkmdxp4.dll`
expects the ring buffers to be updated at regular intervals inside
`libacio2.dll` at ~250Hz per player. Instead, in the emulated version,
the updates happen in this function and that regular interval is
established internally using the game's refresh rate (60Hz, 120Hz,
144Hz, etc.). This effectively locks the polling rate of pad input to
that refresh rate, which is quite low for pad input.

## Description of change
The polling rate lock was circumvented by calling
`ac_io_mdxf_update_control_status_buffer` as soon as the game receives
controller input in `rawinput.cpp`. A simple wrapper function
`mdxf_poll` was exposed so press and release events could be added to
the ring buffers in real time as they happen. After each controller
event in `rawinput.cpp`, `mdxf_poll` calls
`ac_io_mdxf_update_control_status_buffer` for each player, checking the
pad's current state and adding it to the ring buffer if it's changed
since the last call. This results in the 0 -> 1 (press) and 1 -> 0
(release) state transitions used for gameplay to be based only on the
real-time events inserted from `rawinput.cpp`, while leaving the rest of
the entries generated from the main `arkmdxp4.dll` thread as "padding"
the game expects (I actually tried reducing the ring buffers to *only*
write entries on state transitions, but it broke gameplay, which means
the game still depends regular reporting of the pad state). Here's an
example of how a ring buffer would look if an arrow was pressed at some
time 32ms (assume 165Hz game refresh rate, ~6ms updates):

```
Old (only frame updates):
1 | 36ms
0 | 30ms
0 | 24ms
0 | 18ms
0 | 12ms
0 | 6ms
0 | 0ms
```
The game only sees the press event at time 36ms on frame update, so time
36ms is assigned to the press time of that arrow (4ms later than the
real press time).

```
New (frame updates + event updates from rawinput.cpp):
1 | 36ms
1 | 32ms <- from rawinput.cpp
0 | 30ms
0 | 24ms
0 | 18ms
0 | 12ms
0 | 6ms
```
The game sees the real press time 32ms on frame update, so the correct
press time 32ms is assigned.

## Testing
- Played on various refresh rates and verified the controller input
remains highly responsive.
- Inspected the ring buffers with a debugger and verified entries for
press and release events from `rawinput.cpp` were correctly being added
for their respective players.
2025-12-12 19:03:04 -08:00
bicarus-dev 052698afa3 rawinput: use UTF-8 for device descriptor (#422)
## Link to GitHub Issue, if one exists
n/a

## Description of change
For HID device descriptor, use the "W" version of Windows API, and make
sure UTF-8 is being used throughout since that's the only format IMGUI
supports.

Before this change, non-Latin characters would have shown up as `HID ???
?????` for a mouse, for example.

Due to the way ImGui loads fonts, only the following languages are
supported:

* Simplified Chinese
* Cyrillic
* Japanese
* Korean
* Thai
* Vietnamese

## Testing
Tested various combination of Windows UI language and non-Unicode
language.
2025-11-16 00:08:30 -08:00
bicarus-dev 26ea8a1b92 api: check for window focus when accepting input (#317)
## Link to GitHub Issue, if one exists
Fixes #139 

## Description of change
Add an option for detecting window focus when accepting input.

The new default will be to have the following:
 * naive bindings will check for window focus
* rawinput binds are not affected, will continue to be accepted
regardless of focus

Other options (always / never choices) can be picked by the user to
tweak the behavior if needed.

Clean up usage of `0xff` constant to represent invalid naive vkey.

## Testing
Still in progress, especially in regards to performance.

On a i7-9700 system, 10000 calls to `superexit::has_focus()` takes
250-350 microseconds, so this should not be a big deal at all.
2025-05-07 13:22:29 -07:00
ASleepyCat 3d5c64feb7 Fix button HID string ranges not being retrieved correctly (#299)
## Description of change
Currently, retrieving HID strings using string index minimum/maximum
ranges for buttons is broken as it uses the same index for each usage
cap.

Now it properly ranges over the minimum/maximum ranges.

Before:

![image](https://github.com/user-attachments/assets/da8d0162-07d9-4027-9933-2348fbf43a27)

After:

![image](https://github.com/user-attachments/assets/c00f81fe-d9d4-43f8-9bdd-d570ef298479)


## Compiling
Check CI.

## Testing
Tested with Beef Board firmware using string index ranges in the USB HID
descriptor.
2025-04-18 01:23:00 -07:00
sp2xdev ed8c72852f Initial commit for GitHub migration based on spice2x-25-03-03 2025-03-10 19:16:49 -07:00