## Link to GitHub Issue or related Pull Request, if one exists
#345
Hoping that #180 is also addressed by this change, but I can't test it.
## Description of change
IIDX (TDJ) and SDVX (Valk) will now be able to boot in full screen even
with 3 or more monitors attached.
spice will "hide" from the game any monitors other than the primary
monitor and one other monitor for subscreen, allowing it to boot without
crashing - accomplished by clearing `DISPLAY_DEVICE_ATTACHED_TO_DESKTOP`
flag when monitors are enumerated over `EnumDisplayDevicesA`, and
fortunately both games seem to respect that flag.
Add options (one for IIDX, another for SDVX) that lets you specify the
monitor ID of the second monitor.
When the option is set, user-specified monitor will be used as the
subscreen. When the option is not set, spice will just pick the
lowest-indexed monitor as the subscreen, not counting the primary one of
course.
## Testing
Tested both games with three monitors. Should probably work for four or
more.
This was a lot more background work than expected, but that is the
nature of unnecessary hobbies I guess. Most things in here are obvious,
so here's the non-obvious thoughts and notes:
1. All the XP stuff is optional, if the toolchain isn't available it
won't even try
2. The docker build is the "known good" build and now has all the
required tools for XP and checking binaries
a. If you're OK with it, can add the XP_MUST_BUILD flag to
build_docker.sh
4. New `SPICE_XP` flag to comment out blocks
5. We could technically build using the Docker image I've made for my XP
compatible LLVM toolchain, but combining the binaries into a single zip
at the end of it is somewhat tedious, so I've chosen to grab the
binaries from my release
6. I also wrote a DLL checker to make sure the final binaries are
_actually_ XP compatible, which found some issues on x86_64 (I don't
know a single game that runs on 64 bit XP, but it wasn't too much effort
so whatever). This also won't run if missing, just to save the trouble.
7. The build script is still pretty shit, I've made some minor
improvements
a. `/usr/bin/env bash` instead of `/bin/bash` as it's more correct
b. Adding `-it` to the docker build, so Ctrl+C actually halts it
c. Main issue is that failures don't halt, because of the custom error
catching function. This has caused a lot of frustration, maybe we can
change that
## Testing
It runs on 32 and 64 bit installs of XP. My jubeat cab is on Win10 these
days and I haven't got around to testing an actual game, but I've
distributed test builds of this to people who *have* confirmed it works
as expected.
## Link to GitHub Issue or related Pull Request, if one exists
#0
## Description of change
Fix random crashes with CCJ.
This should remove the need to add `d3d10warp.dll` to `
preload_libraries` in `ee-config.xml`.
## Testing
Tried a couple games and didn't run into the crash..
## Description of change
Adds `-mainmonitor` option which changes the monitor layout before
launching the game. This is much more reliable than the old `-monitor`
option which operated at DX9 level. This works for TDJ/UFC subscreens,
for example.
Rename `-monitor` option to `-dx9mainadapter` to discourage use.
`-monitor` will continue to work, of course.
Changing of primary monitor happens first before any orientation changes
/ refresh rate changes, which means those options will result in the
logically correct configuration.
Create a new option category for `Monitor` (rotate, refresh rate, etc).
Add a monitor selection widget for `-mainmonitor` option in the
configurator.
Improve how we log names of monitors in the log during boot - should be
less of "Generic PnP Monitor" after this.
## Description of change
Rotate monitor & change the refresh rate **well before** the game is
launched.
This is much faster and more reliable compared to what we do now, which
is trying to do monitor changes during CreateWindow hooks. For example,
SDVX makes a bunch of OS / NVAPI calls to figure out monitor geometry
while it's booting, and by the time CreateWindow is called, the game
already made up its mind, which leads to weird graphical issues.
This affects both windowed mode and full screen.
In addition, add options for normal orientation (landscape) and upside
down (landscape, flipped) options. This can be used if the monitor is
normally rotated to portrait, but the game needs to be in landscape.
## Link to GitHub Issue or related Pull Request, if one exists
#287
## Description of change
Switch over to new event-based I/O system in ImGui so that we can keep
up with ImGui updates.
Unlike #287, this change does not modify how mouse position is handled.
That continues to be supported by newer versions of ImGui.
## Testing
wip
## Link to GitHub Issue or related Pull Request, if one exists
#593
## Description of change
* Display a confirmation dialog when clicking on `Generate` for the
first time (to prevent accidental loss of card number)
* If `cardN.txt` contents are read back successfully, show card number
in green to indicate success, and red in case of failure.
## Description of change
Merge option name and command line parameter columns.
Expand the size of widget column.
In Search tab, add a new column to display the category.
Add a highlight effect to rows when hovered over - apply this to all
tables in the configurator UI.
## Link to GitHub Issue or related Pull Request, if one exists
#596
## Description of change
Adds call to `libutils::print_dll_info` for early hooks too.
## Testing
```
[2026/03/27 09:51:16] I:launcher: SpiceTools Bootstrap (x64) (spice2x)
[2026/03/27 09:51:16] I:launcher: 1.0-V-2026-03-27T07:46:10
[2026/03/27 09:51:16] I:launcher: spice2x is free & open source; if you paid money for it, you got scammed
[2026/03/27 09:51:16] I:launcher: visit https://spice2x.github.io to download the latest version for free
[2026/03/27 09:51:16] I:launcher: arguments:
[...]
-z C:\Users\Noe\AppData\Local\Programs\SpiceTools\hooks\64\mempatcher64.dll
[...]
[2026/03/27 09:51:16] I:launcher: loading early hook DLL C:\Users\Noe\AppData\Local\Programs\SpiceTools\hooks\64\mempatcher64.dll
[2026/03/27 09:51:16] I:superexit: enabled
[2026/03/27 09:51:16] I:libutils: DLL info for mempatcher64.dll: CompanyName = aixxe, ProductName = mempatcher, Version = 4975386c637a86e8daa89d479a0c67ab28d792ec
```
## Link to GitHub Issue or related Pull Request, if one exists
#592
## Description of change
* when custom DLLs are detected (`d3d9.dll`) print out some basic data
from the PE header
* for our own NVIDIA DLL stubs, add manifest files to identify ourselves
* as a bonus, when DLL hooks are loaded from `-k`, print DLL info there
as well
This is mainly to detect when DXVK is in use.
Show better warning message when `ea3-config.xml` / `eamuse-config.xml`
is missing. Right now we just say `failed to load prop/eamuseconfig.xml`
which is really confusing when people look for `eamuse-config.xml` that
never existed in the first place.
## Link to GitHub Issue or related Pull Request, if one exists
#345
## Description of change
When X or Y axis is being bound to any button labeled `TT` or `Knob` or
`VOL-`, show a warning and ask if the user really meant to do that,
encouraging them to use the Analog tab instead.
* add `-card0` `-card1` options at the top of Cards tab to clearly
indicate that they take precedence over card files
* reorganize UI / clean up
* remove ability to directly edit the contents of `card0.txt` /
`card1.txt` as that wasn't very intuitive; instead, encourage users to
use overrides directly or use an external text editor (`Edit` button
opens notepad)
## Link to GitHub Issue or related Pull Request, if one exists
For #587
## Description of change
`Invert Touch` option is now honored by the IIDX/SDVX touch handler.
## Link to GitHub Issue or related Pull Request, if one exists
#579
## Description of change
* Fix profiles being loaded twice on tab switch
* Add more default profiles for some controllers
* Remove borders from tables since they look broken in software renderer
* Add check boxes to import/export only certain parts of of a profile
* Show device identifier string in drop down when applying profiles
since some controllers have multiple identically named interfaces
* Show completion message when action buttons are clicked (`Apply`
button, `Clear all bindings` button both become disabled & shows `done`
message)
## Link to GitHub Issue or related Pull Request, if one exists
N/A
## Description of change
Move `dirs_created` flag assignment before `dir_create_recursive` calls
in `CreateFileW_Hook` to prevent stack overflow. `dir_create_recursive`
calls `_wstat64` (ucrtbase), which internally calls `CreateFileW`,
re-entering the hook before the flag is set. GCC 13 preserved the source
order, but GCC 15 reorders the flag store after the function calls,
causing infinite recursion.
Note: I'm not fully confident the root cause is specific to GCC version
differences. Also, I cannot determine whether this directory creation
hook is truly necessary. Without these directories the game boots but
quizzes won't load, making gameplay impossible. It may be worth removing
this hook entirely, but for now this fix is needed to prevent the crash.
## Testing
Verified title screen transition on LMA-2019022700. Crashes on the
latest build without this fix.
## Link to GitHub Issue or related Pull Request, if one exists
Implements #579.
## Description of change
### Controller Presets
Add a new "Presets" tab to spicecfg that allows users to save, load, and
manage controller binding presets.
#### Save Presets
- Capture all current button, analog, and light bindings as a preset
- "Assign Labels" dialog prompts the user to name each source device
(e.g. "Player 1", "Player 2") before saving
- Device IDs are replaced with these labels, making presets portable
across different machines
- Presets are stored in `%APPDATA%/spice2x/spicetools_presets.xml`
#### Load / Apply Presets
- Preset list shows name, type (Built-in / User), and binding counts
- Apply dialog maps each preset source label to a connected device or
keyboard
- Bindings are applied per-source, supporting multi-device setups (e.g.
two PHOENIXWAN controllers)
#### Edit / Delete Presets
- Rename source labels in saved presets (propagates to all bindings)
- Delete user presets
#### Built-in Presets
- PHOENIXWAN preset for Beatmania IIDX: P1/P2 buttons (1-7, Start,
EFFECT, VEFX), turntable analogs, and button lights
## Testing
* [x] Open spicecfg, go to Buttons tab, verify Presets section loads
* [x] Verify PHOENIXWAN builtin preset appears for Beatmania IIDX
* [x] Save a new preset: confirm "Assign Labels" dialog appears with
device descriptions as defaults
* [x] Apply a preset: confirm source column shows labels, popup does not
shrink
* [x] Edit labels on a saved preset: confirm rename propagates to all
bindings
* [x] Hover over a device source tooltip: confirm vKey shows as number
Fix stale frame returned by capture API on rapid successive calls
> [!NOTE]
> Before submitting code changes...
> * Please do note that this is a GPL v3.0 open source project.
> * Please read the
[CONTRIBUTING](https://github.com/spice2x/spice2x.github.io/blob/main/CONTRIBUTING.md)
guide.
> * Maintainers reserve the right to reject or modify your submission
without reason.
> * No new compiler warnings must be introduced. Check the CI build
results.
>
> Feel free to remove this section after you have read it.
## Link to GitHub Issue or related Pull Request, if one exists
https://github.com/spice2x/spice2x.github.io/issues/582
## Description of change
When using the SpiceAPI `capture` endpoint for taking screenshots, if
you call multiple times in a row in a short period, there's a good
chance for duplicate / stale data to be returned, and you end up with
multiple identical screenshots. This is due to a race condition in the
graphics capture pipeline because the capture data is never reset to
null between invocations.
`graphics_capture_receive_jpeg()` never resets the capture buffer's data
pointer to `nullptr` after consuming it. The condition variable wait
predicate checks `data != nullptr`, so subsequent calls find the
predicate already satisfied and return immediately with the previous
frame instead of waiting for the render thread to produce a fresh one.
Fix: null out `capture.data` after copying the shared_ptr (which keeps
the pixel data alive via refcount) but before releasing the lock.
## Testing
Tested this locally and invoked the capture API 10+ times in a row
without any duplicates. Previously, every other invocation would be a
duplicate, basically.
## Link to GitHub Issue or related Pull Request, if one exists
#578
## Description of change
Use `Clear All` when there are no defaults, and `Reset All` when there
are defaults.
Clearing analogs should reset values to 0.5, not 0.
## Link to GitHub Issue or related Pull Request, if one exists
#576
## Description of change
Add `Reset All` buttons to these tabs which clears out bindings to none
/ default.
For keypads, introduce a special `Use Preset` button which lets users
pick between numpad and top row number keys.
Update UI-visible string used for vKeys, especially the numpad ones
(e.g., `.` is now `Numpad .` to distinguish from the regular `.`
period).
Breaking change: if the user never had `P1 Keypad 00` set, the default
will change from `Enter` to `Numpad -` since both enter keys trigger the
same. This will affect a small number of popn/ddr players. They can just
change it back.
## Testing
*how was the code tested?*
## Link to GitHub Issue or related Pull Request, if one exists
#574
## Description of change
Refactor so that grouping of lights are in common I/O code. Add this to
IIDX/SDVX/DDR/GitaDora.
## Testing
## Link to GitHub Issue or related Pull Request, if one exists
#574
## Description of change
* Add binds for Nostroller
* Update matching logic to ignore common device-side output names like
"Button" "Light" and "LED" (e.g., `Button 1` from a device now matches
on `P1 1`)
* For RGB matching, in addition to `Light R` on the device also try
`LightR` (Nostroller needs this)
* Add a confirmation dialog for `Clear All`
* Address minor bugs
## Testing
Seems to work on arcin, and Nostroller. Still need to retest Faucetwo.
Hopefully I didn't break Phoenixwan.
<img width="784" height="561" alt="image"
src="https://github.com/user-attachments/assets/3ac6bf6d-2ca8-40e5-80ea-b0fd9e080d7b"
/>
## Link to GitHub Issue or related Pull Request, if one exists
n/a
## Description of change
I've always been annoyed with how long it takes to bind controller
lights, made a few improvements
1) added a button+window for automatically matching device lights to
game lights with the same name
2) added button(s) to cycle through all bound lights to visually confirm
location/function
3) added button to clear all bound lights
4) split SDVX lights into sections (Buttons, Valkyrie, Nemsys, Other)
with formatting, sorted based on current game spec
## Testing
Tested with multiple games and controllers (Faucetwo, custom con) and
matching always works if the descriptor strings are labeled correctly.
Not every controller labels their LEDs the same was as spice, but for
those that do this saves a ton of time clicking every box and testing
one by one.
The SDVX table split/formatting is important because myself (and several
friends) have tried binding to Wing/Controller lights and wondered why
they weren't working in game, when they are legacy Nemsys lights instead
of the strip lights handled by Valk/bi2x. I separated the sections
visually, with tooltips, plus sort the two sections based on active spec
to further minimize the chance of someone trying to use the wrong lights
for their game.
## Link to GitHub Issue or related Pull Request, if one exists
related to #154 though this PR doesn't fix it
## Description of change
1. Add an option for cam hook so that the game can be launched without
any camera
1. Rotate image printed out by print-to-file so that it's right side up
(portrait orientation)
## Testing
Able to boot the game without any cameras, and tested printing in test
menu.
"Holo" printing remains broken.
## Link to GitHub Issue or related Pull Request, if one exists
n/a
## Description of change
Hide the ImGui-rendered cursor in the overlay when the mouse is idle for
more than 2 seconds.
## Testing
Tested windowed and fullscreen.
## Description of change
* Show more descriptive error when connection fails (for
`ERROR_WINHTTP_NAME_NOT_RESOLVED`)
* ensure patches are reloaded even if importing fails, since existing
checkboxes get reset
Logic was wrong; caught by compiling with a newer clang and it raising a
warning about the useless expression (since the second clause always
eval'd as true).
Changed to the intended functionality, but I have no ddr3 with p3io so I
can't test it. But it seems nobody ever really noticed this.
- Allow overriding the toolchains so I can avoid changes in my working
tree
- Squash warnings that the deps use, can't just add them as PRIVATE
compile flags because it's in the headers :(
- Squash those d3d9 warnings with a suppression instead of trying to
rewrite 400 lines of code
- Include order and forward decls were breaking button.h because a
declared but not defined struct can't be initiated (honestly this file
was cooked, crazy include order).
- `MAXINT` is GCC specific, `INT_MAX` is portable.
- InterlockedDecrement takes a LONG, not ULONG
- an imgui printf-style call using a direct string instead of %s (let's
ignore the fact that it's actually safe based on how the str is
constructed)
- missing `override` on a virtual subclass
- `CALLBACK` on a lambda threw me for a loop, but I believe moving it
after the arg list is the correct approach (see if it builds on gcc I
guess)
- `std::result_of` was removed in C++20, which the project is built with
## 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.