Serenity Operating System
at master 347 lines 7.7 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il> 4 * Copyright (c) 2021, Edwin Hoksberg <mail@edwinhoksberg.nl> 5 * 6 * SPDX-License-Identifier: BSD-2-Clause 7 */ 8 9#include <AK/Assertions.h> 10#include <AK/Types.h> 11#include <Kernel/API/Ioctl.h> 12#include <Kernel/Devices/HID/KeyboardDevice.h> 13#include <Kernel/Sections.h> 14#include <Kernel/TTY/VirtualConsole.h> 15 16namespace Kernel { 17 18static constexpr KeyCode unshifted_key_map[0x80] = { 19 Key_Invalid, 20 Key_Escape, 21 Key_1, 22 Key_2, 23 Key_3, 24 Key_4, 25 Key_5, 26 Key_6, 27 Key_7, 28 Key_8, 29 Key_9, 30 Key_0, 31 Key_Minus, 32 Key_Equal, 33 Key_Backspace, 34 Key_Tab, // 15 35 Key_Q, 36 Key_W, 37 Key_E, 38 Key_R, 39 Key_T, 40 Key_Y, 41 Key_U, 42 Key_I, 43 Key_O, 44 Key_P, 45 Key_LeftBracket, 46 Key_RightBracket, 47 Key_Return, // 28 48 Key_Control, // 29 49 Key_A, 50 Key_S, 51 Key_D, 52 Key_F, 53 Key_G, 54 Key_H, 55 Key_J, 56 Key_K, 57 Key_L, 58 Key_Semicolon, 59 Key_Apostrophe, 60 Key_Backtick, 61 Key_LeftShift, // 42 62 Key_Backslash, 63 Key_Z, 64 Key_X, 65 Key_C, 66 Key_V, 67 Key_B, 68 Key_N, 69 Key_M, 70 Key_Comma, 71 Key_Period, 72 Key_Slash, 73 Key_RightShift, // 54 74 Key_Asterisk, 75 Key_Alt, // 56 76 Key_Space, // 57 77 Key_CapsLock, // 58 78 Key_F1, 79 Key_F2, 80 Key_F3, 81 Key_F4, 82 Key_F5, 83 Key_F6, 84 Key_F7, 85 Key_F8, 86 Key_F9, 87 Key_F10, 88 Key_NumLock, 89 Key_Invalid, // 70 90 Key_Home, 91 Key_Up, 92 Key_PageUp, 93 Key_Minus, 94 Key_Left, 95 Key_Invalid, 96 Key_Right, // 77 97 Key_Plus, 98 Key_End, 99 Key_Down, // 80 100 Key_PageDown, 101 Key_Insert, 102 Key_Delete, // 83 103 Key_Invalid, 104 Key_Invalid, 105 Key_Backslash, 106 Key_F11, 107 Key_F12, 108 Key_Invalid, 109 Key_Invalid, 110 Key_Super, 111 Key_Invalid, 112 Key_Menu, 113}; 114 115static constexpr KeyCode shifted_key_map[0x100] = { 116 Key_Invalid, 117 Key_Escape, 118 Key_ExclamationPoint, 119 Key_AtSign, 120 Key_Hashtag, 121 Key_Dollar, 122 Key_Percent, 123 Key_Circumflex, 124 Key_Ampersand, 125 Key_Asterisk, 126 Key_LeftParen, 127 Key_RightParen, 128 Key_Underscore, 129 Key_Plus, 130 Key_Backspace, 131 Key_Tab, 132 Key_Q, 133 Key_W, 134 Key_E, 135 Key_R, 136 Key_T, 137 Key_Y, 138 Key_U, 139 Key_I, 140 Key_O, 141 Key_P, 142 Key_LeftBrace, 143 Key_RightBrace, 144 Key_Return, 145 Key_Control, 146 Key_A, 147 Key_S, 148 Key_D, 149 Key_F, 150 Key_G, 151 Key_H, 152 Key_J, 153 Key_K, 154 Key_L, 155 Key_Colon, 156 Key_DoubleQuote, 157 Key_Tilde, 158 Key_LeftShift, // 42 159 Key_Pipe, 160 Key_Z, 161 Key_X, 162 Key_C, 163 Key_V, 164 Key_B, 165 Key_N, 166 Key_M, 167 Key_LessThan, 168 Key_GreaterThan, 169 Key_QuestionMark, 170 Key_RightShift, // 54 171 Key_Asterisk, 172 Key_Alt, 173 Key_Space, // 57 174 Key_CapsLock, // 58 175 Key_F1, 176 Key_F2, 177 Key_F3, 178 Key_F4, 179 Key_F5, 180 Key_F6, 181 Key_F7, 182 Key_F8, 183 Key_F9, 184 Key_F10, 185 Key_NumLock, 186 Key_Invalid, // 70 187 Key_Home, 188 Key_Up, 189 Key_PageUp, 190 Key_Minus, 191 Key_Left, 192 Key_Invalid, 193 Key_Right, // 77 194 Key_Plus, 195 Key_End, 196 Key_Down, // 80 197 Key_PageDown, 198 Key_Insert, 199 Key_Delete, // 83 200 Key_Invalid, 201 Key_Invalid, 202 Key_Pipe, 203 Key_F11, 204 Key_F12, 205 Key_Invalid, 206 Key_Invalid, 207 Key_Super, 208 Key_Invalid, 209 Key_Menu, 210}; 211 212void KeyboardDevice::key_state_changed(u8 scan_code, bool pressed) 213{ 214 KeyCode key = (m_modifiers & Mod_Shift) ? shifted_key_map[scan_code] : unshifted_key_map[scan_code]; 215 216 if (key == Key_NumLock && pressed) 217 m_num_lock_on = !m_num_lock_on; 218 219 if (m_num_lock_on && !m_has_e0_prefix) { 220 if (scan_code >= 0x47 && scan_code <= 0x53) { 221 u8 index = scan_code - 0x47; 222 constexpr 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 }; 223 KeyCode newKey = numpad_key_map[index]; 224 225 if (newKey != Key_Invalid) { 226 key = newKey; 227 } 228 } 229 } 230 231 Event event; 232 event.key = key; 233 event.scancode = m_has_e0_prefix ? 0xe000 + scan_code : scan_code; 234 event.flags = m_modifiers; 235 event.e0_prefix = m_has_e0_prefix; 236 event.caps_lock_on = m_caps_lock_on; 237 event.code_point = HIDManagement::the().get_char_from_character_map(event); 238 239 // If using a non-QWERTY layout, event.key needs to be updated to be the same as event.code_point 240 KeyCode mapped_key = code_point_to_key_code(event.code_point); 241 if (mapped_key != KeyCode::Key_Invalid) { 242 event.key = mapped_key; 243 key = mapped_key; 244 } 245 246 if (!g_caps_lock_remapped_to_ctrl && key == Key_CapsLock && pressed) 247 m_caps_lock_on = !m_caps_lock_on; 248 249 if (g_caps_lock_remapped_to_ctrl && key == Key_CapsLock) 250 m_caps_lock_to_ctrl_pressed = pressed; 251 252 if (g_caps_lock_remapped_to_ctrl) 253 update_modifier(Mod_Ctrl, m_caps_lock_to_ctrl_pressed); 254 255 if (pressed) 256 event.flags |= Is_Press; 257 258 { 259 SpinlockLocker locker(HIDManagement::the().m_client_lock); 260 if (HIDManagement::the().m_client) 261 HIDManagement::the().m_client->on_key_pressed(event); 262 } 263 264 { 265 SpinlockLocker lock(m_queue_lock); 266 m_queue.enqueue(event); 267 } 268 269 m_has_e0_prefix = false; 270 271 evaluate_block_conditions(); 272} 273 274// FIXME: UNMAP_AFTER_INIT is fine for now, but for hot-pluggable devices 275// like USB keyboards, we need to remove this 276UNMAP_AFTER_INIT KeyboardDevice::KeyboardDevice() 277 : HIDDevice(85, HIDManagement::the().generate_minor_device_number_for_keyboard()) 278{ 279} 280 281// FIXME: UNMAP_AFTER_INIT is fine for now, but for hot-pluggable devices 282// like USB keyboards, we need to remove this 283UNMAP_AFTER_INIT KeyboardDevice::~KeyboardDevice() = default; 284 285bool KeyboardDevice::can_read(OpenFileDescription const&, u64) const 286{ 287 return !m_queue.is_empty(); 288} 289 290ErrorOr<size_t> KeyboardDevice::read(OpenFileDescription&, u64, UserOrKernelBuffer& buffer, size_t size) 291{ 292 size_t nread = 0; 293 SpinlockLocker lock(m_queue_lock); 294 while (nread < size) { 295 if (m_queue.is_empty()) 296 break; 297 // Don't return partial data frames. 298 if (size - nread < sizeof(Event)) 299 break; 300 auto event = m_queue.dequeue(); 301 302 lock.unlock(); 303 304 auto result = TRY(buffer.write_buffered<sizeof(Event)>(sizeof(Event), [&](Bytes bytes) { 305 memcpy(bytes.data(), &event, sizeof(Event)); 306 return bytes.size(); 307 })); 308 VERIFY(result == sizeof(Event)); 309 nread += sizeof(Event); 310 311 lock.lock(); 312 } 313 return nread; 314} 315 316ErrorOr<void> KeyboardDevice::ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg) 317{ 318 switch (request) { 319 case KEYBOARD_IOCTL_GET_NUM_LOCK: { 320 auto output = static_ptr_cast<bool*>(arg); 321 return copy_to_user(output, &m_num_lock_on); 322 } 323 case KEYBOARD_IOCTL_SET_NUM_LOCK: { 324 // In this case we expect the value to be a boolean and not a pointer. 325 auto num_lock_value = static_cast<u8>(arg.ptr()); 326 if (num_lock_value != 0 && num_lock_value != 1) 327 return EINVAL; 328 m_num_lock_on = !!num_lock_value; 329 return {}; 330 } 331 case KEYBOARD_IOCTL_GET_CAPS_LOCK: { 332 auto output = static_ptr_cast<bool*>(arg); 333 return copy_to_user(output, &m_caps_lock_on); 334 } 335 case KEYBOARD_IOCTL_SET_CAPS_LOCK: { 336 auto caps_lock_value = static_cast<u8>(arg.ptr()); 337 if (caps_lock_value != 0 && caps_lock_value != 1) 338 return EINVAL; 339 m_caps_lock_on = !!caps_lock_value; 340 return {}; 341 } 342 default: 343 return EINVAL; 344 }; 345} 346 347}