Linux/Wine support: ydotool input dispatcher + IFileOpenDialog picker#7
Open
Alexconquer wants to merge 2 commits into
Open
Linux/Wine support: ydotool input dispatcher + IFileOpenDialog picker#7Alexconquer wants to merge 2 commits into
Alexconquer wants to merge 2 commits into
Conversation
Detect Wine at startup via ntdll!wine_get_version and route IInputMessageDispatcher through ydotool (uinput) when detected, so synthetic keystrokes reach native Linux apps (e.g. Star Citizen under Proton) instead of staying inside the Wine prefix. Bridge the Property Inspector picker through Win32 GetOpenFileNameW (rendered by Wine as a native GTK dialog) so PI settings receive real file paths. Zero behaviour change on Windows native — WineDetector returns false and the existing SendInput path runs unchanged. See docs/linux-wine.md for architecture, prerequisites, and build notes.
Replace the legacy comdlg32!GetOpenFileNameW P/Invoke with the
modern Common Item Dialog (CLSID_FileOpenDialog / IFileOpenDialog,
introduced in Vista). Public API of WineFileDialog is unchanged so
callers don't move. Windows native users now get the shell-style
file picker instead of the XP-era dialog; Wine renders the same COM
dialog via its dlls/comdlg32/itemdlg.c implementation.
docs/linux-wine.md is updated to match (describes the COM flow,
drops the "future migration" note) and gains two new prerequisite
sections:
- winetricks dotnet8 / dotnetdesktop8 inside the Wine prefix that
spawns the plugin.
- GStreamer plugins on the Linux host. gst-plugins-good in
particular is required for MP3 click sounds (provides id3demux);
without it winegstreamer logs "Missing decoder: application/x-id3"
and the sound never plays.
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.
Why
OpenDeck (the open-source Stream Deck alternative) can spawn this plugin
under Wine on Linux when the manifest's
OSarray includes"linux",but Win32
SendInputinside the Wine process produces synthetic inputmessages that stay inside the Wine prefix and never reach native Linux
applications like Star Citizen via Proton. This PR makes the plugin
detect Wine at runtime and route its keyboard/mouse output through
ydotool(a uinput-based Linux utility) when it sees Wine, so deckbutton presses actually reach the game.
It also fixes the Property Inspector file pickers (audio click sounds
and Data.p4k overrides), which were returning only filenames under
OpenDeck because the Tauri WebView doesn't grant the dialog plugin to
plugin-served pages and
<input type="file">is privacy-restricted.The plugin now opens its own
IFileOpenDialog(Common Item Dialog COMAPI) on request — Wine renders it via its mature
dlls/comdlg32/itemdlg.cimplementation and Windows users get thestandard shell-style dialog.
Tested live on CachyOS / Wayland with OpenDeck 7.1 + ydotool 1.0.4
Star Citizen, the AdaptiveKey audio click sounds play (WAV + MP3 once
gst-plugins-goodis installed for ID3 demuxing), andData.p4kchannel overrides apply correctly through the new file picker.
The patch is purely additive on Windows:
WineDetector.IsWinereturns false on native Windows and the existing
SendInputpathruns unchanged. The file picker also switches from
<input type="file">toIFileOpenDialogon Windows — same shelldialog the user already expects, returned path is identical.
Commits
1️⃣
Add Wine runtime detection + ydotool input dispatcherAdds the Wine-aware input path and the cross-process file-picker
plumbing:
WineDetector.cs— one-shotntdll!wine_get_versionprobe,cached in a
Lazy<bool>.LinuxInputBridge.cs— receives anINPUT[]array, batcheskeyboard events into a single
ydotool key A:1 B:1 B:0 A:0call,dispatches mouse clicks / wheel via
ydotool clickandydotool mousemove --wheel. Resolves the daemon socket from$XDG_RUNTIME_DIR/.ydotool_socketwith/tmp/.ydotool_socketasfallback.
Vk2Evdev.cs— VK_* and PS/2 Set 1 scan code → Linux evdevkeycode tables (alpha-num, function row, modifiers L/R, numpad,
navigation cluster, OEM punctuation).
WineFileDialog.cs— Win32 file picker on an STA thread. Backsthe new
requestFilePickerPI ↔ plugin round-trip.WindowsInputMessageDispatcher.cs— 3-line branch thatdelegates to
LinuxInputBridgewhenWineDetector.IsWine.ControlPanelKey.cs/SCActionBase.cs— handlerequestFilePickerfor the four Data.p4k pickers and theAdaptiveKey/ToggleKey audio pickers respectively.
sc-file-picker.js— clicking the picker button now sendsrequestFilePickerto the plugin and listens forfilePickerResultinstead of relying on
<input type="file">.manifest.json— appends{"Platform":"linux","MinimumVersion":"5.0"}to the
OSarray.Cross-build accommodations (no-op on Windows CI):
PluginCore.csprojadds<EnableWindowsTargeting>true</EnableWindowsTargeting>andswaps
\to/in the PiAssetsBuilder pre-build<Exec>command.Tests.csprojcarries the sameEnableWindowsTargeting.DirectInputDisplayMapper.cssubstitutes the['+']collection-expression to
string.Splitwith astatic readonlychar[]field (sidesteps a CS0121 ambiguity on some .NET 8 SDKbuilds, also satisfies CA1861).
2️⃣
Use IFileOpenDialog COM API for the file pickerReplaces the initial
GetOpenFileNameWP/Invoke inWineFileDialogwith
CLSID_FileOpenDialog/IFileOpenDialog(the Vista-eraCommon Item Dialog) — same public API on the C# side, modern
shell-style dialog on the user side, equally well supported under
Wine.
docs/linux-wine.mdis updated to match and adds two prerequisitesections that surfaced during testing:
dotnet8/dotnetdesktop8inside the Wine prefixthat spawns the plugin (Wine-Mono alone wasn't enough on
CachyOS).
winegstreamerdelegates to the host's GStreamer; in particulargst-plugins-goodprovidesid3demuxwhich MP3 files require —without it the click sound silently fails with
Missing decoder: application/x-id3in the Wine debug log).Test plan
Reviewer-side checks recommended on a Windows machine (CI already
covers
dotnet build SCStreamDeck.sln -c Release):modern shell-style Windows file dialog appears and the picked
path is stored in the button's
clickSoundPathsettingbefore
WineDetector.IsWinereturnsfalse(debugger or temporarylog assertion); the
SendInputpath should run unchangedNotes
WindowsInput.csprojkeeps its legacy MSBuild format — only threeadditive
<Compile Include>lines are added. Linux contributorsbuilding locally need to convert it to SDK-style
(
net8.0-windows) themselves; this is documented indocs/linux-wine.mdand intentionally not part of the upstreamdiff to keep the project file changes minimal for the Windows
maintainer.