mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 16:32:45 +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
					
				
					 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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling