feat: add keyboard layout support
This commit is contained in:
@@ -12,4 +12,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MONTAUK_BUILD_NUMBER 109
|
||||
#define MONTAUK_BUILD_NUMBER 116
|
||||
|
||||
@@ -54,6 +54,9 @@ namespace montauk::abi {
|
||||
outEvent->shift = k.Shift;
|
||||
outEvent->ctrl = k.Ctrl;
|
||||
outEvent->alt = k.Alt;
|
||||
outEvent->capslock = k.CapsLock;
|
||||
outEvent->altgr = k.AltGr;
|
||||
outEvent->extended = k.Extended;
|
||||
}
|
||||
|
||||
static char Sys_GetChar() {
|
||||
|
||||
@@ -458,6 +458,13 @@ namespace montauk::abi {
|
||||
bool shift;
|
||||
bool ctrl;
|
||||
bool alt;
|
||||
bool capslock;
|
||||
// Right Alt held, reported separately from alt so keyboard layouts can
|
||||
// use it as AltGr without swallowing left-Alt shortcuts.
|
||||
bool altgr;
|
||||
// Key came from an E0-prefixed scancode (keypad "/" and Enter share a
|
||||
// scancode with the main-block keys). Layout translation must skip it.
|
||||
bool extended;
|
||||
};
|
||||
|
||||
struct MouseState {
|
||||
|
||||
@@ -179,7 +179,9 @@ namespace Drivers::PS2::Keyboard {
|
||||
.Shift = g_Modifiers.LeftShift || g_Modifiers.RightShift,
|
||||
.Ctrl = g_Modifiers.LeftCtrl || g_Modifiers.RightCtrl,
|
||||
.Alt = g_Modifiers.LeftAlt || g_Modifiers.RightAlt,
|
||||
.CapsLock = g_Modifiers.CapsLock
|
||||
.CapsLock = g_Modifiers.CapsLock,
|
||||
.AltGr = g_Modifiers.RightAlt,
|
||||
.Extended = true
|
||||
};
|
||||
PushAndNotify(event);
|
||||
|
||||
@@ -237,7 +239,9 @@ namespace Drivers::PS2::Keyboard {
|
||||
.Shift = g_Modifiers.LeftShift || g_Modifiers.RightShift,
|
||||
.Ctrl = g_Modifiers.LeftCtrl || g_Modifiers.RightCtrl,
|
||||
.Alt = g_Modifiers.LeftAlt || g_Modifiers.RightAlt,
|
||||
.CapsLock = g_Modifiers.CapsLock
|
||||
.CapsLock = g_Modifiers.CapsLock,
|
||||
.AltGr = g_Modifiers.RightAlt,
|
||||
.Extended = false
|
||||
};
|
||||
PushAndNotify(event);
|
||||
return;
|
||||
@@ -261,7 +265,9 @@ namespace Drivers::PS2::Keyboard {
|
||||
.Shift = g_Modifiers.LeftShift || g_Modifiers.RightShift,
|
||||
.Ctrl = g_Modifiers.LeftCtrl || g_Modifiers.RightCtrl,
|
||||
.Alt = g_Modifiers.LeftAlt || g_Modifiers.RightAlt,
|
||||
.CapsLock = g_Modifiers.CapsLock
|
||||
.CapsLock = g_Modifiers.CapsLock,
|
||||
.AltGr = g_Modifiers.RightAlt,
|
||||
.Extended = false
|
||||
};
|
||||
|
||||
PushAndNotify(event);
|
||||
@@ -298,7 +304,18 @@ namespace Drivers::PS2::Keyboard {
|
||||
}
|
||||
|
||||
void InjectKeyEvent(const KeyEvent& event) {
|
||||
PushAndNotify(event);
|
||||
// Caps Lock is owned here rather than by each injecting driver: USB HID
|
||||
// reports the key as an ordinary usage and carries no lock state, so
|
||||
// without this the lock would never toggle on a USB keyboard.
|
||||
KeyEvent stamped = event;
|
||||
if (stamped.Scancode == ScCapsLock && stamped.Pressed)
|
||||
g_Modifiers.CapsLock = !g_Modifiers.CapsLock;
|
||||
stamped.CapsLock = g_Modifiers.CapsLock;
|
||||
PushAndNotify(stamped);
|
||||
}
|
||||
|
||||
bool GetCapsLock() {
|
||||
return g_Modifiers.CapsLock;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -18,6 +18,13 @@ namespace Drivers::PS2::Keyboard {
|
||||
bool Ctrl;
|
||||
bool Alt;
|
||||
bool CapsLock;
|
||||
// Right Alt held. Reported separately from Alt so keyboard layouts can
|
||||
// use it as AltGr without swallowing left-Alt shortcuts.
|
||||
bool AltGr;
|
||||
// Key came from an E0-prefixed (extended) scancode. The prefix is not
|
||||
// part of Scancode, so without this flag keypad "/" is indistinguishable
|
||||
// from the main "/" key and layout translation would rewrite it.
|
||||
bool Extended;
|
||||
};
|
||||
|
||||
// Modifier key state
|
||||
@@ -52,4 +59,8 @@ namespace Drivers::PS2::Keyboard {
|
||||
// Inject a key event from an external source (e.g., USB HID keyboard)
|
||||
void InjectKeyEvent(const KeyEvent& event);
|
||||
|
||||
// Current Caps Lock state. Injecting drivers (USB HID) need this to
|
||||
// compute ASCII, since the lock is toggled centrally here.
|
||||
bool GetCapsLock();
|
||||
|
||||
};
|
||||
|
||||
@@ -200,20 +200,28 @@ namespace Drivers::USB::HidKeyboard {
|
||||
return (hidUsage >= 0x39 && hidUsage <= 0x53);
|
||||
}
|
||||
|
||||
// Keys that arrive E0-prefixed on a PS/2 keyboard. They share a scancode
|
||||
// with a main-block key (keypad "/" with "/", keypad Enter with Enter), so
|
||||
// they must be flagged or a keyboard layout would rewrite them.
|
||||
static bool IsExtendedKey(uint8_t hidUsage) {
|
||||
return hidUsage == 0x54 || hidUsage == 0x58; // KP /, KP Enter
|
||||
}
|
||||
|
||||
// Build and inject a KeyEvent into the PS/2 keyboard buffer
|
||||
static void InjectKey(uint8_t scancode, bool pressed, uint8_t modifiers,
|
||||
bool nonChar = false) {
|
||||
bool nonChar = false, bool extended = false) {
|
||||
bool shift = (modifiers & (MOD_LEFT_SHIFT | MOD_RIGHT_SHIFT)) != 0;
|
||||
bool ctrl = (modifiers & (MOD_LEFT_CTRL | MOD_RIGHT_CTRL)) != 0;
|
||||
bool alt = (modifiers & (MOD_LEFT_ALT | MOD_RIGHT_ALT)) != 0;
|
||||
bool caps = Drivers::PS2::Keyboard::GetCapsLock();
|
||||
|
||||
char ascii = 0;
|
||||
if (!nonChar && scancode < 128 && pressed) {
|
||||
if (shift) {
|
||||
ascii = g_ScancodeToAsciiShifted[scancode];
|
||||
} else {
|
||||
ascii = g_ScancodeToAscii[scancode];
|
||||
}
|
||||
// Caps Lock inverts shift for letters only, matching the PS/2 path.
|
||||
char base = g_ScancodeToAscii[scancode];
|
||||
bool upper = shift;
|
||||
if (caps && base >= 'a' && base <= 'z') upper = !shift;
|
||||
ascii = upper ? g_ScancodeToAsciiShifted[scancode] : base;
|
||||
}
|
||||
|
||||
Drivers::PS2::Keyboard::KeyEvent event = {
|
||||
@@ -223,7 +231,9 @@ namespace Drivers::USB::HidKeyboard {
|
||||
.Shift = shift,
|
||||
.Ctrl = ctrl,
|
||||
.Alt = alt,
|
||||
.CapsLock = false
|
||||
.CapsLock = caps, // re-stamped by InjectKeyEvent, which owns the lock
|
||||
.AltGr = (modifiers & MOD_RIGHT_ALT) != 0,
|
||||
.Extended = extended
|
||||
};
|
||||
|
||||
Drivers::PS2::Keyboard::InjectKeyEvent(event);
|
||||
@@ -238,7 +248,9 @@ namespace Drivers::USB::HidKeyboard {
|
||||
.Shift = (modifiers & (MOD_LEFT_SHIFT | MOD_RIGHT_SHIFT)) != 0,
|
||||
.Ctrl = (modifiers & (MOD_LEFT_CTRL | MOD_RIGHT_CTRL)) != 0,
|
||||
.Alt = (modifiers & (MOD_LEFT_ALT | MOD_RIGHT_ALT)) != 0,
|
||||
.CapsLock = false
|
||||
.CapsLock = Drivers::PS2::Keyboard::GetCapsLock(),
|
||||
.AltGr = (modifiers & MOD_RIGHT_ALT) != 0,
|
||||
.Extended = false
|
||||
};
|
||||
|
||||
Drivers::PS2::Keyboard::InjectKeyEvent(event);
|
||||
@@ -271,7 +283,7 @@ namespace Drivers::USB::HidKeyboard {
|
||||
|
||||
uint8_t scancode = g_HidToScancode[key];
|
||||
if (scancode != 0) {
|
||||
InjectKey(scancode, false, modifiers, IsNonCharKey(key));
|
||||
InjectKey(scancode, false, modifiers, IsNonCharKey(key), IsExtendedKey(key));
|
||||
}
|
||||
g_PrevKeys[i] = 0;
|
||||
}
|
||||
@@ -354,7 +366,7 @@ namespace Drivers::USB::HidKeyboard {
|
||||
if (!KeyInArray(key, g_PrevKeys)) {
|
||||
uint8_t scancode = g_HidToScancode[key];
|
||||
if (scancode != 0) {
|
||||
InjectKey(scancode, true, modifiers, IsNonCharKey(key));
|
||||
InjectKey(scancode, true, modifiers, IsNonCharKey(key), IsExtendedKey(key));
|
||||
g_RepeatKey = key;
|
||||
g_RepeatStartMs = now;
|
||||
g_LastRepeatMs = 0;
|
||||
@@ -373,7 +385,7 @@ namespace Drivers::USB::HidKeyboard {
|
||||
if (!KeyInArray(key, keys)) {
|
||||
uint8_t scancode = g_HidToScancode[key];
|
||||
if (scancode != 0) {
|
||||
InjectKey(scancode, false, modifiers, IsNonCharKey(key));
|
||||
InjectKey(scancode, false, modifiers, IsNonCharKey(key), IsExtendedKey(key));
|
||||
}
|
||||
if (key == g_RepeatKey) {
|
||||
g_RepeatKey = 0;
|
||||
@@ -405,7 +417,7 @@ namespace Drivers::USB::HidKeyboard {
|
||||
(now - g_LastRepeatMs) >= TYPEMATIC_PERIOD_MS) {
|
||||
uint8_t scancode = g_HidToScancode[g_RepeatKey];
|
||||
if (scancode != 0) {
|
||||
InjectKey(scancode, true, g_PrevModifiers, IsNonCharKey(g_RepeatKey));
|
||||
InjectKey(scancode, true, g_PrevModifiers, IsNonCharKey(g_RepeatKey), IsExtendedKey(g_RepeatKey));
|
||||
}
|
||||
g_LastRepeatMs = now;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user