summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kernel/MousePacket.h7
-rw-r--r--Kernel/PS2MouseDevice.cpp35
-rw-r--r--Kernel/PS2MouseDevice.h8
-rw-r--r--WindowServer/WSMessageLoop.cpp39
-rw-r--r--WindowServer/WSScreen.cpp23
-rw-r--r--WindowServer/WSScreen.h4
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)