Skip to content

Commit

Permalink
platform: Add support for keyboard modifiers in GPM events
Browse files Browse the repository at this point in the history
  • Loading branch information
magiblot committed Oct 3, 2024
1 parent 6cb4c85 commit c5519c7
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 16 deletions.
4 changes: 3 additions & 1 deletion include/tvision/internal/linuxcon.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 11 additions & 4 deletions source/platform/gpminput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <internal/gpminput.h>
#include <internal/dispbuff.h>
#include <internal/linuxcon.h>
#include <linux/keyboard.h>
#include <stdlib.h>
#include <gpm.h>

Expand All @@ -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"));
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
Expand Down
39 changes: 28 additions & 11 deletions source/platform/linuxcon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down

0 comments on commit c5519c7

Please sign in to comment.