From 331844c97963f70392c50cc003170d08f11cb124 Mon Sep 17 00:00:00 2001 From: Christian Helmuth Date: Thu, 10 Jun 2021 14:26:25 +0200 Subject: [PATCH] vbox6: support capslock="rom" mode In ROM mode the global CapsLock state is controlled by the capslock ROM by virtual KEY_CAPSLOCK events. Guests are easily confused by spurious KEY_CAPSLOCK input events in caps="rom" mode. These spurious events may reach the VMM if KEY_CAPSLOCK is not pressed as first key in a combination and, therefore, is not filtered as global key. We filter KEY_CAPSLOCK in ROM mode in the VMM explicitly, but let it pass in non-ROM mode. Per default RAW mode is used and CapsLock key events are sent unfiltered to the guest. --- repos/ports/recipes/pkg/vbox6/runtime | 2 +- repos/ports/src/virtualbox6/README | 32 ++++++++ repos/ports/src/virtualbox6/main.cc | 102 ++++++++++++++++++++++---- 3 files changed, 122 insertions(+), 14 deletions(-) create mode 100644 repos/ports/src/virtualbox6/README diff --git a/repos/ports/recipes/pkg/vbox6/runtime b/repos/ports/recipes/pkg/vbox6/runtime index 768727b24c..e0f75382a6 100755 --- a/repos/ports/recipes/pkg/vbox6/runtime +++ b/repos/ports/recipes/pkg/vbox6/runtime @@ -44,7 +44,7 @@ - + diff --git a/repos/ports/src/virtualbox6/README b/repos/ports/src/virtualbox6/README new file mode 100644 index 0000000000..5232f4cf89 --- /dev/null +++ b/repos/ports/src/virtualbox6/README @@ -0,0 +1,32 @@ +VirtualBox configuration options +================================ + +The configuration requires an attribute named vbox_file with the name of the +vbox configuration to be used (.vbox). + + + +XHCI controller +~~~~~~~~~~~~~~~ + +The virtual XHCI controller can be enabled with the following +configuration option: + + + +CapsLock +~~~~~~~~ + +Per default CapsLock key events are send unmodified to guest +operating systems. As guest and host state may diverge, the event +filter optionally reports the capslock state as ROM, which can be +monitored by VirtualBox if configured like follows. + + + +VirtualBox requests a "capslock" ROM, which is interpreted as XML. The +top-level node attribute 'enabled' is expected boolean and represents +the CapsLock state. If ROM and VM-internal CapsLock state differ, the +VMM sends aritifical CapsLock key events to the VM. In this mode, +incoming KEY_CAPSLOCK input events a dropped and not sent to the guest +to prevent the state divergence. diff --git a/repos/ports/src/virtualbox6/main.cc b/repos/ports/src/virtualbox6/main.cc index e6c1b548d9..e71dde1b82 100644 --- a/repos/ports/src/virtualbox6/main.cc +++ b/repos/ports/src/virtualbox6/main.cc @@ -207,19 +207,63 @@ struct Main : Event_handler } } _idisplay { _iconsole }; + Signal_handler
_capslock_handler { _env.ep(), *this, &Main::_handle_capslock }; + + void _handle_capslock(); + + struct Capslock + { + enum class Mode { RAW, ROM } const mode; + + bool _host { false }; + bool _guest { false }; + + Constructible _rom; + + Capslock(Env &env, Xml_node config, Signal_context_capability sigh) + : + mode(config.attribute_value("capslock", String<4>()) == "rom" + ? Mode::ROM : Mode::RAW) + { + if (mode == Mode::ROM) { + _rom.construct(env, "capslock"); + _rom->sigh(sigh); + } + } + + void update_guest(bool enabled) { _guest = enabled; } + + bool update_from_rom() + { + _rom->update(); + + bool const rom = _rom->xml().attribute_value("enabled", _guest); + + bool trigger = false; + + /* + * If guest didn't respond with led change last time, we have to + * trigger CapsLock change - mainly assuming that guest don't use the + * led to externalize its internal state. + */ + if (rom != _host && _host != _guest) + trigger = true; + + if (rom != _guest) + trigger = true; + + /* remember last seen host capslock state */ + _host = rom; + + return trigger; + } + } _capslock { _env, _config.xml(), _capslock_handler }; + Registry> _gui_connections { }; Signal_handler
_input_handler { _env.ep(), *this, &Main::_handle_input }; - void _handle_input_event(Input::Event const &); - - void _handle_input() - { - Libc::with_libc([&] { - _gui_connections.for_each([&] (Gui::Connection &gui) { - gui.input()->for_each_event([&] (Input::Event const &ev) { - _handle_input_event(ev); }); }); }); - } + void _handle_input(); Input_adapter _input_adapter { _iconsole }; @@ -296,9 +340,34 @@ struct Main : Event_handler }; -void Main::_handle_input_event(Input::Event const &ev) +void Main::_handle_capslock() { - _input_adapter.handle_input_event(ev); + if (_capslock.update_from_rom()) { + Libc::with_libc([&] { + _input_adapter.handle_input_event(Input::Event { Input::Press { Input::KEY_CAPSLOCK } }); + _input_adapter.handle_input_event(Input::Event { Input::Release { Input::KEY_CAPSLOCK } }); + }); + } +} + + +void Main::_handle_input() +{ + auto handle_one_event = [&] (Input::Event const &ev) { + /* don't confuse guests and drop CapsLock events in ROM mode */ + if (_capslock.mode == Capslock::Mode::ROM) { + if (ev.key_press(Input::KEY_CAPSLOCK) + || ev.key_release(Input::KEY_CAPSLOCK)) + return; + } + + _input_adapter.handle_input_event(ev); + }; + + Libc::with_libc([&] { + _gui_connections.for_each([&] (Gui::Connection &gui) { + gui.input()->for_each_event([&] (Input::Event const &ev) { + handle_one_event(ev); }); }); }); } @@ -314,7 +383,14 @@ void Main::handle_vbox_event(VBoxEventType_T ev_type, IEvent &ev) } break; case VBoxEventType_OnMousePointerShapeChanged: break; - case VBoxEventType_OnKeyboardLedsChanged: break; + + case VBoxEventType_OnKeyboardLedsChanged: + { + ComPtr led_ev = &ev; + BOOL capslock; + led_ev->COMGETTER(CapsLock)(&capslock); + _capslock.update_guest(!!capslock); + } break; default: /* ignore other events */ break; } @@ -335,7 +411,7 @@ void Libc::Component::construct(Libc::Env &env) char **envp = nullptr; populate_args_and_env(env, argc, argv, envp); - + environ = envp; Pthread::init(env);