kernel: Add much-needed support for extended keyboard scancodes
This commit is contained in:
parent
f05fea441c
commit
fc37634a18
@ -117,6 +117,30 @@ namespace moon
|
|||||||
K_CH46, // .
|
K_CH46, // .
|
||||||
K_CH47, // /
|
K_CH47, // /
|
||||||
K_CH48, // Space
|
K_CH48, // Space
|
||||||
|
// Multimedia keys
|
||||||
|
K_MediaPrev,
|
||||||
|
K_MediaNext,
|
||||||
|
K_MediaMute,
|
||||||
|
K_MediaCalc,
|
||||||
|
K_MediaPlay,
|
||||||
|
K_MediaStop,
|
||||||
|
K_MediaVolDown,
|
||||||
|
K_MediaVolUp,
|
||||||
|
// WWW keys
|
||||||
|
K_WWWHome,
|
||||||
|
K_WWWSearch,
|
||||||
|
K_WWWFavorites,
|
||||||
|
K_WWWRefresh,
|
||||||
|
K_WWWStop,
|
||||||
|
K_WWWForward,
|
||||||
|
K_WWWBack,
|
||||||
|
K_WWWMyComputer,
|
||||||
|
K_WWWEmail,
|
||||||
|
K_WWWSelect,
|
||||||
|
// Power keys
|
||||||
|
K_ACPIPower,
|
||||||
|
K_ACPISleep,
|
||||||
|
K_ACPIWake,
|
||||||
// Unknown key
|
// Unknown key
|
||||||
K_Unknown,
|
K_Unknown,
|
||||||
};
|
};
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "api/Keyboard.h"
|
#include "api/Keyboard.h"
|
||||||
#include <luna/Option.h>
|
#include <luna/Option.h>
|
||||||
|
#include <luna/Vector.h>
|
||||||
|
|
||||||
namespace Keyboard
|
namespace Keyboard
|
||||||
{
|
{
|
||||||
struct TTYKeyboardState
|
|
||||||
{
|
|
||||||
bool ignore_next { false };
|
|
||||||
bool left_shift { false };
|
|
||||||
bool right_shift { false };
|
|
||||||
bool left_control { false };
|
|
||||||
bool capslock { false };
|
|
||||||
};
|
|
||||||
|
|
||||||
struct KeyboardState
|
struct KeyboardState
|
||||||
{
|
{
|
||||||
bool ignore_next { false };
|
Vector<u8> key_state;
|
||||||
|
bool parsing_ext { false };
|
||||||
|
bool parsing_pause { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
Option<char> decode_scancode_tty(u8 scancode, TTYKeyboardState& state);
|
|
||||||
|
|
||||||
Option<moon::KeyboardPacket> decode_scancode(u8 scancode, KeyboardState& state);
|
Option<moon::KeyboardPacket> decode_scancode(u8 scancode, KeyboardState& state);
|
||||||
}
|
}
|
||||||
|
@ -13,104 +13,9 @@ static bool is_key_released(u8& scancode)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u8 EXTENDED_KEY_CODE = 0xe0;
|
constexpr static u8 print_screen_pressed[] = { 0xe0, 0x2a, 0xe0, 0x37 };
|
||||||
constexpr u8 LEFT_SHIFT = 0x2a;
|
constexpr static u8 print_screen_released[] = { 0xe0, 0xb7, 0xe0, 0xaa };
|
||||||
constexpr u8 RIGHT_SHIFT = 0x36;
|
constexpr static u8 pause[] = { 0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5 };
|
||||||
constexpr u8 CAPS_LOCK = 0x3a;
|
|
||||||
|
|
||||||
constexpr u8 LEFT_CONTROL = 0x1D;
|
|
||||||
constexpr u8 LEFT_ALT = 0x38;
|
|
||||||
constexpr u8 F11 = 0x57;
|
|
||||||
constexpr u8 F12 = 0x58;
|
|
||||||
|
|
||||||
static bool should_ignore_key(u8 scancode)
|
|
||||||
{
|
|
||||||
return (scancode > 0x3A && scancode < 0x47) || scancode == F11 || scancode == F12;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr char key_table[] = {
|
|
||||||
'\0',
|
|
||||||
'\1', // escape
|
|
||||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
|
||||||
'\t', // tab
|
|
||||||
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
|
||||||
'\0', // left ctrl
|
|
||||||
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
|
|
||||||
'\0', // left shift
|
|
||||||
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
|
|
||||||
'\0', // right shift
|
|
||||||
'*', // keypad *
|
|
||||||
'\0', // left alt
|
|
||||||
' ',
|
|
||||||
'\0', // caps lock
|
|
||||||
'\0', // f1
|
|
||||||
'\0', // f2
|
|
||||||
'\0', // f3
|
|
||||||
'\0', // f4
|
|
||||||
'\0', // f5
|
|
||||||
'\0', // f6
|
|
||||||
'\0', // f7
|
|
||||||
'\0', // f8
|
|
||||||
'\0', // f9
|
|
||||||
'\0', // f10
|
|
||||||
'\0', // num lock
|
|
||||||
'\0', // scroll lock
|
|
||||||
'7', // keypad 7
|
|
||||||
'8', // keypad 8
|
|
||||||
'9', // keypad 9
|
|
||||||
'-', // keypad -
|
|
||||||
'4', // keypad 4
|
|
||||||
'5', // keypad 5
|
|
||||||
'6', // keypad 6
|
|
||||||
'+', // keypad +
|
|
||||||
'1', // keypad 1
|
|
||||||
'2', // keypad 2
|
|
||||||
'3', // keypad 3
|
|
||||||
'0', // keypad 0
|
|
||||||
'.', // keypad .
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr char shifted_key_table[] = {
|
|
||||||
'\0',
|
|
||||||
'\1', // escape
|
|
||||||
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
|
|
||||||
'\t', // tab
|
|
||||||
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
|
|
||||||
'\0', // left ctrl
|
|
||||||
'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',
|
|
||||||
'\0', // left shift
|
|
||||||
'|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',
|
|
||||||
'\0', // right shift
|
|
||||||
'*', // keypad *
|
|
||||||
'\0', // left alt
|
|
||||||
' ',
|
|
||||||
'\0', // caps lock
|
|
||||||
'\0', // f1
|
|
||||||
'\0', // f2
|
|
||||||
'\0', // f3
|
|
||||||
'\0', // f4
|
|
||||||
'\0', // f5
|
|
||||||
'\0', // f6
|
|
||||||
'\0', // f7
|
|
||||||
'\0', // f8
|
|
||||||
'\0', // f9
|
|
||||||
'\0', // f10
|
|
||||||
'\0', // num lock
|
|
||||||
'\0', // scroll lock
|
|
||||||
'7', // keypad 7
|
|
||||||
'8', // keypad 8
|
|
||||||
'9', // keypad 9
|
|
||||||
'-', // keypad -
|
|
||||||
'4', // keypad 4
|
|
||||||
'5', // keypad 5
|
|
||||||
'6', // keypad 6
|
|
||||||
'+', // keypad +
|
|
||||||
'1', // keypad 1
|
|
||||||
'2', // keypad 2
|
|
||||||
'3', // keypad 3
|
|
||||||
'0', // keypad 0
|
|
||||||
'.', // keypad .
|
|
||||||
};
|
|
||||||
|
|
||||||
using namespace moon;
|
using namespace moon;
|
||||||
|
|
||||||
@ -176,95 +81,113 @@ constexpr KeyCode keycode_table[] = {
|
|||||||
K_F11, K_F12,
|
K_F11, K_F12,
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool is_shifted(const Keyboard::TTYKeyboardState& state)
|
constexpr KeyCode extended_keycode_table[] = {
|
||||||
{
|
K_MediaPrev, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown,
|
||||||
if (state.capslock) return !(state.left_shift || state.right_shift);
|
K_Unknown, K_Unknown, K_MediaNext, K_Unknown, K_Unknown, K_KeypadEnter, K_RightControl,
|
||||||
return state.left_shift || state.right_shift;
|
K_Unknown, K_Unknown, K_MediaMute, K_MediaCalc, K_MediaPlay, K_Unknown, K_MediaStop,
|
||||||
}
|
K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown,
|
||||||
|
K_Unknown, K_Unknown, K_MediaVolDown, K_Unknown, K_MediaVolUp, K_Unknown, K_WWWHome,
|
||||||
|
K_Unknown, K_Unknown, K_KeypadDiv, K_Unknown, K_Unknown, K_RightAlt, K_Unknown,
|
||||||
|
K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown,
|
||||||
|
K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Home,
|
||||||
|
K_UpArrow, K_PageUp, K_Unknown, K_LeftArrow, K_Unknown, K_RightArrow, K_Unknown,
|
||||||
|
K_End, K_DownArrow, K_PageDown, K_Insert, K_Delete, K_Unknown, K_Unknown,
|
||||||
|
K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Unknown, K_Super, K_Super,
|
||||||
|
K_Menu, K_ACPIPower, K_ACPISleep, K_Unknown, K_Unknown, K_Unknown, K_ACPIWake,
|
||||||
|
K_Unknown, K_WWWSearch, K_WWWFavorites, K_WWWRefresh, K_WWWStop, K_WWWForward, K_WWWBack,
|
||||||
|
K_WWWMyComputer, K_WWWEmail, K_WWWSelect
|
||||||
|
};
|
||||||
|
|
||||||
namespace Keyboard
|
namespace Keyboard
|
||||||
{
|
{
|
||||||
Option<char> decode_scancode_tty(u8 scancode, TTYKeyboardState& state)
|
|
||||||
{
|
|
||||||
if (state.ignore_next)
|
|
||||||
{
|
|
||||||
state.ignore_next = false;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Support extended scancodes.
|
|
||||||
if (scancode == EXTENDED_KEY_CODE)
|
|
||||||
{
|
|
||||||
state.ignore_next = true;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool released = is_key_released(scancode);
|
|
||||||
|
|
||||||
if (scancode == LEFT_SHIFT)
|
|
||||||
{
|
|
||||||
state.left_shift = !released;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scancode == RIGHT_SHIFT)
|
|
||||||
{
|
|
||||||
state.right_shift = !released;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scancode == CAPS_LOCK)
|
|
||||||
{
|
|
||||||
if (!released) state.capslock = !state.capslock;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scancode == LEFT_CONTROL)
|
|
||||||
{
|
|
||||||
if (released) state.left_control = false;
|
|
||||||
else
|
|
||||||
state.left_control = true;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (should_ignore_key(scancode)) return {};
|
|
||||||
|
|
||||||
if (released) return {};
|
|
||||||
|
|
||||||
if (state.left_control)
|
|
||||||
{
|
|
||||||
char key;
|
|
||||||
if (is_shifted(state)) key = shifted_key_table[scancode];
|
|
||||||
else
|
|
||||||
key = key_table[scancode];
|
|
||||||
if (_islower(key)) key = (char)_toupper(key);
|
|
||||||
if (_isupper(key)) return key - 0x40;
|
|
||||||
if (key == '@') return key - 0x40;
|
|
||||||
if (key > 'Z' && key < '`') return key - 0x40;
|
|
||||||
if (key == '?') return 0x7f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_shifted(state)) return shifted_key_table[scancode];
|
|
||||||
return key_table[scancode];
|
|
||||||
}
|
|
||||||
|
|
||||||
Option<KeyboardPacket> decode_scancode(u8 scancode, KeyboardState& state)
|
Option<KeyboardPacket> decode_scancode(u8 scancode, KeyboardState& state)
|
||||||
{
|
{
|
||||||
if (state.ignore_next)
|
if (state.parsing_pause)
|
||||||
{
|
{
|
||||||
state.ignore_next = false;
|
if (state.key_state.size() < 6) state.key_state.try_append(scancode).release_value();
|
||||||
|
|
||||||
|
if (state.key_state.size() == 6)
|
||||||
|
{
|
||||||
|
state.parsing_pause = state.parsing_ext = false;
|
||||||
|
if (!memcmp(state.key_state.data(), pause, 6))
|
||||||
|
{
|
||||||
|
state.key_state.clear_data();
|
||||||
|
return KeyboardPacket { K_Pause, false };
|
||||||
|
}
|
||||||
|
|
||||||
|
state.key_state.clear_data();
|
||||||
|
return KeyboardPacket { K_Unknown, false };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.parsing_ext)
|
||||||
|
{
|
||||||
|
if (scancode == 0xe0 && state.key_state.size() == 2)
|
||||||
|
{
|
||||||
|
state.key_state.try_append(scancode).release_value();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.key_state.size() == 3)
|
||||||
|
{
|
||||||
|
state.key_state.try_append(scancode).release_value();
|
||||||
|
if (!memcmp(state.key_state.data(), print_screen_pressed, 4))
|
||||||
|
{
|
||||||
|
state.parsing_ext = false;
|
||||||
|
state.key_state.clear_data();
|
||||||
|
return KeyboardPacket { K_PrtScr, false };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(state.key_state.data(), print_screen_released, 4))
|
||||||
|
{
|
||||||
|
state.parsing_ext = false;
|
||||||
|
state.key_state.clear_data();
|
||||||
|
return KeyboardPacket { K_PrtScr, true };
|
||||||
|
}
|
||||||
|
|
||||||
|
state.parsing_ext = false;
|
||||||
|
state.key_state.clear_data();
|
||||||
|
return KeyboardPacket { K_Unknown, false };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scancode == 0x2a || scancode == 0xb7)
|
||||||
|
{
|
||||||
|
state.key_state.try_append(scancode).release_value();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool released = is_key_released(scancode);
|
||||||
|
|
||||||
|
KeyCode key = KeyCode::K_Unknown;
|
||||||
|
|
||||||
|
if (scancode <= 0x6d) key = extended_keycode_table[scancode - 0x10];
|
||||||
|
|
||||||
|
state.parsing_ext = false;
|
||||||
|
state.key_state.clear_data();
|
||||||
|
|
||||||
|
return KeyboardPacket { key, released };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scancode == 0xe0)
|
||||||
|
{
|
||||||
|
state.parsing_ext = true;
|
||||||
|
state.key_state.try_append(scancode).release_value();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Support extended scancodes.
|
if (scancode == 0xe1)
|
||||||
if (scancode == EXTENDED_KEY_CODE)
|
|
||||||
{
|
{
|
||||||
state.ignore_next = true;
|
state.parsing_pause = true;
|
||||||
|
state.key_state.try_append(scancode).release_value();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool released = is_key_released(scancode);
|
bool released = is_key_released(scancode);
|
||||||
|
|
||||||
return KeyboardPacket { keycode_table[scancode], released };
|
KeyCode key = KeyCode::K_Unknown;
|
||||||
|
|
||||||
|
if (scancode <= 0x58) key = keycode_table[scancode];
|
||||||
|
|
||||||
|
return KeyboardPacket { key, released };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user