mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
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.
This commit is contained in:
parent
1cc32ebc7e
commit
26a9d662f4
Notes:
sideshowbarker
2024-07-19 15:32:54 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/26a9d662f4b
6 changed files with 74 additions and 42 deletions
7
Kernel/MousePacket.h
Normal file
7
Kernel/MousePacket.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
struct MousePacket {
|
||||
int dx { 0 };
|
||||
int dy { 0 };
|
||||
byte buttons;
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue