Userspace: Write simple mouse test program
This program draws circle on framebuffer, that you can move with mouse, resize with scroll, and recolor with mouse buttons.
This commit is contained in:
		
							parent
							
								
									54c811ac2e
								
							
						
					
					
						commit
						40f55be587
					
				| 
						 | 
					@ -26,8 +26,9 @@ set(USERSPACE_PROJECTS
 | 
				
			||||||
	sync
 | 
						sync
 | 
				
			||||||
	tee
 | 
						tee
 | 
				
			||||||
	test
 | 
						test
 | 
				
			||||||
	test-globals
 | 
					 | 
				
			||||||
	test-framebuffer
 | 
						test-framebuffer
 | 
				
			||||||
 | 
						test-globals
 | 
				
			||||||
 | 
						test-mouse
 | 
				
			||||||
	test-sort
 | 
						test-sort
 | 
				
			||||||
	touch
 | 
						touch
 | 
				
			||||||
	u8sum
 | 
						u8sum
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,16 @@
 | 
				
			||||||
 | 
					cmake_minimum_required(VERSION 3.26)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					project(test-mouse CXX)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set(SOURCES
 | 
				
			||||||
 | 
						main.cpp
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_executable(test-mouse ${SOURCES})
 | 
				
			||||||
 | 
					target_compile_options(test-mouse PUBLIC -O2 -g)
 | 
				
			||||||
 | 
					target_link_libraries(test-mouse PUBLIC libc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_custom_target(test-mouse-install
 | 
				
			||||||
 | 
						COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/test-mouse ${BANAN_BIN}/
 | 
				
			||||||
 | 
						DEPENDS test-mouse
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,182 @@
 | 
				
			||||||
 | 
					#include <BAN/Math.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <sys/framebuffer.h>
 | 
				
			||||||
 | 
					#include <sys/mman.h>
 | 
				
			||||||
 | 
					#include <termios.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <kernel/Input/MouseEvent.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					framebuffer_info_t fb_info;
 | 
				
			||||||
 | 
					void* fb_mmap = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mouse_fd = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					termios original_termios {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void draw_circle(int cx, int cy, int r, uint32_t color)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int min_x = BAN::Math::max<int>(cx - r, 0);
 | 
				
			||||||
 | 
						int max_x = BAN::Math::min<int>(cx + r + 1, fb_info.width);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int min_y = BAN::Math::max<int>(cy - r, 0);
 | 
				
			||||||
 | 
						int max_y = BAN::Math::min<int>(cy + r + 1, fb_info.height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int y = min_y; y < max_y; y++)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							for (int x = min_x; x < max_x; x++)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								int dx = x - cx;
 | 
				
			||||||
 | 
								int dy = y - cy;
 | 
				
			||||||
 | 
								if (dx * dx + dy * dy > r * r)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								static_cast<uint32_t*>(fb_mmap)[y * fb_info.width + x] = color;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cleanup()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (fb_mmap)
 | 
				
			||||||
 | 
							munmap(fb_mmap, fb_info.height * fb_info.width * (BANAN_FB_BPP / 8));
 | 
				
			||||||
 | 
						if (mouse_fd != -1)
 | 
				
			||||||
 | 
							close(mouse_fd);
 | 
				
			||||||
 | 
						if (original_termios.c_lflag & ECHO)
 | 
				
			||||||
 | 
							tcsetattr(STDIN_FILENO, TCSANOW, &original_termios);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char** argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const char* fb_path = "/dev/fb0";
 | 
				
			||||||
 | 
						const char* mouse_path = "/dev/input1";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (argc == 1)
 | 
				
			||||||
 | 
							;
 | 
				
			||||||
 | 
						else if (argc == 3)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							fb_path = argv[1];
 | 
				
			||||||
 | 
							mouse_path = argv[2];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							fprintf(stderr, "usage: %s [FB_PATH MOUSE_PATH]", argv[0]);
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						signal(SIGINT, [](int) { exit(0); });
 | 
				
			||||||
 | 
						if (atexit(cleanup) == -1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							perror("atexit");
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (BANAN_FB_BPP != 32)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							fprintf(stderr, "unsupported bpp\n");
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int fb_fd = open(fb_path, O_RDWR);
 | 
				
			||||||
 | 
						if (fb_fd == -1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							fprintf(stderr, "open: ");
 | 
				
			||||||
 | 
							perror(fb_path);
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pread(fb_fd, &fb_info, sizeof(fb_info), -1) == -1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							fprintf(stderr, "read: ");
 | 
				
			||||||
 | 
							perror(fb_path);
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t fb_bytes = fb_info.width * fb_info.height * (BANAN_FB_BPP / 8);
 | 
				
			||||||
 | 
						fb_mmap = mmap(nullptr, fb_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
 | 
				
			||||||
 | 
						close(fb_fd);
 | 
				
			||||||
 | 
						if (fb_mmap == MAP_FAILED)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							fprintf(stderr, "mmap: ");
 | 
				
			||||||
 | 
							perror(fb_path);
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int mouse_fd = open(mouse_path, O_RDONLY);
 | 
				
			||||||
 | 
						if (mouse_fd == -1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							fprintf(stderr, "open: ");
 | 
				
			||||||
 | 
							perror(mouse_path);
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tcgetattr(STDIN_FILENO, &original_termios) == -1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							perror("tcgetattr");
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						termios termios = original_termios;
 | 
				
			||||||
 | 
						termios.c_lflag &= ~ECHO;
 | 
				
			||||||
 | 
						if (tcsetattr(STDIN_FILENO, TCSANOW, &termios) == -1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							perror("tcsetattr");
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						uint32_t color = 0xFF0000;
 | 
				
			||||||
 | 
						int mouse_x = fb_info.width / 2;
 | 
				
			||||||
 | 
						int mouse_y = fb_info.height / 2;
 | 
				
			||||||
 | 
						int radius = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// clear screen and render 
 | 
				
			||||||
 | 
						memset(fb_mmap, 0x00, fb_bytes);
 | 
				
			||||||
 | 
						draw_circle(mouse_x, mouse_y, radius, color);
 | 
				
			||||||
 | 
						msync(fb_mmap, fb_bytes, MS_SYNC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (true)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							using namespace Kernel::Input;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							MouseEvent event;
 | 
				
			||||||
 | 
							if (read(mouse_fd, &event, sizeof(event)) == -1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								fprintf(stderr, "read: ");
 | 
				
			||||||
 | 
								perror(mouse_path);
 | 
				
			||||||
 | 
								return 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (event.type)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								case MouseEventType::MouseMoveEvent:
 | 
				
			||||||
 | 
									draw_circle(mouse_x, mouse_y, radius, 0x000000);
 | 
				
			||||||
 | 
									mouse_x = BAN::Math::clamp<int>(mouse_x + event.move_event.rel_x, 0, fb_info.width);
 | 
				
			||||||
 | 
									mouse_y = BAN::Math::clamp<int>(mouse_y - event.move_event.rel_y, 0, fb_info.height);
 | 
				
			||||||
 | 
									draw_circle(mouse_x, mouse_y, radius, color);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case MouseEventType::MouseScrollEvent:
 | 
				
			||||||
 | 
									draw_circle(mouse_x, mouse_y, radius, 0x000000);
 | 
				
			||||||
 | 
									radius = BAN::Math::clamp(radius + event.scroll_event.scroll, 1, 50);
 | 
				
			||||||
 | 
									draw_circle(mouse_x, mouse_y, radius, color);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case MouseEventType::MouseButtonEvent:
 | 
				
			||||||
 | 
									if (!event.button_event.pressed)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									switch (event.button_event.button)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										case MouseButton::Left:		color = 0xFF0000; break;
 | 
				
			||||||
 | 
										case MouseButton::Right:	color = 0x00FF00; break;
 | 
				
			||||||
 | 
										case MouseButton::Middle:	color = 0x0000FF; break;
 | 
				
			||||||
 | 
										case MouseButton::Extra1:	color = 0xFFFF00; break;
 | 
				
			||||||
 | 
										case MouseButton::Extra2:	color = 0x00FFFF; break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									draw_circle(mouse_x, mouse_y, radius, color);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							msync(fb_mmap, fb_bytes, MS_SYNC);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue