## Link to GitHub Issue or related Pull Request, if one exists
Fixes#779
Regressed by #720
## Description of change
#720 introduced a static dependency on DX9 which caused `d3d9.dll` to be
loaded at boot from `system32`. Some third party hooks (like
ifs_layeredfs and dxvk) rely on supplying a custom `d3d9.dll` in the DLL
search path (usually in modules) but this change caused Windows to skip
that check.
Remove the hard dependency on d3d9 and add a CMake check to ensure that
compiled binaries do not accidentally introduce new static imports in
the future.
## Testing
Confirmed that dxvk runs again.
Only affects the caption bar.
Should work for:
- [x] standalone configurator
- [x] dx9 games, including multi-window games like gitadora
- [x] Unity games
## Link to GitHub Issue or related Pull Request, if one exists
n/a
## Description of change
Fully flush `tmp` file and then use `MoveFileExW` instead of `CopyFileW`
which guarantees atomic operation on NTFS.
## Testing
## Link to GitHub Issue or related Pull Request, if one exists
#0
## Description of change
Combine API/Options/Advanced/Development/Search tabs into one Options
tab and add a left nav for navigation categories.
Reduce information density for options table by making each row double
the height and slightly increasing widget sizes.
## Testing
## Link to GitHub Issue or related Pull Request, if one exists
n/a
## Description of change
Create three distinct layers for the overlay:
1. Bottommost persistent layer - non-interactable layer that is always
on. This was only for notifications, but now the FPS widget lives here
as well.
2. Overlay windows layer - most interactable windows go here.
3. Topmost main menu - this is reserved for the main menu (escape key)
and this is a modal dialog that occludes the layers below.
Why?
- `toggle overlay` behavior with FPS widget *also* toggling on/off was a
bit confusing (now they're two separate keys)
- FPS widget is popular, but it caused the entire overlay to be active,
which affects how input is handled
- the main menu being a standalone window was a little awkward (now it's
a modal)
## Testing
## Link to GitHub Issue or related Pull Request, if one exists
#720
## Description of change
Pass `VK_F4` sys-key messages through to `DefWindowProc` before ImGui
ingestion, restoring the normal Alt+F4 -> `WM_CLOSE` ->
`launcher::shutdown()` path.
## Testing
- [x] Launch `spicecfg` (D3D9 default path) and press Alt+F4; window
closes and process exits
- [x] Launch `spicecfg` (software path) and press Alt+F4; window closes
and process exits
- [x] Close via title-bar X; still works
## Description of change
**Configurator (spicecfg.exe)**
- Attempts to create a D3D9 device on startup and uses the hardware
ImGui DX9 path when successful; falls back to the existing software
rasterizer automatically if D3D9 init fails.
- Rewrites the configurator window loop: refresh-rate-aware render
timer, minimize/resize/`WM_DISPLAYCHANGE` handling, direct Win32 ->
ImGui input (keyboard, mouse, wheel), and optimized software painting
via `SetDIBitsToDevice` instead of per-frame GDI `HBITMAP` allocation.
**Overlay / input (scoped to standalone configurator)**
- Skips expensive per-frame rawinput polling in
`ImGui_ImplSpice_NewFrame` when `CONFIGURATOR_STANDALONE` is set (Win32
messages drive input instead).
- Adds software-renderer idle-frame detection (`sw_pixels_dirty` +
draw-data hash) so spicecfg only repaints when pixels actually change.
- Adds `ImGuiWindowFlags_NoScrollWithMouse` on the configurator root
window to prevent scroll jolt on non-scrollable child widgets.
## Link to GitHub Issue or related Pull Request, if one exists
#0
## Description of change
Save config xml once instead of ~33 times
## Testing
xml is still saved properly
## Link to GitHub Issue or related Pull Request, if one exists
#694
## Description of change
Before this change, we have it set in the executable manifest to always
ask for UAC elevation.
This change removes that and instead attempts to prompt for elevation
when we launch, depending on the new developer option that is being
added here to run as current user instead of elevating.
The default behavior continues to run as admin. This is still the safest
in terms of regression risk.
A bit of history on this: while spicecfg never technically needed to
elevate, we continue to do so to avoid difference in behavior when the
game is launched. For example, if the user is using an input remapper
running without elevation, it would inject input into spicecfg running
as user but fail to do so if the game runs elevated.
WinXP builds are unaffected (there is no UAC).
Some features will straight up fail without elevation so this will
remain as a debug option. To name a few (not a complete list):
* reboot/shutdown of PC
* running at realtime process priority
* `-nvprofile` option
* ...
## Testing
## Link to GitHub Issue or related Pull Request, if one exists
#181
## Description of change
Implement analog relative mode and delay option using a new
millisecond-based algorithm.
## Testing
WIP
## Link to GitHub Issue or related Pull Request, if one exists
n/a
## Description of change
Add a checkbox to the buttons edit dialog that lets you set a device as
"always on", accomplished by setting the device to `Naive`, vkey to
`0xff` (invalid), and `Invert`.
No backend rawinput changes.
## Testing
## Link to GitHub Issue or related Pull Request, if one exists
Related to #181
## Description of change
This PR removes two features marked as "experimental" for analog axis -
`Delay` and `Relative Axis`.
They have been in spice as experimental option for almost 2 years.. but
they have a fundamental problem of being tied to how often the analog is
polled. Not just how often the game's I/O emulation code polls it, but
literally any source (spice API, overlay, etc).
For `Delay`, the only real usage I'm aware of is for #181 which is
delaying IIDX turntable input. For this, I will follow up with a
separate PR that adds back the delay option specifically for IIDX.
For `Relative Axis` - I'm not quite sure if any one actually uses this.
This could be implemented per-game if some game demands it. Polaris
Chord already has one, for example.
## Testing
## Link to GitHub Issue or related Pull Request, if one exists
n/a
## Description of change
Currently, all analogs are treated as circular values that wrap around.
This works for knobs and turntables, but can get weird for linear values
(like tilt sensors and sliders) especially once analog options are
enabled, such as sensitivity.
This PR groups analogs into 3 buckets: circular, linear (centered), and
linear (positive). Linear types get different algorithms applied to it
when options are set (e.g., sensitivity caps out at 0, 1 instead of
wrapping around).
In linear mode:
* Sensitivity value applies an exponential response curve (power curve)
to the original value.
* Multiplier/divisor serves as a linear cut-off.
* Relative mode works as you expect, but of course, values don't wrap
around.
* Invert and deadzone work as you expect (since they applied to the
controller input anyway)
* Smoothing is removed from the UI and has no effect.
* Delay is unaffected.
Also, fix a small bug with -/+ button not working for analog `Delay`
option.
## Testing
WIP
As noted in #567, a filesystem path that contains non-ascii will break a
lot if using a clang toolchain.
Luckily, fmtlib has a lossy utf8 convert when you use it to print a path
(after including `fmt/std.h`). The vast majority of this diff is just
removing `.string()` from paths inside loggings calls.
There are some callsites I _didn't_ touch, mainly the options, because
it would be an ABI break to change those to be wide strings and I cbf
looking into settings upgrades. There are also some spots (avs mountpath
remapping, for example) where the path is guaranteed to be ascii, so I
didn't modify them.
ImGui doesn't appear to easily support wide strings (I mean, surely it
does, but I'm not gonna look too far into it) so I mostly just left
those alone too, with a few spots modified to re-use fmtlib's lossy
utf8.
Some of the changes are basically never gonna be hit IRL, like who would
put a file with a non-ascii _extension_ along with their modules? But
the diff is (I hope) pretty easy to validate as OK.
Testing has been somewhat minimal, I fired up the GCC build of spice2x
in a dodgy folder name, got mojibake (running via wine in linux so take
that as you will), ran the unmodified clang spice and crashed the same
way the reporter did. After modification, I get the exact same mojibake
so I assume if the terminal enjoys utf8 it'll display OK.
Claude (only used for review) thinks the commit is fine but is annoyed
that I use `fmt::detail` in the appdata censoring, which is part of the
private API; personally I don't care because it's pretty stable.
## Link to GitHub Issue or related Pull Request, if one exists
#653
## Description of change
By default, BAT Positive / Negative binds trigger when the stick is
tilted 10% off the center.
This needs a bit more customization since:
1. User may want to customize the center point (e.g., guitar controller
neutral position)
2. User may want to adjust the sensitivity (e.g., guitar controller tilt
angle to trigger wailing).
## Testing
WIP
## Description of change
This adds a toggleable option to remove the rounded window corners when
running a game, or a subscreen, in a window on Windows 11 and upwards.
## Testing
On Windows 11: Resort Anthem, MÚSECA and EPOLIS were tested and the
window corners were removed from both main windows and the TDJ subscreen
when running in windowed mode, with no change in fullscreen mode.
On Windows 7: IIDX18 was tested with no change, the call to
`DwmSetWindowAttribute` is ignored as `DWMWA_WINDOW_CORNER_PREFERENCE`
doesn't exist.
For XP builds, the call is compiled out to avoid linking against dwmapi
and windows_dll_compat_checker returns successfully when testing against
the XP Embedded image. I can't test it on XP, but it ran on Vista.
## 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.
## 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.
## 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.
## 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
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
## 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
- 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
## 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
The old pages UI was not intuitive and often led to questions like:
* How do I bind multiple controllers to a single input?? (failure to
discover)
* I have a ghost input that won't go away, how do I fix this? Is this a
bug? (non-intuitive UI - there are too many pages and finding out where
each binding is potentially requires scrolling through 100 pages)
* Potential perf issue - user binds too many by accident, or puts
bindings all the way in page 99, requiring us to walk each element in
the vector, wasting precious CPU cycles during an input poll.
This PR removes the multiple pages, and puts everything on a single
page, showing multiple binds in a tree structure.
It also puts a hard limit on how many alternate bindings can be made (8
for buttons, 16 for lights), though if the user has configured more in
older version they will be respected.
## Link to GitHub Issue, if one exists
#0
## Description of change
Occasionally we would read a bad "vKey" for an analog axis and end up
accessing invalid memory (beyond the size of a vector) and potentially
crash or read junk values.
## Testing
Fixed based on minidump, this was a rare repro though.
## Description of change
Three bugs:
* Some keys are IME-dependent. Right Alt can be IME mode switch for
Japanese / Korean, and Right Ctrl is often the Kanji button.
* If you press modifiers like Ctrl during bind-many-naive, it will skip
over a button, because of broken for loop logic that ends up calling
`inc_buttons_many_index` too many times
* trying to cancel out of bind-many-naive with left and right mouse
buttons swap doesn't work
## Testing
Validating various IME. I don't have a keyboard in another language
though..
## Link to GitHub Issue, if one exists
n/a
## Description of change
Improper bounds check resulting in crash when binding mouse buttons
beyond Mouse 5.
## Testing
Tested with `Edit` function.
## Link to GitHub Issue, if one exists
n/a
## Description of change
For buttons and lights, it's possible to have multiple alternatives.
When you create alternatives and then clear then, the config files
continue to have stale entries. This is because alternatives are stored
in a vector and elements are never deleted when unbound; they get
written out to the XML on modification.
These stale XML entries live forever, and get loaded on next startup of
spice.
This PR fixes that by deleting stale entries - basically, XML nodes will
be kept only until the last valid node (properly bound button or light),
trimming the trailing invalid entries.
## Testing
Manual testing, validating XML.
## Link to GitHub Issue, if one exists
Regressed by #401
## Description of change
Two things from testing SDVX Live2D -
1. ColorFill is almost always too expensive and will lead to drops
1. Scale factor of 0.5 causes GPU to sync and causes drops
(ARGB/XRGB doesn't matter, linear filtering doesn't matter)
1 is fixed by removing ColorFill calls on every frame - instead only do
this once when the user changes the duplicate option (on the next frame)
2 is fixed by updating the UI (limit the slider) though people can
ctrl+click to override these slider limits.
The warning label will be kept with slightly reworded text.
## Testing
tested in sdvx eg final (sudden death) - on my RTX 4070, my FPS is rock
solid 120 fps even with image resize on now.
## Link to GitHub Issue, if one exists
n/a
## Description of change
Turning on Image Resize feature completely tanks performance of Live2D
in some SDVX songs. Add a giant warning next to the UI.
On my system with RTX 4070, Sudden Death is normally a rock solid
120FPS, but drops to 30-40FPS when resizing is on.
* linear filter does not affect this at all
* window resize options also have no effect
It's really just rendering on a larger surface + calling `StretchRect`
that does this.
Additionally, hide the resolution swap option since it sees very low
usage & has potential gotchas likes this.
## Link to GitHub Issue, if one exists
#477
## Description of change
F11 menu (window settings) did not work for arena model because the game
engine races to create many windows, so our logic of grabbing the first
window created doesn't always get the main window.
## Testing
## Link to GitHub Issue, if one exists
n/a
## Description of change
Add the raw device handle string to tooltip.
Add `Reset` button that clears all values.
## Testing
manual testing
## Link to GitHub Issue, if one exists
#399
## Description of change
Add image duplication option to screen resize, allowing overflow images
to wrap around the other side.
## Testing
Tested with DDR, IIDX (windowed and full screen TDJ), SDVX (orientation
swap)
## Link to GitHub Issue, if one exists
Fixes#190
## Description of change
When `-cmdoverride` is specified, any command line arguments are taken
first before merging with what is in the config file.
## Testing
Still testing...
## 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.
## Link to GitHub Issue, if one exists
n/a
## Description of change
For JSON config files of the following features:
* patch manager
* screen resize
* IIDX camera hook
* card manager
when saving a new file, store them in %appdata%\spice2x instead of
%appdata%.
On load:
1. If the JSON file exists in %appdata%\spice2x, use that (new path)
1. If the JSON file exists in %appdata%, continue to use that (legacy
path)
It's common for people to have mixed versions of spicetools/spice2x so
we'll continue to read from the %appdata% root if the files are there,
but with a preference for the new path. We will not forcibly move files.
spicetools.xml will continue to live in the %appdata% root. Moving this
will confuse a lot of people, so I'm avoiding this.
Also, this fixes `-patchcfgpath` and `-resizecfgpath` to create
directories as needed (previously the parent directory must have existed
first)
## Testing
Tested -
* existing config files are continued to be read from %appdata%
* new files get created in %appdata%\spice2x\... (both in spicecfg and
in overlay)
* can provide custom path for `-patchcfgpath` `-resizecfgpath` and
observe directories + file created in custom path, try absolute or local
relative paths
## Link to GitHub Issue, if one exists
Fixes#276
## Description of change
Note: this change is not compatible with previous screen resize config;
i.e., if you had the zoom setting dialed into a certain view, after this
change it won't be the same area, so you'll have to set up a scene
again. I think this is a worthwhile cost since the old logic is just
broken in weird ways, and preserving old settings is really tedious math
(for a feature that not many people use). Besides, this change will only
use the new Scenes values from the JSON.
Rewrite the DX9 image scaler logic.
* Previously, the rendering surface was fixed at `4096*4096 px`. Now,
this is relative to the backbuffer dimensions, which depends on the game
& respects user provided `-forceres`.
* Remove "center" option, make it the default.
Above two changes fix the aspect ratio issue (scaling in portrait games
not respecting screen ratio) and things breaking at higher res (1080p
when zoomed out far enough, or when forced to run at 4k resolution for
example)
* Use `scenes` leaf of screen resize JSON config for Scene 1 as well,
completely removing ourselves from being compatible with older spice2x
versions for these values.
* Add additional bounds check before calling `StretchRect` to avoid
users getting stuck with a bad layout, which can kill performance.
## Compiling
🦾
## Testing
Tested 32 bit (popn / ddr), 64 bit (ldj), portrait and landscape modes
(kfc)
## Link to GitHub Issue, if one exists
Fixes#263
## Description of change
Add "scenes" to screen resize.
* UI changes - F11 menu now has a "scene switcher" for `Scene 1/2/3/4`.
Clean up other UI bits.
* Add hotkeys for `Screen Resize Scene 1`, `Screen Resize 2`, and so on.
* Detect hot key and trigger resizes.
* Add additional objects to screen_resize.json for saving and loading
the new scene settings.
* Existing screen resize data is backwards compatible (can be
loaded/saved to JSON), and is treated as `Scene 1`.
* Add API endpoint for `Resize`, allow toggling resize on/off, switching
active scene
* Add Python wrapper. Did not bother with the other wrappers (Dart, C++,
etc)...
## Compiling
🥇
## Testing
Still testing, but seems to work fine for TDJ.