Forráskód Böngészése

Flesh out keyboard event support a bit more.

Andreas Kling 6 éve
szülő
commit
aefbbeb3cb

+ 62 - 35
Kernel/Keyboard.cpp

@@ -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]);
-            }
-        //break;
+            key_state_changed(ch, pressed);
+        }
     }
 }
 
@@ -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;
 }

+ 125 - 8
Kernel/Keyboard.h

@@ -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;
 };

+ 1 - 1
Kernel/VirtualConsole.cpp

@@ -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') {

+ 1 - 1
Kernel/VirtualConsole.h

@@ -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;

+ 4 - 7
WindowServer/WSEventLoop.cpp

@@ -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);
     }
 }

+ 2 - 31
WindowServer/WSScreen.cpp

@@ -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;
     }
 

+ 1 - 1
WindowServer/WSScreen.h

@@ -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);