1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 18:57:42 +00:00

Flesh out keyboard event support a bit more.

This commit is contained in:
Andreas Kling 2019-01-21 07:05:31 +01:00
parent 76a2881793
commit aefbbeb3cb
7 changed files with 196 additions and 84 deletions

View file

@ -19,52 +19,85 @@
#define MOD_CTRL 2
#define MOD_SHIFT 4
static char map[0x100] =
static char map[0x80] =
{
0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0x08, 0,
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0, 0,
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0,
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\',
'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
0, 0, 0, ' '
};
static char shift_map[0x100] =
static char shift_map[0x80] =
{
0, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0, 0,
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 0, 0,
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', 0,
'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 0, '|',
'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',
0, 0, 0, ' '
};
void Keyboard::emit(byte ch)
static KeyCode unshifted_key_map[0x80] =
{
Key key;
key.character = ch;
key.modifiers = m_modifiers;
Key_Invalid, Key_Invalid,
Key_1, Key_2, Key_3, Key_4, Key_5, Key_6, Key_7, Key_8, Key_9, Key_0, Key_Minus, Key_Equal, Key_Backspace,
Key_Invalid, //15
Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_LeftBracket, Key_RightBracket,
Key_Return, // 28
Key_Control, // 29
Key_A, Key_S, Key_D, Key_F, Key_G, Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Apostrophe, Key_Backtick,
Key_Shift,
Key_Backslash,
Key_Z, Key_X, Key_C, Key_V, Key_B, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash,
Key_Alt,
Key_Invalid, Key_Invalid,
Key_Space
};
static KeyCode shifted_key_map[0x100] =
{
Key_Invalid, Key_Invalid,
Key_ExclamationPoint, Key_AtSign, Key_Hashtag, Key_Dollar, Key_Percent, Key_Circumflex, Key_Ampersand, Key_Asterisk, Key_LeftParen, Key_RightParen, Key_Underscore, Key_Plus, Key_Backspace,
Key_Invalid,
Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_LeftBrace, Key_RightBrace,
Key_Return,
Key_Control,
Key_A, Key_S, Key_D, Key_F, Key_G, Key_H, Key_J, Key_K, Key_L, Key_Colon, Key_DoubleQuote, Key_Tilde,
Key_Shift,
Key_Pipe,
Key_Z, Key_X, Key_C, Key_V, Key_B, Key_N, Key_M, Key_LessThan, Key_GreaterThan, Key_QuestionMark,
Key_Alt,
Key_Invalid, Key_Invalid,
Key_Space
};
void Keyboard::key_state_changed(byte raw, bool pressed)
{
Event event;
event.key = (m_modifiers & Mod_Shift) ? shifted_key_map[raw] : unshifted_key_map[raw];
event.character = (m_modifiers & Mod_Shift) ? shift_map[raw] : map[raw];
event.flags = m_modifiers;
if (pressed)
event.flags |= Is_Press;
if (m_client)
m_client->on_key_pressed(key);
m_queue.enqueue(key);
m_client->on_key_pressed(event);
m_queue.enqueue(event);
}
void Keyboard::handle_irq()
{
while (IO::in8(0x64) & 1) {
byte ch = IO::in8(0x60);
byte raw = IO::in8(0x60);
byte ch = raw & 0x7f;
bool pressed = !(raw & 0x80);
switch (ch) {
case 0x38: m_modifiers |= Mod_Alt; break;
case 0xB8: m_modifiers &= ~Mod_Alt; break;
case 0x1D: m_modifiers |= Mod_Ctrl; break;
case 0x9D: m_modifiers &= ~Mod_Ctrl; break;
case 0x2A: m_modifiers |= Mod_Shift; break;
case 0xAA: m_modifiers &= ~Mod_Shift; break;
case 0x1C: /* enter */ emit('\n'); break;
case 0xFA: /* i8042 ack */ break;
case 0x38: update_modifier(Mod_Alt, pressed); break;
case 0x1d: update_modifier(Mod_Ctrl, pressed); break;
case 0x2a: update_modifier(Mod_Shift, pressed); break;
case 0xfa: /* i8042 ack */ break;
default:
if (ch & 0x80) {
// key has been depressed
break;
}
if (m_modifiers & MOD_ALT) {
switch (map[ch]) {
case '1':
@ -77,14 +110,8 @@ void Keyboard::handle_irq()
break;
}
}
if (!m_modifiers)
emit(map[ch]);
else if (m_modifiers & Mod_Shift)
emit(shift_map[ch]);
else if (m_modifiers & Mod_Ctrl)
emit(map[ch]);
key_state_changed(ch, pressed);
}
//break;
}
}
@ -126,11 +153,11 @@ ssize_t Keyboard::read(Process&, byte* buffer, size_t size)
if (m_queue.is_empty())
break;
// Don't return partial data frames.
if ((size - nread) < 2)
if ((size - nread) < sizeof(Event))
break;
auto key = m_queue.dequeue();
buffer[nread++] = key.character;
buffer[nread++] = key.modifiers;
auto event = m_queue.dequeue();
memcpy(buffer, &event, sizeof(Event));
nread += sizeof(Event);
}
return nread;
}

