Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/Debug.h>
8#include <Kernel/API/MousePacket.h>
9#include <WindowServer/ConnectionFromClient.h>
10#include <WindowServer/Cursor.h>
11#include <WindowServer/EventLoop.h>
12#include <WindowServer/Screen.h>
13#include <WindowServer/WMConnectionFromClient.h>
14#include <WindowServer/WindowManager.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <unistd.h>
18
19namespace WindowServer {
20
21EventLoop::EventLoop()
22{
23 m_keyboard_fd = open("/dev/input/keyboard/0", O_RDONLY | O_NONBLOCK | O_CLOEXEC);
24 m_mouse_fd = open("/dev/input/mouse/0", O_RDONLY | O_NONBLOCK | O_CLOEXEC);
25
26 m_window_server = MUST(IPC::MultiServer<ConnectionFromClient>::try_create("/tmp/portal/window"));
27 m_wm_server = MUST(IPC::MultiServer<WMConnectionFromClient>::try_create("/tmp/portal/wm"));
28
29 if (m_keyboard_fd >= 0) {
30 m_keyboard_notifier = Core::Notifier::construct(m_keyboard_fd, Core::Notifier::Read);
31 m_keyboard_notifier->on_ready_to_read = [this] { drain_keyboard(); };
32 } else {
33 dbgln("Couldn't open /dev/input/keyboard/0");
34 }
35
36 if (m_mouse_fd >= 0) {
37 m_mouse_notifier = Core::Notifier::construct(m_mouse_fd, Core::Notifier::Read);
38 m_mouse_notifier->on_ready_to_read = [this] { drain_mouse(); };
39 } else {
40 dbgln("Couldn't open /dev/input/mouse/0");
41 }
42}
43
44void EventLoop::drain_mouse()
45{
46 auto& screen_input = ScreenInput::the();
47 MousePacket state;
48 state.buttons = screen_input.mouse_button_state();
49 MousePacket packets[32];
50
51 ssize_t nread = read(m_mouse_fd, &packets, sizeof(packets));
52 if (nread < 0) {
53 perror("EventLoop::drain_mouse read");
54 return;
55 }
56 size_t npackets = nread / sizeof(MousePacket);
57 if (!npackets)
58 return;
59
60 bool state_is_sent = false;
61 for (size_t i = 0; i < npackets; ++i) {
62 auto& packet = packets[i];
63 dbgln_if(WSMESSAGELOOP_DEBUG, "EventLoop: Mouse X {}, Y {}, Z {}, W {}, relative={}", packet.x, packet.y, packet.z, packet.w, packet.is_relative);
64
65 state.is_relative = packet.is_relative;
66 if (packet.is_relative) {
67 state.x += packet.x;
68 state.y -= packet.y;
69 } else {
70 state.x = packet.x;
71 state.y = packet.y;
72 }
73 state.w += packet.w;
74 state_is_sent = false;
75
76 // Invert scroll direction if checked in the settings.
77 if (WindowManager::the().is_natural_scroll())
78 state.z -= packet.z;
79 else
80 state.z += packet.z;
81
82 if (packet.buttons != state.buttons) {
83 state.buttons = packet.buttons;
84 dbgln_if(WSMESSAGELOOP_DEBUG, "EventLoop: Mouse Button Event");
85
86 // Swap primary (1) and secondary (2) buttons if checked in Settings.
87 // Doing the swap here avoids all emulator and hardware issues.
88 if (WindowManager::the().are_mouse_buttons_switched()) {
89 bool has_primary = state.buttons & MousePacket::Button::LeftButton;
90 bool has_secondary = state.buttons & MousePacket::Button::RightButton;
91 state.buttons = state.buttons & ~(MousePacket::Button::LeftButton | MousePacket::Button::RightButton);
92 // Invert the buttons:
93 if (has_primary)
94 state.buttons |= MousePacket::Button::RightButton;
95 if (has_secondary)
96 state.buttons |= MousePacket::Button::LeftButton;
97 }
98
99 screen_input.on_receive_mouse_data(state);
100 state_is_sent = true;
101 if (state.is_relative) {
102 state.x = 0;
103 state.y = 0;
104 state.z = 0;
105 state.w = 0;
106 }
107 }
108 }
109 if (state_is_sent)
110 return;
111 if (state.is_relative && (state.x || state.y || state.z || state.w))
112 screen_input.on_receive_mouse_data(state);
113 if (!state.is_relative)
114 screen_input.on_receive_mouse_data(state);
115}
116
117void EventLoop::drain_keyboard()
118{
119 auto& screen_input = ScreenInput::the();
120 for (;;) {
121 ::KeyEvent event;
122 ssize_t nread = read(m_keyboard_fd, (u8*)&event, sizeof(::KeyEvent));
123 if (nread == 0)
124 break;
125 VERIFY(nread == sizeof(::KeyEvent));
126 screen_input.on_receive_keyboard_data(event);
127 }
128}
129
130}