Serenity Operating System
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}