Skip to content

Commit e3c8713

Browse files
Refresh Virtual HID keyboard and mouse path
Renamed the license-state refresh flow from mouse-only to shared virtual input so Sunshine now recreates both libvirtualhid keyboard and mouse devices, including resetting keyboard/mouse state before refresh. Added explicit keyboard refresh support in the virtualhid input context and wired config HTTP license updates to trigger the full refresh. Updated Windows-facing messaging and docs to describe Raw Input keyboard + mouse support, added troubleshooting guidance for keyboard detection, and adjusted tray/UI localization strings accordingly. Also bumped the minimum supported Virtual HID Driver version to 2026.826.2024.22, updated related unit tests, and advanced the libvirtualhid submodule.
1 parent 377e07c commit e3c8713

14 files changed

Lines changed: 93 additions & 53 deletions

File tree

docs/getting_started.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -476,10 +476,10 @@ and enter its device name in the [audio_sink](configuration.md#audio_sink) field
476476
### Windows
477477
Sunshine uses libvirtualhid for virtual input on Windows. You must install the
478478
[Virtual HID Driver](https://github.com/LizardByte/libvirtualhid/releases/latest) separately for a driver-backed Raw
479-
Input mouse and full virtual gamepad support. ViGEmBus is detected only as a limited fallback for Xbox 360 and
480-
DualShock 4 gamepads when libvirtualhid is unavailable.
479+
Input keyboard and mouse plus full virtual gamepad support. ViGEmBus is detected only as a limited fallback for Xbox
480+
360 and DualShock 4 gamepads when libvirtualhid is unavailable.
481481

482-
Sunshine requires Virtual HID Driver version `2026.823.352.3` or newer. Earlier releases use incompatible Windows
482+
Sunshine requires Virtual HID Driver version `2026.826.2024.22` or newer. Earlier releases use incompatible Windows
483483
control and broker protocols and must be upgraded together with Sunshine's embedded libvirtualhid library. Local
484484
development driver builds using a `0.0.0.*` version remain supported.
485485

@@ -488,15 +488,21 @@ Pro, and Generic gamepads in addition to Xbox 360 and DualShock 4. It can also e
488488
as motion, touchpads, LEDs, and adaptive triggers when supported. Virtual HID Driver is actively developed and
489489
supported by the LizardByte team.
490490

491-
With a compatible driver and active license, relative mouse movement, buttons, and scrolling are exposed as a real HID
491+
With a compatible driver and active license, normal key transitions are exposed through a real HID keyboard so
492+
applications using Raw Input can receive them. Unicode text input and keys outside the supported HID keyboard page
493+
continue to use Windows input injection. When the driver-backed keyboard cannot be created because the driver,
494+
broker, or license is unavailable, libvirtualhid retains its legacy SendInput fallback.
495+
496+
Relative mouse movement, buttons, and scrolling are exposed as a real HID
492497
mouse so applications using Raw Input can receive them. Absolute mouse positioning continues to use Windows input
493498
injection. When the driver-backed mouse cannot be created, libvirtualhid retains its legacy SendInput fallback.
494499

495500
The Virtual HID Driver requires an active machine license for driver-backed devices, including gamepads and the Raw
496-
Input mouse. Sunshine shows the current license status and actions on the Web UI Troubleshooting page and in the
497-
**Virtual HID Driver** system tray submenu. When Sunshine starts on an unactivated machine, select its tray notification
498-
to open the activation and purchase options in the Web UI. Sunshine recreates the shared mouse after a successful
499-
license action, so switching between the HID and SendInput paths does not require restarting Sunshine.
501+
Input keyboard and mouse. Sunshine shows the current license status and actions on the Web UI Troubleshooting page and
502+
in the **Virtual HID Driver** system tray submenu. When Sunshine starts on an unactivated machine, select its tray
503+
notification to open the activation and purchase options in the Web UI. Sunshine recreates the shared keyboard and
504+
mouse after a successful license action, so switching between the HID and SendInput paths does not require restarting
505+
Sunshine.
500506

501507
After installing or updating virtual input drivers, it is recommended to restart your computer.
502508

docs/troubleshooting.md

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -292,11 +292,11 @@ launchctl load -w /Library/LaunchAgents/org.freedesktop.dbus-session.plist
292292
### No gamepad detected
293293
Sunshine uses libvirtualhid for virtual input on Windows. Install the
294294
[Virtual HID Driver](https://github.com/LizardByte/libvirtualhid/releases/latest) separately for a driver-backed Raw
295-
Input mouse and full virtual gamepad support. ViGEmBus is detected only as a limited fallback for Xbox 360 and
296-
DualShock 4 gamepads when libvirtualhid is unavailable. If you use the
295+
Input keyboard and mouse plus full virtual gamepad support. ViGEmBus is detected only as a limited fallback for Xbox
296+
360 and DualShock 4 gamepads when libvirtualhid is unavailable. If you use the
297297
[ViGEmBus fallback](https://github.com/nefarius/ViGEmBus/releases/latest), you must use version 1.17 or newer.
298298
299-
Sunshine requires Virtual HID Driver version `2026.823.352.3` or newer. Earlier releases use incompatible Windows
299+
Sunshine requires Virtual HID Driver version `2026.826.2024.22` or newer. Earlier releases use incompatible Windows
300300
control and broker protocols. The Troubleshooting page reports an older installed package as unsupported and links
301301
to the current driver release. Local development driver builds using a `0.0.0.*` version remain supported.
302302
@@ -305,21 +305,31 @@ controller features such as motion, touchpads, LEDs, and adaptive triggers when
305305
ViGEmBus project, Virtual HID Driver is actively developed and supported by the LizardByte team.
306306
307307
An active Virtual HID Driver machine license is required before Sunshine can create driver-backed libvirtualhid
308-
devices, including gamepads and the Raw Input mouse. Follow the warning on the Web UI home page, the startup tray
309-
notification, or the **Virtual HID Driver** tray submenu to open the license section on the Troubleshooting page, where
310-
you can activate a key or follow the purchase link.
308+
devices, including gamepads and the Raw Input keyboard and mouse. Follow the warning on the Web UI home page, the
309+
startup tray notification, or the **Virtual HID Driver** tray submenu to open the license section on the
310+
Troubleshooting page, where you can activate a key or follow the purchase link.
311311
312312
After installation, it is recommended to restart your computer.
313313
314+
### Games do not detect keyboard input
315+
With a compatible Virtual HID Driver and active license, Sunshine sends normal key transitions through a real HID
316+
keyboard so games using Raw Input can receive them. Unicode text input and keys outside the supported HID keyboard
317+
page continue to use Windows input injection. When the driver-backed keyboard cannot be created because the driver,
318+
broker, or license is unavailable, libvirtualhid falls back to SendInput.
319+
320+
Check the Virtual HID Driver version and license sections on the Web UI Troubleshooting page. Sunshine recreates the
321+
shared keyboard and mouse after a successful license activation, validation, or deactivation, so you do not need to
322+
restart Sunshine merely to switch between the HID and SendInput paths.
323+
314324
### Games do not detect mouse input
315325
With a compatible Virtual HID Driver and active license, Sunshine sends relative mouse movement, buttons, and scrolling
316326
through a real HID device so games using Raw Input can receive them. Absolute positioning still uses Windows input
317327
injection. When the driver-backed mouse cannot be created, libvirtualhid falls back to SendInput; the Windows cursor may
318328
still move even though a game that listens only for Raw Input receives nothing.
319329
320330
Check the Virtual HID Driver version and license sections on the Web UI Troubleshooting page even when controller input
321-
is disabled. Sunshine recreates the shared mouse after a successful license activation, validation, or deactivation, so
322-
you do not need to restart Sunshine merely to switch between the HID and SendInput paths.
331+
is disabled. The same live refresh used by the keyboard path also switches the mouse between HID and SendInput without
332+
requiring a Sunshine restart.
323333
324334
### Permission denied
325335
Since Sunshine runs as a service on Windows, it may not have the same level of access that your regular user account

src/confighttp.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ namespace confighttp {
175175
*/
176176
constexpr auto CSRF_TOKEN_LIFETIME = std::chrono::hours(1); // Tokens valid for 1 hour
177177

178-
constexpr auto LIBVIRTUALHID_MINIMUM_VERSION = "2026.823.352.3"sv; ///< Minimum supported libvirtualhid driver version. // NOSONAR(cpp:S1313): not an IP address
178+
constexpr auto LIBVIRTUALHID_MINIMUM_VERSION = "2026.826.2024.22"sv; ///< Minimum supported libvirtualhid driver version. // NOSONAR(cpp:S1313): not an IP address
179179
constexpr auto VIGEMBUS_MINIMUM_VERSION = "1.17.0.0"sv; ///< Minimum supported ViGEmBus fallback driver version. // NOSONAR(cpp:S1313): not an IP address
180180

181181
/**
@@ -1958,7 +1958,7 @@ namespace confighttp {
19581958
#endif
19591959
#ifdef _WIN32
19601960
if (result.status.ok()) {
1961-
input::refresh_virtual_mouse();
1961+
input::refresh_virtual_input();
19621962
}
19631963
#endif
19641964
send_response(response, build_virtualhid_license_status(result));

src/input.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2091,11 +2091,16 @@ namespace input {
20912091
});
20922092
}
20932093

2094-
void refresh_virtual_mouse() {
2094+
void refresh_virtual_input() {
20952095
dispatch_input_task([]() {
20962096
if (platf_input) {
2097+
task_pool.cancel(key_press_repeat_id);
2098+
key_press_repeat_id = nullptr;
20972099
reset_mouse_buttons();
2098-
platf::virtualhid::get_input_context(platf_input).refresh_mouse();
2100+
reset_keyboard_keys();
2101+
auto &context = platf::virtualhid::get_input_context(platf_input);
2102+
context.refresh_keyboard();
2103+
context.refresh_mouse();
20992104
}
21002105
});
21012106
}

src/input.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@ namespace input {
6363
bool probe_gamepads();
6464

6565
/**
66-
* @brief Recreate the shared libvirtualhid mouse after a license-state change.
66+
* @brief Recreate shared libvirtualhid keyboard and mouse devices after a license-state change.
6767
*
68-
* The work is serialized with streamed input so the mouse backend can switch
68+
* The work is serialized with streamed input so both backends can switch
6969
* safely between the Windows HID and SendInput paths.
7070
*/
71-
void refresh_virtual_mouse();
71+
void refresh_virtual_input();
7272

7373
/**
7474
* @brief Allocate and initialize platform input state for a stream.

src/platform/virtualhid_input.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -421,21 +421,27 @@ namespace platf::virtualhid {
421421
return;
422422
}
423423

424-
const auto &capabilities = runtime->capabilities();
425-
if (capabilities.supports_keyboard) {
426-
lvh::CreateKeyboardOptions options;
427-
options.profile = lvh::profiles::keyboard();
428-
options.stable_id = "sunshine-keyboard";
429-
auto created = runtime->create_keyboard(options);
430-
if (created) {
431-
keyboard = std::move(created.keyboard);
432-
} else {
433-
log_failure("create libvirtualhid keyboard"sv, created.status);
434-
}
435-
}
424+
refresh_keyboard();
436425
refresh_mouse();
437426
}
438427

428+
void input_context_t::refresh_keyboard() {
429+
keyboard.reset();
430+
if (!runtime || !runtime->capabilities().supports_keyboard) {
431+
return;
432+
}
433+
434+
lvh::CreateKeyboardOptions options;
435+
options.profile = lvh::profiles::keyboard();
436+
options.stable_id = "sunshine-keyboard";
437+
auto created = runtime->create_keyboard(options);
438+
if (created) {
439+
keyboard = std::move(created.keyboard);
440+
} else {
441+
log_failure("create libvirtualhid keyboard"sv, created.status);
442+
}
443+
}
444+
439445
void input_context_t::refresh_mouse() {
440446
mouse.reset();
441447
if (!runtime || !runtime->capabilities().supports_mouse) {

src/platform/virtualhid_input.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ namespace platf::virtualhid {
3535
*/
3636
explicit input_context_t(lvh::BackendKind backend);
3737

38+
/**
39+
* @brief Recreate the shared keyboard using the runtime's current driver and license state.
40+
*/
41+
void refresh_keyboard();
42+
3843
/**
3944
* @brief Recreate the shared mouse using the runtime's current driver and license state.
4045
*/

src/system_tray.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ namespace system_tray {
151151
constexpr auto LIBVIRTUALHID_RELEASES_URL = "https://github.com/LizardByte/libvirtualhid/releases/latest"sv; ///< Latest Virtual HID Driver release.
152152
static std::array<struct tray_menu, 7> virtualhid_benefits_menu {{
153153
{.text = "Xbox One, Xbox Series, DualSense (DS5), Switch Pro, and Generic", .disabled = 1},
154-
{.text = "Raw Input mouse for relative movement, buttons, and scrolling", .disabled = 1},
154+
{.text = "Raw Input keyboard and mouse for physical-style input", .disabled = 1},
155155
{.text = "Motion, touchpads, LEDs, and adaptive triggers where supported", .disabled = 1},
156156
{.text = "Actively developed and supported by LizardByte", .disabled = 1},
157157
{.text = "-"},
@@ -435,7 +435,7 @@ namespace system_tray {
435435
set_virtualhid_license_menu_item(6, "Manage License", false, tray_virtualhid_license_cb);
436436
} else {
437437
set_virtualhid_license_menu_item(1, std::string {virtualhid_license_state_detail(license.state)}, true);
438-
set_virtualhid_license_menu_item(2, "Driver-backed gamepads and Raw Input mouse are locked", true);
438+
set_virtualhid_license_menu_item(2, "Driver-backed keyboard, mouse, and gamepads are locked", true);
439439
set_virtualhid_license_menu_item(
440440
3,
441441
license.service_available ? "License service: Available" : "License service: Unavailable",
@@ -470,7 +470,7 @@ namespace system_tray {
470470
if (notify_if_unlicensed && !license.licensed()) {
471471
tray.notification_title = "Activate Virtual HID Driver";
472472
tray.notification_text =
473-
"Adds a Raw Input mouse plus Xbox One/Series, DualSense (DS5), Switch Pro, and Generic gamepads. Actively maintained by LizardByte. Click to activate or buy a license; details remain in the tray menu.";
473+
"Adds a Raw Input keyboard and mouse plus Xbox One/Series, DualSense (DS5), Switch Pro, and Generic gamepads. Actively maintained by LizardByte. Click to activate or buy a license; details remain in the tray menu.";
474474
tray.notification_icon = tray.allIconPaths[4];
475475
tray.notification_cb = []() {
476476
launch_ui("/troubleshooting#virtualhid-license");

src_assets/common/assets/web/public/assets/locale/en.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -453,11 +453,11 @@
453453
"startup_errors": "<b>Attention!</b> Sunshine detected these errors during startup. We <b>STRONGLY RECOMMEND</b> fixing them before streaming.",
454454
"version_dirty": "Thank you for helping to make Sunshine a better software!",
455455
"version_latest": "You are running the latest version of Sunshine",
456-
"virtualhid_license_required_desc": "Virtual HID Driver adds a Raw Input mouse plus Xbox One, Xbox Series, DualSense, Nintendo Switch Pro, and Generic gamepads. It is actively maintained by the LizardByte team. Activate or manage the license to unlock driver-backed input.",
456+
"virtualhid_license_required_desc": "Virtual HID Driver adds a Raw Input keyboard and mouse plus Xbox One, Xbox Series, DualSense, Nintendo Switch Pro, and Generic gamepads. It is actively maintained by the LizardByte team. Activate or manage the license to unlock driver-backed input.",
457457
"virtualhid_license_required_title": "Virtual HID Driver License Missing",
458458
"virtualhid_missing_vigembus_installed_desc": "ViGEmBus is installed, but without the libvirtualhid driver Sunshine can only offer limited fallback gamepad support.",
459459
"virtualhid_missing_vigembus_installed_title": "Gamepad Support Is Limited",
460-
"virtualhid_not_installed_desc": "Sunshine requires the libvirtualhid Windows driver for a Raw Input mouse and full virtual gamepad support. Install the libvirtualhid driver package, then restart Sunshine.",
460+
"virtualhid_not_installed_desc": "Sunshine requires the libvirtualhid Windows driver for a Raw Input keyboard and mouse plus full virtual gamepad support. Install the libvirtualhid driver package, then restart Sunshine.",
461461
"virtualhid_not_installed_title": "libvirtualhid Driver Not Installed",
462462
"virtualhid_outdated_desc": "The installed libvirtualhid driver version (v{version}) is not supported. Supported versions: {supported_versions}.",
463463
"virtualhid_outdated_title": "libvirtualhid Driver Outdated",
@@ -576,15 +576,15 @@
576576
"unpair_title": "Unpair Devices",
577577
"vigembus_driver": "ViGEmBus Fallback Driver",
578578
"virtual_gamepad": "Virtual Input",
579-
"virtual_gamepad_desc": "Sunshine uses libvirtualhid for a driver-backed mouse and full virtual gamepad support on Windows. ViGEmBus is detected only as a limited fallback for Xbox 360 and DualShock 4 gamepads.",
579+
"virtual_gamepad_desc": "Sunshine uses libvirtualhid for a driver-backed keyboard and mouse plus full virtual gamepad support on Windows. ViGEmBus is detected only as a limited fallback for Xbox 360 and DualShock 4 gamepads.",
580580
"virtual_gamepad_drivers": "Windows Driver Status",
581581
"virtual_gamepad_drivers_desc": "Installed versions are compared with each project's latest stable GitHub release. Prereleases are ignored.",
582582
"virtualhid_benefit_features": "Supports controller-specific features such as motion, touchpads, LEDs, and adaptive triggers when available.",
583583
"virtualhid_benefit_features_title": "Modern Controller Features",
584584
"virtualhid_benefit_gamepads": "Creates Xbox One, Xbox Series, DualSense, Nintendo Switch Pro, and Generic gamepads in addition to Xbox 360 and DualShock 4.",
585585
"virtualhid_benefit_gamepads_title": "More Gamepad Types",
586-
"virtualhid_benefit_mouse": "Exposes relative movement, buttons, and scrolling as a real HID mouse so games using Raw Input can receive them.",
587-
"virtualhid_benefit_mouse_title": "Raw Input Mouse",
586+
"virtualhid_benefit_mouse": "Exposes normal key transitions and relative mouse input through real HID devices so games using Raw Input can receive them.",
587+
"virtualhid_benefit_mouse_title": "Raw Input Keyboard and Mouse",
588588
"virtualhid_benefit_maintained": "Actively developed and supported by the LizardByte team instead of relying only on the discontinued ViGEmBus project.",
589589
"virtualhid_benefit_maintained_title": "Actively Supported",
590590
"virtualhid_benefits_title": "Virtual HID Driver Benefits",
@@ -597,12 +597,12 @@
597597
"virtualhid_license_buy": "Buy License",
598598
"virtualhid_license_customer": "Customer",
599599
"virtualhid_license_deactivate": "Deactivate This Machine",
600-
"virtualhid_license_desc": "An active license is required before Sunshine can create driver-backed libvirtualhid devices, including gamepads and the Raw Input mouse. Activation is handled by the local libvirtualhid service; Sunshine does not save your license key.",
600+
"virtualhid_license_desc": "An active license is required before Sunshine can create driver-backed libvirtualhid devices, including gamepads and the Raw Input keyboard and mouse. Activation is handled by the local libvirtualhid service; Sunshine does not save your license key.",
601601
"virtualhid_license_key": "License Key",
602602
"virtualhid_license_key_desc": "The key is sent only to the local libvirtualhid service and is cleared from this page after successful activation.",
603603
"virtualhid_license_key_placeholder": "Enter your product key",
604604
"virtualhid_license_machine_activated": "This machine is activated",
605-
"virtualhid_license_machine_activated_desc": "Sunshine can create Virtual HID Driver gamepads and a Raw Input mouse while this license remains valid.",
605+
"virtualhid_license_machine_activated_desc": "Sunshine can create Virtual HID Driver gamepads and a Raw Input keyboard and mouse while this license remains valid.",
606606
"virtualhid_license_manage": "Manage Account and Activations",
607607
"virtualhid_license_not_reported": "Not reported",
608608
"virtualhid_license_plan": "Plan",

tests/unit/platform/test_virtualhid_input.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ TEST_F(VirtualHidDeviceTest, RejectsUnavailableAndInvalidGamepadSlots) {
240240

241241
platf::virtualhid::input_context_t no_runtime {lvh::BackendKind::fake};
242242
no_runtime.runtime.reset();
243+
no_runtime.refresh_keyboard();
244+
no_runtime.refresh_mouse();
245+
EXPECT_EQ(no_runtime.keyboard, nullptr);
246+
EXPECT_EQ(no_runtime.mouse, nullptr);
243247
EXPECT_EQ(platf::virtualhid::alloc_gamepad(no_runtime, valid_id, metadata, nullptr), -1);
244248

245249
EXPECT_EQ(platf::virtualhid::alloc_gamepad(*context(), {-1, 0}, metadata, nullptr), -1);

0 commit comments

Comments
 (0)