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