summaryrefslogtreecommitdiff
path: root/Kernel/Devices/HID/KeyboardDevice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel/Devices/HID/KeyboardDevice.cpp')
-rw-r--r--Kernel/Devices/HID/KeyboardDevice.cpp334
1 files changed, 334 insertions, 0 deletions
diff --git a/Kernel/Devices/HID/KeyboardDevice.cpp b/Kernel/Devices/HID/KeyboardDevice.cpp
new file mode 100644
index 0000000000..c1c27b02ea
--- /dev/null
+++ b/Kernel/Devices/HID/KeyboardDevice.cpp
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/Assertions.h>
+#include <AK/ByteBuffer.h>
+#include <AK/Singleton.h>
+#include <AK/StringView.h>
+#include <AK/Types.h>
+#include <Kernel/Arch/x86/CPU.h>
+#include <Kernel/Debug.h>
+#include <Kernel/Devices/HID/KeyboardDevice.h>
+#include <Kernel/IO.h>
+#include <Kernel/TTY/VirtualConsole.h>
+
+namespace Kernel {
+
+#define IRQ_KEYBOARD 1
+
+static const KeyCode unshifted_key_map[0x80] = {
+ Key_Invalid,
+ Key_Escape,
+ 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_Tab, //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_LeftShift, // 42
+ Key_Backslash,
+ Key_Z,
+ Key_X,
+ Key_C,
+ Key_V,
+ Key_B,
+ Key_N,
+ Key_M,
+ Key_Comma,
+ Key_Period,
+ Key_Slash,
+ Key_RightShift, // 54
+ Key_Asterisk,
+ Key_Alt, // 56
+ Key_Space, // 57
+ Key_CapsLock, // 58
+ Key_F1,
+ Key_F2,
+ Key_F3,
+ Key_F4,
+ Key_F5,
+ Key_F6,
+ Key_F7,
+ Key_F8,
+ Key_F9,
+ Key_F10,
+ Key_NumLock,
+ Key_Invalid, // 70
+ Key_Home,
+ Key_Up,
+ Key_PageUp,
+ Key_Minus,
+ Key_Left,
+ Key_Invalid,
+ Key_Right, // 77
+ Key_Plus,
+ Key_End,
+ Key_Down, // 80
+ Key_PageDown,
+ Key_Invalid,
+ Key_Delete, // 83
+ Key_Invalid,
+ Key_Invalid,
+ Key_Backslash,
+ Key_F11,
+ Key_F12,
+ Key_Invalid,
+ Key_Invalid,
+ Key_Super,
+ Key_Invalid,
+ Key_Menu,
+};
+
+static const KeyCode shifted_key_map[0x100] = {
+ Key_Invalid,
+ Key_Escape,
+ 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_Tab,
+ 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_LeftShift, // 42
+ Key_Pipe,
+ Key_Z,
+ Key_X,
+ Key_C,
+ Key_V,
+ Key_B,
+ Key_N,
+ Key_M,
+ Key_LessThan,
+ Key_GreaterThan,
+ Key_QuestionMark,
+ Key_RightShift, // 54
+ Key_Asterisk,
+ Key_Alt,
+ Key_Space, // 57
+ Key_CapsLock, // 58
+ Key_F1,
+ Key_F2,
+ Key_F3,
+ Key_F4,
+ Key_F5,
+ Key_F6,
+ Key_F7,
+ Key_F8,
+ Key_F9,
+ Key_F10,
+ Key_NumLock,
+ Key_Invalid, // 70
+ Key_Home,
+ Key_Up,
+ Key_PageUp,
+ Key_Minus,
+ Key_Left,
+ Key_Invalid,
+ Key_Right, // 77
+ Key_Plus,
+ Key_End,
+ Key_Down, // 80
+ Key_PageDown,
+ Key_Invalid,
+ Key_Delete, // 83
+ Key_Invalid,
+ Key_Invalid,
+ Key_Pipe,
+ Key_F11,
+ Key_F12,
+ Key_Invalid,
+ Key_Invalid,
+ Key_Super,
+ Key_Invalid,
+ Key_Menu,
+};
+
+static const KeyCode numpad_key_map[13] = { Key_7, Key_8, Key_9, Key_Invalid, Key_4, Key_5, Key_6, Key_Invalid, Key_1, Key_2, Key_3, Key_0, Key_Comma };
+
+void KeyboardDevice::key_state_changed(u8 scan_code, bool pressed)
+{
+ KeyCode key = (m_modifiers & Mod_Shift) ? shifted_key_map[scan_code] : unshifted_key_map[scan_code];
+
+ if (key == Key_NumLock && pressed)
+ m_num_lock_on = !m_num_lock_on;
+
+ if (m_num_lock_on && !m_has_e0_prefix) {
+ if (scan_code >= 0x47 && scan_code <= 0x53) {
+ u8 index = scan_code - 0x47;
+ KeyCode newKey = numpad_key_map[index];
+
+ if (newKey != Key_Invalid) {
+ key = newKey;
+ }
+ }
+ }
+
+ if (key == Key_CapsLock && pressed)
+ m_caps_lock_on = !m_caps_lock_on;
+
+ Event event;
+ event.key = key;
+ event.scancode = m_has_e0_prefix ? 0xe000 + scan_code : scan_code;
+ event.flags = m_modifiers;
+ event.e0_prefix = m_has_e0_prefix;
+ event.caps_lock_on = m_caps_lock_on;
+ event.code_point = HIDManagement::the().character_map().get_char(event);
+
+ if (pressed)
+ event.flags |= Is_Press;
+ if (HIDManagement::the().m_client)
+ HIDManagement::the().m_client->on_key_pressed(event);
+
+ {
+ ScopedSpinLock lock(m_queue_lock);
+ m_queue.enqueue(event);
+ }
+
+ m_has_e0_prefix = false;
+
+ evaluate_block_conditions();
+}
+
+// FIXME: UNMAP_AFTER_INIT is fine for now, but for hot-pluggable devices
+// like USB keyboards, we need to remove this
+UNMAP_AFTER_INIT KeyboardDevice::KeyboardDevice()
+ : HIDDevice(85, HIDManagement::the().generate_minor_device_number_for_keyboard())
+{
+}
+
+// FIXME: UNMAP_AFTER_INIT is fine for now, but for hot-pluggable devices
+// like USB keyboards, we need to remove this
+UNMAP_AFTER_INIT KeyboardDevice::~KeyboardDevice()
+{
+}
+
+bool KeyboardDevice::can_read(const FileDescription&, size_t) const
+{
+ return !m_queue.is_empty();
+}
+
+KResultOr<size_t> KeyboardDevice::read(FileDescription&, u64, UserOrKernelBuffer& buffer, size_t size)
+{
+ size_t nread = 0;
+ ScopedSpinLock lock(m_queue_lock);
+ while (nread < size) {
+ if (m_queue.is_empty())
+ break;
+ // Don't return partial data frames.
+ if ((size - nread) < (ssize_t)sizeof(Event))
+ break;
+ auto event = m_queue.dequeue();
+
+ lock.unlock();
+
+ ssize_t n = buffer.write_buffered<sizeof(Event)>(sizeof(Event), [&](u8* data, size_t data_bytes) {
+ memcpy(data, &event, sizeof(Event));
+ return (ssize_t)data_bytes;
+ });
+ if (n < 0)
+ return KResult((ErrnoCode)-n);
+ VERIFY((size_t)n == sizeof(Event));
+ nread += sizeof(Event);
+
+ lock.lock();
+ }
+ return nread;
+}
+
+KResultOr<size_t> KeyboardDevice::write(FileDescription&, u64, const UserOrKernelBuffer&, size_t)
+{
+ return 0;
+}
+
+}