Serenity Operating System
at hosted 408 lines 16 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "Clipboard.h" 28#include <Kernel/KeyCode.h> 29#include <Kernel/MousePacket.h> 30#include <LibCore/LocalSocket.h> 31#include <LibCore/Object.h> 32#include <WindowServer/ClientConnection.h> 33#include <WindowServer/Cursor.h> 34#include <WindowServer/Event.h> 35#include <WindowServer/EventLoop.h> 36#include <WindowServer/Screen.h> 37#include <WindowServer/WindowManager.h> 38#include <errno.h> 39#include <fcntl.h> 40#include <stdio.h> 41#include <sys/select.h> 42#include <sys/socket.h> 43#include <sys/time.h> 44#include <time.h> 45#include <unistd.h> 46 47#ifdef __OpenBSD__ 48#include <dev/wscons/wsconsio.h> 49#include <dev/wscons/wsksymdef.h> 50 51static const struct kbd_trans { 52 int wskbd_value; 53 int wsusb_value; 54 KeyCode keycode; 55 u8 character; 56 KeyCode shifted_keycode; 57 u8 shifted_character; 58} kbd_trans_table[] = { 59 { KS_Escape, 41, Key_Escape, '\033', Key_Escape, '\033' }, 60 { KS_1, 30, Key_1, '1', Key_ExclamationPoint, '!' }, 61 { KS_2, 31, Key_2, '2', Key_AtSign, '@' }, 62 { KS_3, 32, Key_3, '3', Key_Hashtag, '#' }, 63 { KS_4, 33, Key_4, '4', Key_Dollar, '$' }, 64 { KS_5, 34, Key_5, '5', Key_Percent, '%' }, 65 { KS_6, 35, Key_6, '6', Key_Circumflex, '^' }, 66 { KS_7, 36, Key_7, '7', Key_Ampersand, '&' }, 67 { KS_8, 37, Key_8, '8', Key_Asterisk, '*' }, 68 { KS_9, 38, Key_9, '9', Key_LeftParen, '(' }, 69 { KS_0, 39, Key_0, '0', Key_RightParen, ')' }, 70 { KS_minus, 45, Key_Minus, '-', Key_Underscore, '_' }, 71 { KS_equal, 46, Key_Equal, '=', Key_Plus, '+' }, 72 { KS_Tab, 43, Key_Tab, '\t', Key_Tab, '\t' }, 73 { KS_Delete, 42, Key_Backspace, 0x8, Key_Backspace, 0x8 }, 74 { KS_q, 20, Key_Q, 'q', Key_Q, 'Q' }, 75 { KS_w, 26, Key_W, 'w', Key_W, 'W' }, 76 { KS_e, 8, Key_E, 'e', Key_E, 'E' }, 77 { KS_r, 21, Key_R, 'r', Key_R, 'R' }, 78 { KS_t, 23, Key_T, 't', Key_T, 'T' }, 79 { KS_y, 28, Key_Y, 'y', Key_Y, 'Y' }, 80 { KS_u, 24, Key_U, 'u', Key_U, 'U' }, 81 { KS_i, 12, Key_I, 'i', Key_I, 'I' }, 82 { KS_o, 18, Key_O, 'o', Key_O, 'O' }, 83 { KS_p, 19, Key_P, 'p', Key_P, 'P' }, 84 { KS_bracketleft, 47, Key_LeftBracket, '[', Key_LeftBrace, '{' }, 85 { KS_bracketright, 48, Key_RightBracket, ']', Key_RightBrace, '}' }, 86 { KS_Return, 40, Key_Return, '\n', Key_Return, '\n' }, 87 { KS_Control_L, 224, Key_Control, 0, Key_Control, 0 }, 88 { KS_a, 4, Key_A, 'a', Key_A, 'A' }, 89 { KS_s, 22, Key_S, 's', Key_S, 'S' }, 90 { KS_d, 7, Key_D, 'd', Key_D, 'D' }, 91 { KS_f, 9, Key_F, 'f', Key_F, 'F' }, 92 { KS_g, 10, Key_G, 'g', Key_G, 'G' }, 93 { KS_h, 11, Key_H, 'h', Key_H, 'H' }, 94 { KS_j, 13, Key_J, 'j', Key_J, 'J' }, 95 { KS_k, 14, Key_K, 'k', Key_K, 'K' }, 96 { KS_l, 15, Key_L, 'l', Key_L, 'L' }, 97 { KS_semicolon, 51, Key_Semicolon, ';', Key_Colon, ':' }, 98 { KS_apostrophe, 52, Key_Apostrophe, '\'', Key_DoubleQuote, '"' }, 99 { KS_grave, 53, Key_Backtick, '`', Key_Tilde, '~' }, 100 { KS_Shift_L, 225, Key_Shift, 0, Key_Shift, 0 }, 101 { KS_backslash, 49, Key_Backslash, '\\', Key_Pipe, '|' }, 102 { KS_z, 29, Key_Z, 'z', Key_Z, 'Z' }, 103 { KS_x, 27, Key_X, 'x', Key_X, 'X' }, 104 { KS_c, 6, Key_C, 'c', Key_C, 'C' }, 105 { KS_v, 25, Key_V, 'v', Key_V, 'V' }, 106 { KS_b, 5, Key_B, 'b', Key_B, 'B' }, 107 { KS_n, 17, Key_N, 'n', Key_N, 'N' }, 108 { KS_m, 16, Key_M, 'm', Key_M, 'M' }, 109 { KS_comma, 54, Key_Comma, ',', Key_LessThan, '<' }, 110 { KS_period, 55, Key_Period, '.', Key_GreaterThan, '>' }, 111 { KS_slash, 56, Key_Slash, '/', Key_QuestionMark, '?' }, 112 { KS_Shift_R, 0, Key_Shift, 0, Key_Shift, 0 }, 113 { KS_multiply, 85, Key_Asterisk, '*', Key_Asterisk, '*' }, 114 { KS_Alt_L, 226, Key_Alt, 0, Key_Alt, 0 }, 115 { KS_space, 44, Key_Space, ' ', Key_Space, ' ' }, 116 { KS_Caps_Lock, 57, Key_CapsLock, 0, Key_CapsLock, 0 }, 117 { KS_f1, 58, Key_F1, 0, Key_F1, 0 }, 118 { KS_f2, 59, Key_F2, 0, Key_F2, 0 }, 119 { KS_f3, 60, Key_F3, 0, Key_F3, 0 }, 120 { KS_f4, 61, Key_F4, 0, Key_F4, 0 }, 121 { KS_f5, 62, Key_F5, 0, Key_F5, 0 }, 122 { KS_f6, 63, Key_F6, 0, Key_F6, 0 }, 123 { KS_f7, 64, Key_F7, 0, Key_F7, 0 }, 124 { KS_f8, 65, Key_F8, 0, Key_F8, 0 }, 125 { KS_f9, 66, Key_F9, 0, Key_F9, 0 }, 126 { KS_f10, 67, Key_F10, 0, Key_F10, 0 }, 127 { KS_Num_Lock, 83, Key_NumLock, 0, Key_NumLock, 0 }, 128 { KS_Hold_Screen, 71, Key_SysRq, 0, Key_SysRq, 0 }, 129 { KS_Home, 74, Key_Home, 0, Key_Home, 0 }, 130 { KS_Up, 82, Key_Up, 0, Key_Up, 0 }, 131 { KS_Prior, 75, Key_PageUp, 0, Key_PageUp, 0 }, 132 { KS_Alt_R, 230, Key_Alt, 0, Key_Alt, 0 }, 133 { KS_Control_R, 228, Key_Control, 0, Key_Control, 0 }, 134 { KS_KP_Subtract, 86, Key_Minus, '-', Key_Minus, '-' }, 135 { KS_Left, 80, Key_Left, 0, Key_Left, 0 }, 136 { KS_Right, 79, Key_Right, 0, Key_Right, 0 }, 137 { KS_KP_Add, 87, Key_Plus, '+', Key_Plus, '+' }, 138 { KS_End, 77, Key_End, 0, Key_End, 0 }, 139 { KS_Down, 81, Key_Down, 0, Key_Down, 0 }, 140 { KS_Next, 78, Key_PageDown, 0, Key_PageDown, 0 }, 141 { KS_Insert, 73, Key_Insert, 0, Key_Insert, 0 }, 142 { KS_Delete, 76, Key_Delete, 0, Key_Delete, 0 }, 143 { KS_Print_Screen, 70, Key_PrintScreen, 0, Key_PrintScreen, 0 }, 144 { KS_f11, 68, Key_F11, 0, Key_F11, 0 }, 145 { KS_f12, 69, Key_F12, 0, Key_F12, 0 }, 146 { KS_KP_Divide, 84, Key_Slash, '/', Key_Slash, '/' }, 147 { KS_Pause, 72, Key_Invalid, 0, Key_Invalid, 0 }, 148 { KS_KP_7, 95, Key_7, '7', Key_7, '7' }, 149 { KS_KP_8, 96, Key_8, '8', Key_8, '8' }, 150 { KS_KP_9, 97, Key_9, '9', Key_9, '9' }, 151 { KS_KP_4, 92, Key_4, '4', Key_4, '4' }, 152 { KS_KP_5, 93, Key_5, '5', Key_5, '5' }, 153 { KS_KP_6, 94, Key_6, '6', Key_6, '6' }, 154 { KS_KP_1, 89, Key_1, '1', Key_1, '1' }, 155 { KS_KP_2, 90, Key_2, '2', Key_2, '2' }, 156 { KS_KP_3, 91, Key_3, '3', Key_3, '3' }, 157 { KS_KP_0, 98, Key_0, '0', Key_0, '0' }, 158 { KS_KP_Decimal, 99, Key_Period, '.', Key_Period, '.' }, 159 { KS_KP_Enter, 88, Key_Return, '\n', Key_Return, '\n' }, 160 { 219, 101, Key_Logo, 0, Key_Logo, 0 }, 161}; 162 163static int kbd_modifiers = 0; 164#endif 165 166//#define WSMESSAGELOOP_DEBUG 167 168namespace WindowServer { 169 170EventLoop::EventLoop() 171 : m_server(Core::LocalServer::construct()) 172{ 173#ifdef __OpenBSD__ 174 m_keyboard_fd = open("/dev/wskbd", O_RDONLY | O_NONBLOCK | O_CLOEXEC); 175 m_mouse_fd = open("/dev/wsmouse", O_RDONLY | O_NONBLOCK | O_CLOEXEC); 176#else 177 m_keyboard_fd = open("/dev/keyboard", O_RDONLY | O_NONBLOCK | O_CLOEXEC); 178 m_mouse_fd = open("/dev/mouse", O_RDONLY | O_NONBLOCK | O_CLOEXEC); 179#endif 180 181 bool ok = m_server->take_over_from_system_server(); 182 ASSERT(ok); 183 184 m_server->on_ready_to_accept = [this] { 185 auto client_socket = m_server->accept(); 186 if (!client_socket) { 187 dbg() << "WindowServer: accept failed."; 188 return; 189 } 190 static int s_next_client_id = 0; 191 int client_id = ++s_next_client_id; 192 IPC::new_client_connection<ClientConnection>(*client_socket, client_id); 193 }; 194 195 ASSERT(m_keyboard_fd >= 0); 196 ASSERT(m_mouse_fd >= 0); 197 198 m_keyboard_notifier = Core::Notifier::construct(m_keyboard_fd, Core::Notifier::Read); 199 m_keyboard_notifier->on_ready_to_read = [this] { drain_keyboard(); }; 200 201 m_mouse_notifier = Core::Notifier::construct(m_mouse_fd, Core::Notifier::Read); 202 m_mouse_notifier->on_ready_to_read = [this] { drain_mouse(); }; 203 204 Clipboard::the().on_content_change = [&] { 205 ClientConnection::for_each_client([&](auto& client) { 206 client.notify_about_clipboard_contents_changed(); 207 }); 208 }; 209} 210 211EventLoop::~EventLoop() 212{ 213} 214 215void EventLoop::drain_mouse() 216{ 217 auto& screen = Screen::the(); 218 MousePacket state; 219 state.buttons = screen.mouse_button_state(); 220 unsigned buttons = state.buttons; 221 MousePacket packets[32]; 222 223#ifdef __OpenBSD__ 224 struct wscons_event wsevent; 225 ssize_t nread = read(m_mouse_fd, (u8*)&wsevent, sizeof(wsevent)); 226 if (nread < (ssize_t)sizeof(wsevent)) 227 return; 228 229 /* fake it */ 230 size_t npackets = 1; 231 232 memset(&packets[0], 0, sizeof(packets[0])); 233 234 packets[0].buttons = buttons; 235 packets[0].is_relative = true; 236 237 switch (wsevent.type) { 238 case WSCONS_EVENT_MOUSE_UP: 239 packets[0].buttons = 0; 240 break; 241 case WSCONS_EVENT_MOUSE_DOWN: 242 packets[0].buttons = wsevent.value + 1; // button 0 is left-most 243 break; 244 case WSCONS_EVENT_MOUSE_DELTA_X: 245 packets[0].x = wsevent.value; 246 break; 247 case WSCONS_EVENT_MOUSE_DELTA_Y: 248 packets[0].y = wsevent.value; 249 break; 250 case WSCONS_EVENT_MOUSE_DELTA_Z: 251 packets[0].y = wsevent.value; 252 break; 253 default: 254 /* discard */ 255 npackets = 0; 256 257 switch (wsevent.type) { 258 case WSCONS_EVENT_MOUSE_DELTA_W: 259 break; 260 case WSCONS_EVENT_MOUSE_ABSOLUTE_X: 261 case WSCONS_EVENT_MOUSE_ABSOLUTE_Y: 262 case WSCONS_EVENT_MOUSE_ABSOLUTE_Z: 263 case WSCONS_EVENT_MOUSE_ABSOLUTE_W: 264 dbg() << "need absolute coordinate support"; 265 break; 266 case WSCONS_EVENT_HSCROLL: 267 case WSCONS_EVENT_VSCROLL: 268 /* serenity doesn't support these yet */ 269 break; 270 case WSCONS_EVENT_SYNC: 271 break; 272 default: 273 dbg() << "unknown wscons event of type " << wsevent.type; 274 } 275 } 276 npackets = 1; 277#else 278 ssize_t nread = read(m_mouse_fd, &packets, sizeof(packets)); 279 if (nread < 0) { 280 perror("EventLoop::drain_mouse read"); 281 return; 282 } 283 size_t npackets = nread / sizeof(MousePacket); 284#endif 285 if (!npackets) 286 return; 287 for (size_t i = 0; i < npackets; ++i) { 288 auto& packet = packets[i]; 289#ifdef WSMESSAGELOOP_DEBUG 290 dbgprintf("EventLoop: Mouse X %d, Y %d, Z %d, relative %d\n", packet.x, packet.y, packet.z, packet.is_relative); 291#endif 292 buttons = packet.buttons; 293 294 state.is_relative = packet.is_relative; 295 if (packet.is_relative) { 296 state.x += packet.x; 297 state.y -= packet.y; 298 state.z += packet.z; 299 } else { 300 state.x = packet.x; 301 state.y = packet.y; 302 state.z += packet.z; 303 } 304 305 if (buttons != state.buttons) { 306 state.buttons = buttons; 307#ifdef WSMESSAGELOOP_DEBUG 308 dbgprintf("EventLoop: Mouse Button Event\n"); 309#endif 310 screen.on_receive_mouse_data(state); 311 if (state.is_relative) { 312 state.x = 0; 313 state.y = 0; 314 state.z = 0; 315 } 316 } 317 } 318 if (state.is_relative && (state.x || state.y || state.z)) 319 screen.on_receive_mouse_data(state); 320 if (!state.is_relative) 321 screen.on_receive_mouse_data(state); 322} 323 324void EventLoop::drain_keyboard() 325{ 326 auto& screen = Screen::the(); 327 for (;;) { 328 ::KeyEvent event; 329#ifdef __OpenBSD__ 330 struct wscons_event wsevent; 331 ssize_t nread = 0; 332 if (read(m_keyboard_fd, (u8*)&wsevent, sizeof(wsevent)) < (ssize_t)sizeof(wsevent)) 333 break; 334 335 memset(&event, 0, sizeof(event)); 336 337 for (int i = 0; i < (int)(sizeof(kbd_trans_table) / sizeof(kbd_trans)); i++) { 338 // XXX: We are reading events from the wskbd mux which provides no 339 // indication of which child device this event came from. Since 340 // each child has its own keyboard type and map, wsevent.value is 341 // only useful if you have the keyboard's specific map. 342 // I guess the proper way to do this is to open the mux, do 343 // WSMUXIO_LIST_DEVICES, then open each device separately and poll 344 // on it. Then we'd know which device each event came from and can 345 // look it up properly, but that's a lot of work. So just 346 // hard-code that we're looking at a USB device here... 347 if (wsevent.value != kbd_trans_table[i].wsusb_value) 348 continue; 349 350 switch (wsevent.type) { 351 case WSCONS_EVENT_KEY_UP: 352 switch (kbd_trans_table[i].keycode) { 353 case Key_Shift: 354 kbd_modifiers &= ~Mod_Shift; 355 break; 356 case Key_Control: 357 kbd_modifiers &= ~Mod_Ctrl; 358 break; 359 case Key_Alt: 360 kbd_modifiers &= ~Mod_Alt; 361 break; 362 default: 363 ; 364 } 365 break; 366 case WSCONS_EVENT_KEY_DOWN: 367 event.flags = Is_Press; 368 369 switch (kbd_trans_table[i].keycode) { 370 case Key_Shift: 371 kbd_modifiers |= Mod_Shift; 372 break; 373 case Key_Control: 374 kbd_modifiers |= Mod_Ctrl; 375 break; 376 case Key_Alt: 377 kbd_modifiers |= Mod_Alt; 378 break; 379 default: 380 ; 381 } 382 break; 383 } 384 385 if (kbd_modifiers & Mod_Shift) { 386 event.key = kbd_trans_table[i].shifted_keycode; 387 event.character = kbd_trans_table[i].shifted_character; 388 } else { 389 event.key = kbd_trans_table[i].keycode; 390 event.character = kbd_trans_table[i].character; 391 } 392 event.flags |= kbd_modifiers; 393 nread = sizeof(::KeyEvent); 394 395 //dbg() << "wskbd key " << wsevent.value << " (type " << wsevent.type << ") -> serenity event key " << event.key << " (" << (char)event.character << "), modifiers " << kbd_modifiers; 396 break; 397 } 398#else 399 ssize_t nread = read(m_keyboard_fd, (u8*)&event, sizeof(::KeyEvent)); 400#endif 401 if (nread == 0) 402 break; 403 ASSERT(nread == sizeof(::KeyEvent)); 404 screen.on_receive_keyboard_data(event); 405 } 406} 407 408}