1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 09:08:12 +00:00
serenity/Kernel/Devices/HID/KeyboardDevice.cpp
Spencer Dixon 0f89e47a1a
Kernel: Allow remapping Caps Lock to Control (#6883)
We use a global setting to determine if Caps Lock should be remapped to
Control because we don't care how keyboard events come in, just that they
should be massaged into different scan codes.

The `proc` filesystem is able to manipulate this global variable using
the `sysctl` utility like so:

```
# sysctl caps_lock_to_ctrl=1
```
2021-05-05 23:10:56 +02:00

320 lines
6.4 KiB
C++

/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#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 (!g_caps_lock_remapped_to_ctrl && key == Key_CapsLock && pressed)
m_caps_lock_on = !m_caps_lock_on;
if (g_caps_lock_remapped_to_ctrl && key == Key_CapsLock)
m_caps_lock_to_ctrl_pressed = pressed;
if (g_caps_lock_remapped_to_ctrl)
update_modifier(Mod_Ctrl, m_caps_lock_to_ctrl_pressed);
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;
}
}