View file

@ -8,6 +8,113 @@
class KeyboardClient;
enum KeyCode : byte {
Key_Invalid = 0,
Key_Escape,
Key_Tab,
Key_Backspace,
Key_Return,
Key_Insert,
Key_Delete,
Key_PrintScreen,
Key_SysRq,
Key_Home,
Key_End,
Key_Left,
Key_Up,
Key_Right,
Key_Down,
Key_PageUp,
Key_PageDown,
Key_Shift,
Key_Control,
Key_Alt,
Key_CapsLock,
Key_NumLock,
Key_ScrollLock,
Key_F1,
Key_F2,
Key_F3,
Key_F4,
Key_F5,
Key_F6,
Key_F7,
Key_F8,
Key_F9,
Key_F10,
Key_F11,
Key_F12,
Key_Space,
Key_ExclamationPoint,
Key_DoubleQuote,
Key_Hashtag,
Key_Dollar,
Key_Percent,
Key_Ampersand,
Key_Apostrophe,
Key_LeftParen,
Key_RightParen,
Key_Asterisk,
Key_Plus,
Key_Comma,
Key_Minus,
Key_Period,
Key_Slash,
Key_0,
Key_1,
Key_2,
Key_3,
Key_4,
Key_5,
Key_6,
Key_7,
Key_8,
Key_9,
Key_Colon,
Key_Semicolon,
Key_LessThan,
Key_Equal,
Key_GreaterThan,
Key_QuestionMark,
Key_AtSign,
Key_A,
Key_B,
Key_C,
Key_D,
Key_E,
Key_F,
Key_G,
Key_H,
Key_I,
Key_J,
Key_K,
Key_L,
Key_M,
Key_N,
Key_O,
Key_P,
Key_Q,
Key_R,
Key_S,
Key_T,
Key_U,
Key_V,
Key_W,
Key_X,
Key_Y,
Key_Z,
Key_LeftBracket,
Key_RightBracket,
Key_Backslash,
Key_Circumflex,
Key_Underscore,
Key_LeftBrace,
Key_RightBrace,
Key_Pipe,
Key_Tilde,
Key_Backtick,
};
class Keyboard final : public IRQHandler, public CharacterDevice {
AK_MAKE_ETERNAL
public:
@ -15,14 +122,17 @@ public:
Mod_Alt = 0x01,
Mod_Ctrl = 0x02,
Mod_Shift = 0x04,
Is_Press = 0x80,
};
struct Key {
struct Event {
KeyCode key { Key_Invalid };
byte character { 0 };
byte modifiers { 0 };
bool alt() { return modifiers & Mod_Alt; }
bool ctrl() { return modifiers & Mod_Ctrl; }
bool shift() { return modifiers & Mod_Shift; }
byte flags { 0 };
bool alt() const { return flags & Mod_Alt; }
bool ctrl() const { return flags & Mod_Ctrl; }
bool shift() const { return flags & Mod_Shift; }
bool is_press() const { return flags & Is_Press; }
};
static Keyboard& the() PURE;
@ -45,15 +155,22 @@ private:
// ^CharacterDevice
virtual const char* class_name() const override { return "Keyboard"; }
void emit(byte);
void key_state_changed(byte raw, bool pressed);
void update_modifier(byte modifier, bool state)
{
if (state)
m_modifiers |= modifier;
else
m_modifiers &= ~modifier;
}
KeyboardClient* m_client { nullptr };
CircularQueue<Key, 16> m_queue;
CircularQueue<Event, 16> m_queue;
byte m_modifiers { 0 };
};
class KeyboardClient {
public:
virtual ~KeyboardClient();
virtual void on_key_pressed(Keyboard::Key) = 0;
virtual void on_key_pressed(Keyboard::Event) = 0;
};

