From c5519c77aacd504a9377dee8900d3f7f7b5be7f9 Mon Sep 17 00:00:00 2001 From: magiblot Date: Thu, 3 Oct 2024 12:37:09 +0200 Subject: [PATCH] platform: Add support for keyboard modifiers in GPM events --- include/tvision/internal/linuxcon.h | 4 ++- source/platform/gpminput.cpp | 15 ++++++++--- source/platform/linuxcon.cpp | 39 +++++++++++++++++++++-------- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/include/tvision/internal/linuxcon.h b/include/tvision/internal/linuxcon.h index b616907b..cde02272 100644 --- a/include/tvision/internal/linuxcon.h +++ b/include/tvision/internal/linuxcon.h @@ -30,7 +30,9 @@ struct LinuxConsoleInput final : public EventSource bool getEvent(TEvent &ev) noexcept override; bool hasPendingEvents() noexcept override; - static ushort getKeyboardModifiers(StdioCtl &io) noexcept; + ushort getKeyboardModifiers() noexcept; + + static ushort convertLinuxKeyModifiers(ushort linuxShiftState) noexcept; }; class LinuxConsoleStrategy : public ConsoleStrategy diff --git a/source/platform/gpminput.cpp b/source/platform/gpminput.cpp index 1868f4e3..81431576 100644 --- a/source/platform/gpminput.cpp +++ b/source/platform/gpminput.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -20,11 +21,11 @@ GpmInput *GpmInput::create(DisplayBuffer &displayBuf) noexcept Gpm_Connect conn = { .eventMask = GPM_DOWN | GPM_UP | GPM_DRAG | GPM_MOVE, .defaultMask = 0, // Disable cursor drawing by the server. - /* Disable mouse event reporting when keyboard modifiers are active. - * In such case, GPM text selection and copy/paste will be active. */ + // Report keyboard modifiers except Shift, which terminal emulators + // usually reserve for selecting text. Here GPM will do the same. .minMod = 0, - .maxMod = 0 }; - // Because we only instantiate GPM in the Linux console, discard the + .maxMod = (ushort) ~(1 << KG_SHIFT) }; + // Because we only instantiate GPM in the Linux console, unset the // TERM variable during Gpm_Open so that GPM won't assume it is being // ran under xterm (e.g. if TERM=xterm), and 'gpm_fd' won't be -2. char *term = newStr(getenv("TERM")); @@ -82,6 +83,7 @@ bool GpmInput::getEvent(TEvent &ev) noexcept ev.what = evMouse; ev.mouse.where.x = gpmEvent.x; ev.mouse.where.y = gpmEvent.y; + for (const auto &flag : gpmButtonFlags) if (gpmEvent.buttons & flag.gpm) { @@ -91,12 +93,17 @@ bool GpmInput::getEvent(TEvent &ev) noexcept buttonState &= ~flag.mb; } ev.mouse.buttons = buttonState; + if (gpmEvent.wdy) ev.mouse.wheel = gpmEvent.wdy > 0 ? mwUp : mwDown; else if (gpmEvent.wdx) ev.mouse.wheel = gpmEvent.wdx > 0 ? mwRight : mwLeft; else ev.mouse.wheel = 0; + + ev.mouse.controlKeyState = + LinuxConsoleInput::convertLinuxKeyModifiers(gpmEvent.modifiers); + return true; } return false; diff --git a/source/platform/linuxcon.cpp b/source/platform/linuxcon.cpp index 36a8e706..a1314695 100644 --- a/source/platform/linuxcon.cpp +++ b/source/platform/linuxcon.cpp @@ -62,7 +62,7 @@ bool LinuxConsoleInput::getEvent(TEvent &ev) noexcept if (input.getEvent(ev)) { auto &keyCode = ev.keyDown.keyCode; - ev.keyDown.controlKeyState = getKeyboardModifiers(io); + ev.keyDown.controlKeyState = getKeyboardModifiers(); // Prevent Ctrl+H/Ctrl+I/Ctrl+J/Ctrl+M from being interpreted as // Ctrl+Back/Ctrl+Tab/Ctrl+Enter. if (keyCode == kbBack || keyCode == kbTab || keyCode == kbEnter) @@ -83,20 +83,37 @@ bool LinuxConsoleInput::hasPendingEvents() noexcept return input.hasPendingEvents(); } -ushort LinuxConsoleInput::getKeyboardModifiers(StdioCtl &io) noexcept +ushort LinuxConsoleInput::getKeyboardModifiers() noexcept { char res = 6; - ulong actualModifiers = 0; if (ioctl(io.in(), TIOCLINUX, &res) != -1) + return convertLinuxKeyModifiers(res); + return 0; +} + +ushort LinuxConsoleInput::convertLinuxKeyModifiers(ushort linuxShiftState) noexcept +{ + constexpr struct { - if (res & (1 << KG_SHIFT)) - actualModifiers |= kbShift; - if (res & (1 << KG_CTRL)) - actualModifiers |= kbLeftCtrl; - if (res & (1 << KG_ALT)) - actualModifiers |= kbLeftAlt; - } - return actualModifiers; + uchar kb; + uchar tv; + } linuxModifierFlags[] = + { + {1 << KG_SHIFT, kbShift}, + {1 << KG_CTRLL, kbLeftCtrl}, + {1 << KG_CTRLR, kbRightCtrl}, + {1 << KG_ALT, kbLeftAlt}, + {1 << KG_ALTGR, kbRightAlt}, + }; + + ushort modifiers = 0; + for (const auto &flags : linuxModifierFlags) + if (linuxShiftState & flags.kb) + modifiers |= flags.tv; + // It may be that KG_CTRL was detected, but not KG_CTRLL or KG_CTRLR. + if ((linuxShiftState & (1 << KG_CTRL)) && !(modifiers & kbCtrlShift)) + modifiers |= kbLeftCtrl; + return modifiers; } } // namespace tvision