summaryrefslogtreecommitdiffhomepage
path: root/packages/kernel/src/input.cpp
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-13 16:05:28 +0900
committerAdam Malczewski <[email protected]>2026-06-13 16:05:28 +0900
commit9ee2d3ceee93ff0d0afdb47f594ea4fee95455fc (patch)
tree4a1b73d8f140c88775d0487434ba23e807fc441f /packages/kernel/src/input.cpp
parent11812b0374d5de395e2c17532c6bf89a903ee043 (diff)
downloadunbox-9ee2d3ceee93ff0d0afdb47f594ea4fee95455fc.tar.gz
unbox-9ee2d3ceee93ff0d0afdb47f594ea4fee95455fc.zip
Kernel: Ctrl+Alt+F1..F12 VT switching (session escape hatch)
Intercept the XF86Switch_VT_1..12 keysyms before the keybinding filter and call wlr_session_change_vt, so the user can always switch consoles while unbox runs. Clean no-op without a session (headless/nested). Pure vt_for_keysym helper + doctest; wlroots reached via the wlr.hpp wrapper. Real-seat verified on the CF-AX3.
Diffstat (limited to 'packages/kernel/src/input.cpp')
-rw-r--r--packages/kernel/src/input.cpp19
1 files changed, 19 insertions, 0 deletions
diff --git a/packages/kernel/src/input.cpp b/packages/kernel/src/input.cpp
index 336947e..6056c53 100644
--- a/packages/kernel/src/input.cpp
+++ b/packages/kernel/src/input.cpp
@@ -1,5 +1,7 @@
#include "server_impl.hpp"
+#include "vt_core.hpp"
+
#include <xkbcommon/xkbcommon.h>
namespace unbox::kernel {
@@ -75,6 +77,23 @@ void Server::Impl::new_keyboard(wlr_input_device* device) {
const std::uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->keyboard);
const bool pressed = event->state == WL_KEYBOARD_KEY_STATE_PRESSED;
+ // SESSION ESCAPE HATCH: Ctrl+Alt+Fn (XF86Switch_VT_1..12) switches the
+ // Linux VT. Handled HERE, kernel-hardwired, BEFORE the key_filter, so no
+ // extension can intercept, consume, or block the only escape from the
+ // real DRM seat (user decision: not config-driven, not rebindable). On
+ // PRESS we change the VT; we CONSUME both press and release (the matching
+ // release carries the same keysym) so the filter never runs and the key
+ // never reaches the focused client. No session (headless/nested =>
+ // session is NULL) is a clean no-op — never crash.
+ for (int i = 0; i < nsyms; ++i) {
+ if (const std::optional<unsigned> vt = vt_for_keysym(syms[i])) {
+ if (pressed && session != nullptr) {
+ wlr_session_change_vt(session, *vt);
+ }
+ return; // consume: no filter, no client forward (press or release)
+ }
+ }
+
// Thread each resolved keysym through the key_filter; a filter link may
// CONSUME the key (set handled=true) — that is how extensions implement
// compositor shortcuts. If any resolution is consumed, suppress the