diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-03-05 13:59:44 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-03-05 14:01:03 +0100 |
commit | 26a9d662f4bdff1fe7257d1779c96ee541d31bb4 (patch) | |
tree | 84c6dbdc4353447fcb1e81c97e84e6ef6e8de105 | |
parent | 1cc32ebc7e1c6b14b6d79293494e5f6bd098f60d (diff) | |
download | serenity-26a9d662f4bdff1fe7257d1779c96ee541d31bb4.zip |
Kernel+WindowServer: Move mouse input signal parsing to kernel driver.
It was silly for the WindowServer to have to know anything about the
format of PS/2 mouse packets.
This patch also enables use of the middle mouse button.
-rw-r--r-- | Kernel/MousePacket.h | 7 | ||||
-rw-r--r-- | Kernel/PS2MouseDevice.cpp | 35 | ||||
-rw-r--r-- | Kernel/PS2MouseDevice.h | 8 | ||||
-rw-r--r-- | WindowServer/WSMessageLoop.cpp | 39 | ||||
-rw-r--r-- | WindowServer/WSScreen.cpp | 23 | ||||
-rw-r--r-- | WindowServer/WSScreen.h | 4 |
6 files changed, 74 insertions, 42 deletions
diff --git a/Kernel/MousePacket.h b/Kernel/MousePacket.h new file mode 100644 index 0000000000..ad0513ff35 --- /dev/null +++ b/Kernel/MousePacket.h @@ -0,0 +1,7 @@ +#pragma once + +struct MousePacket { + int dx { 0 }; + int dy { 0 }; + byte buttons; +}; diff --git a/Kernel/PS2MouseDevice.cpp b/Kernel/PS2MouseDevice.cpp index 6541163479..b21f489b63 100644 --- a/Kernel/PS2MouseDevice.cpp +++ b/Kernel/PS2MouseDevice.cpp @@ -62,14 +62,35 @@ void PS2MouseDevice::handle_irq() m_queue.size() ); #endif - m_queue.enqueue(m_data[0]); - m_queue.enqueue(m_data[1]); - m_queue.enqueue(m_data[2]); + parse_data_packet(); break; } } } +void PS2MouseDevice::parse_data_packet() +{ + int x = m_data[1]; + int y = m_data[2]; + bool x_overflow = m_data[0] & 0x40; + bool y_overflow = m_data[0] & 0x80; + bool x_sign = m_data[0] & 0x10; + bool y_sign = m_data[0] & 0x20; + if (x && x_sign) + x -= 0x100; + if (y && y_sign) + y -= 0x100; + if (x_overflow || y_overflow) { + x = 0; + y = 0; + } + MousePacket packet; + packet.dx = x; + packet.dy = y; + packet.buttons = m_data[0] & 0x07; + m_queue.enqueue(packet); +} + void PS2MouseDevice::wait_then_write(byte port, byte data) { prepare_for_output(); @@ -150,8 +171,12 @@ ssize_t PS2MouseDevice::read(Process&, byte* buffer, ssize_t size) while (nread < size) { if (m_queue.is_empty()) break; - // FIXME: Don't return partial data frames. - buffer[nread++] = m_queue.dequeue(); + // Don't return partial data frames. + if ((size - nread) < (ssize_t)sizeof(MousePacket)) + break; + auto packet = m_queue.dequeue(); + memcpy(buffer, &packet, sizeof(MousePacket)); + nread += sizeof(MousePacket); } return nread; } diff --git a/Kernel/PS2MouseDevice.h b/Kernel/PS2MouseDevice.h index c5cbc436a6..330d71c6e4 100644 --- a/Kernel/PS2MouseDevice.h +++ b/Kernel/PS2MouseDevice.h @@ -1,7 +1,8 @@ #pragma once #include <Kernel/CharacterDevice.h> -#include "IRQHandler.h" +#include <Kernel/MousePacket.h> +#include <Kernel/IRQHandler.h> class PS2MouseDevice final : public IRQHandler, public CharacterDevice { public: @@ -30,8 +31,9 @@ private: byte mouse_read(); void wait_then_write(byte port, byte data); byte wait_then_read(byte port); + void parse_data_packet(); - CircularQueue<byte, 600> m_queue; + CircularQueue<MousePacket, 100> m_queue; byte m_data_state { 0 }; - signed_byte m_data[3]; + byte m_data[3]; }; diff --git a/WindowServer/WSMessageLoop.cpp b/WindowServer/WSMessageLoop.cpp index 11fc7b1df4..d7c940c251 100644 --- a/WindowServer/WSMessageLoop.cpp +++ b/WindowServer/WSMessageLoop.cpp @@ -6,6 +6,7 @@ #include <WindowServer/WSClientConnection.h> #include <WindowServer/WSAPITypes.h> #include <Kernel/KeyCode.h> +#include <Kernel/MousePacket.h> #include <LibC/sys/socket.h> #include <LibC/sys/select.h> #include <LibC/unistd.h> @@ -200,45 +201,35 @@ void WSMessageLoop::drain_mouse() auto& screen = WSScreen::the(); bool prev_left_button = screen.left_mouse_button_pressed(); bool prev_right_button = screen.right_mouse_button_pressed(); + bool prev_middle_button = screen.middle_mouse_button_pressed(); int dx = 0; int dy = 0; bool left_button = prev_left_button; bool right_button = prev_right_button; + bool middle_button = prev_middle_button; for (;;) { - byte data[3]; - ssize_t nread = read(m_mouse_fd, data, sizeof(data)); + MousePacket packet; + ssize_t nread = read(m_mouse_fd, &packet, sizeof(MousePacket)); if (nread == 0) break; - ASSERT(nread == sizeof(data)); - bool left_button = data[0] & 1; - bool right_button = data[0] & 2; - bool x_overflow = data[0] & 0x40; - bool y_overflow = data[0] & 0x80; - bool x_sign = data[0] & 0x10; - bool y_sign = data[0] & 0x20; + ASSERT(nread == sizeof(packet)); + left_button = packet.buttons & 1; + right_button = packet.buttons & 2; + middle_button = packet.buttons & 4; - if (x_overflow || y_overflow) - continue; - - int x = data[1]; - int y = data[2]; - if (x && x_sign) - x -= 0x100; - if (y && y_sign) - y -= 0x100; - - dx += x; - dy += -y; - if (left_button != prev_left_button || right_button != prev_right_button) { + dx += packet.dx; + dy += -packet.dy; + if (left_button != prev_left_button || right_button != prev_right_button || middle_button != prev_middle_button) { prev_left_button = left_button; prev_right_button = right_button; - screen.on_receive_mouse_data(dx, dy, left_button, right_button); + prev_middle_button = middle_button; + screen.on_receive_mouse_data(dx, dy, left_button, right_button, middle_button); dx = 0; dy = 0; } } if (dx || dy) { - screen.on_receive_mouse_data(dx, dy, left_button, right_button); + screen.on_receive_mouse_data(dx, dy, left_button, right_button, middle_button); } } diff --git a/WindowServer/WSScreen.cpp b/WindowServer/WSScreen.cpp index 96cc2c4b9b..d3d25d498e 100644 --- a/WindowServer/WSScreen.cpp +++ b/WindowServer/WSScreen.cpp @@ -58,28 +58,24 @@ void WSScreen::set_resolution(int width, int height) m_cursor_location.constrain(rect()); } -void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool right_button) +void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool right_button, bool middle_button) { auto prev_location = m_cursor_location; m_cursor_location.move_by(dx, dy); m_cursor_location.constrain(rect()); - if (m_cursor_location.x() >= width()) - m_cursor_location.set_x(width() - 1); - if (m_cursor_location.y() >= height()) - m_cursor_location.set_y(height() - 1); unsigned buttons = 0; if (left_button) buttons |= (unsigned)MouseButton::Left; if (right_button) buttons |= (unsigned)MouseButton::Right; - if (m_cursor_location != prev_location) { - auto message = make<WSMouseEvent>(WSMessage::MouseMove, m_cursor_location, buttons); - WSMessageLoop::the().post_message(WSWindowManager::the(), move(message)); - } + if (middle_button) + buttons |= (unsigned)MouseButton::Middle; bool prev_left_button = m_left_mouse_button_pressed; bool prev_right_button = m_right_mouse_button_pressed; + bool prev_middle_button = m_middle_mouse_button_pressed; m_left_mouse_button_pressed = left_button; m_right_mouse_button_pressed = right_button; + m_middle_mouse_button_pressed = middle_button; if (prev_left_button != left_button) { auto message = make<WSMouseEvent>(left_button ? WSMessage::MouseDown : WSMessage::MouseUp, m_cursor_location, buttons, MouseButton::Left); WSMessageLoop::the().post_message(WSWindowManager::the(), move(message)); @@ -88,6 +84,15 @@ void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool righ auto message = make<WSMouseEvent>(right_button ? WSMessage::MouseDown : WSMessage::MouseUp, m_cursor_location, buttons, MouseButton::Right); WSMessageLoop::the().post_message(WSWindowManager::the(), move(message)); } + if (prev_middle_button != middle_button) { + auto message = make<WSMouseEvent>(middle_button ? WSMessage::MouseDown : WSMessage::MouseUp, m_cursor_location, buttons, MouseButton::Middle); + WSMessageLoop::the().post_message(WSWindowManager::the(), move(message)); + } + if (m_cursor_location != prev_location) { + auto message = make<WSMouseEvent>(WSMessage::MouseMove, m_cursor_location, buttons); + WSMessageLoop::the().post_message(WSWindowManager::the(), move(message)); + } + // NOTE: Invalidate the cursor if it moved, or if the left button changed state (for the cursor color inversion.) if (m_cursor_location != prev_location || prev_left_button != left_button) WSWindowManager::the().invalidate_cursor(); } diff --git a/WindowServer/WSScreen.h b/WindowServer/WSScreen.h index 851a12fd95..654490387f 100644 --- a/WindowServer/WSScreen.h +++ b/WindowServer/WSScreen.h @@ -26,8 +26,9 @@ public: Point cursor_location() const { return m_cursor_location; } bool left_mouse_button_pressed() const { return m_left_mouse_button_pressed; } bool right_mouse_button_pressed() const { return m_right_mouse_button_pressed; } + bool middle_mouse_button_pressed() const { return m_middle_mouse_button_pressed; } - void on_receive_mouse_data(int dx, int dy, bool left_button, bool right_button); + void on_receive_mouse_data(int dx, int dy, bool left_button, bool right_button, bool middle_button); void on_receive_keyboard_data(KeyEvent); private: @@ -40,6 +41,7 @@ private: Point m_cursor_location; bool m_left_mouse_button_pressed { false }; bool m_right_mouse_button_pressed { false }; + bool m_middle_mouse_button_pressed { false }; }; inline RGBA32* WSScreen::scanline(int y) |