View file

@ -476,7 +476,7 @@ void VirtualConsole::on_char(byte ch)
set_cursor(m_cursor_row, m_cursor_column);
}
void VirtualConsole::on_key_pressed(Keyboard::Key key)
void VirtualConsole::on_key_pressed(Keyboard::Event key)
{
if (key.ctrl()) {
if (key.character >= 'a' && key.character <= 'z') {

View file

@ -17,7 +17,7 @@ public:
private:
// ^KeyboardClient
virtual void on_key_pressed(Keyboard::Key) override;
virtual void on_key_pressed(Keyboard::Event) override;
// ^ConsoleImplementation
virtual void on_sysconsole_receive(byte) override;

View file

@ -158,12 +158,9 @@ void WSEventLoop::drain_keyboard()
auto& screen = WSScreen::the();
auto& keyboard = Keyboard::the();
while (keyboard.can_read(*m_server_process)) {
byte data[2];
ssize_t nread = keyboard.read(*m_server_process, (byte*)data, sizeof(data));
ASSERT(nread == sizeof(data));
Keyboard::Key key;
key.character = data[0];
key.modifiers = data[1];
screen.on_receive_keyboard_data(key);
Keyboard::Event event;
ssize_t nread = keyboard.read(*m_server_process, (byte*)&event, sizeof(Keyboard::Event));
ASSERT(nread == sizeof(Keyboard::Event));
screen.on_receive_keyboard_data(event);
}
}

View file

@ -66,9 +66,9 @@ void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool righ
WSWindowManager::the().draw_cursor();
}
void WSScreen::on_receive_keyboard_data(Keyboard::Key key)
void WSScreen::on_receive_keyboard_data(Keyboard::Event key)
{
auto event = make<KeyEvent>(WSEvent::KeyDown, 0);
auto event = make<KeyEvent>(key.is_press() ? WSEvent::KeyDown : WSEvent::KeyUp, 0);
int key_code = 0;
switch (key.character) {
@ -81,35 +81,6 @@ void WSScreen::on_receive_keyboard_data(Keyboard::Key key)
char buf[] = { 0, 0 };
char& ch = buf[0];
ch = key.character;
if (key.shift()) {
if (ch >= 'a' && ch <= 'z') {
ch &= ~0x20;
} else {
switch (ch) {
case '1': ch = '!'; break;
case '2': ch = '@'; break;
case '3': ch = '#'; break;
case '4': ch = '$'; break;
case '5': ch = '%'; break;
case '6': ch = '^'; break;
case '7': ch = '&'; break;
case '8': ch = '*'; break;
case '9': ch = '('; break;
case '0': ch = ')'; break;
case '-': ch = '_'; break;
case '=': ch = '+'; break;
case '`': ch = '~'; break;
case ',': ch = '<'; break;
case '.': ch = '>'; break;
case '/': ch = '?'; break;
case '[': ch = '{'; break;
case ']': ch = '}'; break;
case '\\': ch = '|'; break;
case '\'': ch = '"'; break;
case ';': ch = ':'; break;
}
}
}
event->m_text = buf;
}

View file

@ -26,7 +26,7 @@ public:
bool right_mouse_button_pressed() const { return m_right_mouse_button_pressed; }
void on_receive_mouse_data(int dx, int dy, bool left_button, bool right_button);
void on_receive_keyboard_data(Keyboard::Key);
void on_receive_keyboard_data(Keyboard::Event);
protected:
WSScreen(unsigned width, unsigned height);