diff options
author | Benji Dial <benji@benjidial.net> | 2024-05-19 04:34:40 -0400 |
---|---|---|
committer | Benji Dial <benji@benjidial.net> | 2024-05-19 04:34:40 -0400 |
commit | e60fa7740cd7d245d1b22a25fea9df0768d32668 (patch) | |
tree | 728fa422d3a2abc66a3e2d89e4ef03b72074bb3e | |
parent | b1a912a8a6ff472a49b2e0a09cfd433adfc2cb24 (diff) | |
download | hilbert-os-e60fa7740cd7d245d1b22a25fea9df0768d32668.tar.gz |
mouse support (working in qemu, semi-working in virtualbox)
-rw-r--r-- | applications/init/source/main.cpp | 124 | ||||
-rw-r--r-- | documentation/kernel-interface/keys.txt (renamed from documentation/keys.txt) | 0 | ||||
-rw-r--r-- | documentation/kernel-interface/sockets.txt (renamed from documentation/sockets.txt) | 0 | ||||
-rw-r--r-- | documentation/kernel-interface/syscalls.txt (renamed from documentation/syscalls.txt) | 14 | ||||
-rw-r--r-- | euler/include/euler/syscall.hpp | 15 | ||||
-rw-r--r-- | euler/source/euler/syscall.asm | 28 | ||||
-rw-r--r-- | kernel/include/hilbert/kernel/input.hpp | 21 | ||||
-rw-r--r-- | kernel/include/hilbert/kernel/utility.hpp | 5 | ||||
-rw-r--r-- | kernel/source/input.cpp | 4 | ||||
-rw-r--r-- | kernel/source/interrupts.asm | 102 | ||||
-rw-r--r-- | kernel/source/interrupts.cpp | 49 | ||||
-rw-r--r-- | kernel/source/syscall.cpp | 19 | ||||
-rw-r--r-- | libraries/daguerre/include/daguerre.hpp | 34 | ||||
-rw-r--r-- | libraries/daguerre/source/daguerre.cpp | 15 | ||||
-rw-r--r-- | skeleton/assets/pointer.ppm | bin | 0 -> 1571 bytes | |||
-rw-r--r-- | skeleton/assets/readme.txt | 2 |
16 files changed, 365 insertions, 67 deletions
diff --git a/applications/init/source/main.cpp b/applications/init/source/main.cpp index ed0ef8e..6aa85a4 100644 --- a/applications/init/source/main.cpp +++ b/applications/init/source/main.cpp @@ -1,28 +1,120 @@ #include <daguerre.hpp> +void overlay_encode( + daguerre::hilbert_color &dest, const daguerre::rgb24 &src) { + if (src.r != 0xff || src.g != 0x00 || src.b != 0xff) + daguerre::encode(dest, src); +} + +void invert(daguerre::rgb24 &dest, const daguerre::rgb24 &src) { + dest.r = 255 - src.r; + dest.g = 255 - src.g; + dest.b = 255 - src.b; +} + int main(int, char **) { - auto hfb = daguerre::get_hilbert_framebuffer(); - daguerre::image<daguerre::rgb24> bim; + auto framebuffer = daguerre::get_hilbert_framebuffer(); - std::FILE *burdon = std::fopen("/assets/burden.ppm", "r"); - daguerre::try_load_ppm(burdon, bim); - std::fclose(burdon); + daguerre::image<daguerre::rgb24> burden; + std::FILE *burden_file = std::fopen("/assets/burden.ppm", "r"); + daguerre::try_load_ppm(burden_file, burden); + std::fclose(burden_file); - unsigned width = bim.width < hfb.width ? bim.width : hfb.width; - unsigned height = bim.height < hfb.height ? bim.height : hfb.height; - unsigned x = (hfb.width - width) / 2; - unsigned y = (hfb.height - height) / 2; + daguerre::image<daguerre::rgb24> pointer; + std::FILE *pointer_file = std::fopen("/assets/pointer.ppm", "r"); + daguerre::try_load_ppm(pointer_file, pointer); + std::fclose(pointer_file); + + int32_t width = burden.width < framebuffer.width + ? burden.width : framebuffer.width; + int32_t height = burden.height < framebuffer.height + ? burden.height : framebuffer.height; + unsigned x = (framebuffer.width - width) / 2; + unsigned y = (framebuffer.height - height) / 2; + + int32_t new_mouse_x = width / 2; + int32_t new_mouse_y = height / 2; + int32_t old_mouse_x = new_mouse_x; + int32_t old_mouse_y = new_mouse_y; + bool was_left_mouse_down = false; + + daguerre::overlay_region< + daguerre::hilbert_color, daguerre::rgb24, daguerre::encode>( + framebuffer, x, y, burden, 0, 0, width, height); while (1) { - daguerre::copy_region<>(hfb, bim, 0, 0, x, y, width, height); - while ((__euler_read_key_packet() & 0x0400ff) != 0x00005a) - ; - for (unsigned i = 0; i < bim.width * bim.height; ++i) { - bim.buffer[i].r = 255 - bim.buffer[i].r; - bim.buffer[i].g = 255 - bim.buffer[i].g; - bim.buffer[i].b = 255 - bim.buffer[i].b; + + __euler_mouse_buttons mouse_buttons; + int16_t mouse_change_x, mouse_change_y; + uint32_t key_packet; + __euler_input_packet_type packet_type = __euler_get_input_packet( + mouse_buttons, mouse_change_x, mouse_change_y, key_packet); + + bool anything_changed = false; + bool should_invert = false; + + if (packet_type == __EULER_IPT_MOUSE) { + + if (mouse_change_x != 0 || mouse_change_y != 0) { + + old_mouse_x = new_mouse_x; + old_mouse_y = new_mouse_y; + new_mouse_x += mouse_change_x; + new_mouse_y += mouse_change_y; + + if (new_mouse_x < 0) + new_mouse_x = 0; + else if ((unsigned)new_mouse_x > width - pointer.width) + new_mouse_x = width - pointer.width; + + if (new_mouse_y < 0) + new_mouse_y = 0; + else if ((unsigned)new_mouse_y > height - pointer.height) + new_mouse_y = height - pointer.height; + + anything_changed = true; + + } + + if (!was_left_mouse_down && (mouse_buttons & __EULER_MB_LEFT)) + should_invert = true; + + was_left_mouse_down = mouse_buttons & __EULER_MB_LEFT; + + } + + else if (packet_type == __EULER_IPT_KEYBOARD) + if ((key_packet & 0x0400ff) == 0x00005a) + should_invert = true; + + if (should_invert) { + + //this works with the current implementation of overlay_region, but + //maybe it would be better to have a dedicated function for when the + //two regions are exactly the same, given the comment on overlay_region. + daguerre::overlay_region<daguerre::rgb24, daguerre::rgb24, invert>( + burden, 0, 0, burden, 0, 0, width, height); + + daguerre::overlay_region< + daguerre::hilbert_color, daguerre::rgb24, daguerre::encode>( + framebuffer, x, y, burden, 0, 0, width, height); + + anything_changed = true; + } + + if (anything_changed) { + daguerre::overlay_region< + daguerre::hilbert_color, daguerre::rgb24, daguerre::encode>( + framebuffer, old_mouse_x + x, old_mouse_y + y, burden, + old_mouse_x, old_mouse_y, pointer.width, pointer.height); + daguerre::overlay_region< + daguerre::hilbert_color, daguerre::rgb24, overlay_encode>( + framebuffer, new_mouse_x + x, new_mouse_y + y, + pointer, 0, 0, pointer.width, pointer.height); + } + } } diff --git a/documentation/keys.txt b/documentation/kernel-interface/keys.txt index 1b92afa..1b92afa 100644 --- a/documentation/keys.txt +++ b/documentation/kernel-interface/keys.txt diff --git a/documentation/sockets.txt b/documentation/kernel-interface/sockets.txt index 73dade6..73dade6 100644 --- a/documentation/sockets.txt +++ b/documentation/kernel-interface/sockets.txt diff --git a/documentation/syscalls.txt b/documentation/kernel-interface/syscalls.txt index 52e909d..792c300 100644 --- a/documentation/syscalls.txt +++ b/documentation/kernel-interface/syscalls.txt @@ -63,9 +63,19 @@ get new pages: rax out: start of first page the allocated pages are next to each other, writable, and not executable. -read key packet: +get input packet: rax in: 5 - eax out: key packet + al out: + bit 7: was mouse packet + if bit 7: + bit 0: left mouse button down + bit 1: right mouse button down + bit 2: middle mouse button down + if bit 7: + di out: mouse x change (signed) + si out: mouse y change (signed) + else: + edi out: key packet create private socket: rax in: 6 diff --git a/euler/include/euler/syscall.hpp b/euler/include/euler/syscall.hpp index 9255642..761dbcc 100644 --- a/euler/include/euler/syscall.hpp +++ b/euler/include/euler/syscall.hpp @@ -58,4 +58,17 @@ extern "C" uint32_t *__euler_get_framebuffer( extern "C" uint32_t __euler_encode_color(uint8_t r, uint8_t g, uint8_t b); -extern "C" uint32_t __euler_read_key_packet(); +enum __euler_mouse_buttons : uint8_t { + __EULER_MB_LEFT = 1, + __EULER_MB_RIGHT = 2, + __EULER_MB_MIDDLE = 4 +}; + +enum __euler_input_packet_type : uint8_t { + __EULER_IPT_MOUSE = 1, + __EULER_IPT_KEYBOARD = 2 +}; + +extern "C" __euler_input_packet_type __euler_get_input_packet( + __euler_mouse_buttons &buttons_out, int16_t &x_change_out, + int16_t &y_change_out, uint32_t &keyboard_packet_out); diff --git a/euler/source/euler/syscall.asm b/euler/source/euler/syscall.asm index 34f2735..41bd05c 100644 --- a/euler/source/euler/syscall.asm +++ b/euler/source/euler/syscall.asm @@ -11,7 +11,7 @@ global __euler_end_this_thread global __euler_read_from_stream global __euler_get_framebuffer global __euler_encode_color -global __euler_read_key_packet +global __euler_get_input_packet section .text @@ -96,7 +96,31 @@ __euler_encode_color: syscall ret -__euler_read_key_packet: +__euler_get_input_packet: + push rdi + push rsi + push rdx + push rcx mov rax, 5 syscall + + test al, 0x80 + jnz .mouse_packet + + pop rcx + mov dword [rcx], edi + add rsp, 24 + mov al, 2 + ret + +.mouse_packet: + add rsp, 8 + pop rdx + mov word [rdx], si + pop rdx + mov word [rdx], di + pop rdx + and al, 0x7f + mov byte [rdx], al + mov al, 1 ret diff --git a/kernel/include/hilbert/kernel/input.hpp b/kernel/include/hilbert/kernel/input.hpp index 2209ddc..d1b7ca2 100644 --- a/kernel/include/hilbert/kernel/input.hpp +++ b/kernel/include/hilbert/kernel/input.hpp @@ -18,7 +18,26 @@ namespace hilbert::kernel::input { BREAK = 1 << 18, }; - extern utility::queue<uint32_t> *key_queue; + enum buttons_t : uint8_t { + LEFT_BUTTON = 1, + RIGHT_BUTTON = 2, + MIDDLE_BUTTON = 4 + }; + + struct input_packet { + union { + struct { + int16_t x_change; + int16_t y_change; + buttons_t buttons; + } mouse; + uint32_t keyboard; + }; + bool is_mouse; + }; + + extern utility::queue<input_packet> *input_queue; + //notify a process waiting for input void got_input(); diff --git a/kernel/include/hilbert/kernel/utility.hpp b/kernel/include/hilbert/kernel/utility.hpp index 47f78ea..c0b8c19 100644 --- a/kernel/include/hilbert/kernel/utility.hpp +++ b/kernel/include/hilbert/kernel/utility.hpp @@ -342,6 +342,11 @@ namespace hilbert::kernel::utility { return move(ret); } + //assumes not empty + value_t &last_inserted() const { + return buffer[(count - 1 + next_read_index) % buffer_len]; + } + }; } diff --git a/kernel/source/input.cpp b/kernel/source/input.cpp index 696cb13..921ae7b 100644 --- a/kernel/source/input.cpp +++ b/kernel/source/input.cpp @@ -5,10 +5,10 @@ namespace hilbert::kernel::input { - utility::queue<uint32_t> *key_queue; + utility::queue<input_packet> *input_queue; void init_input() { - key_queue = new utility::queue<uint32_t>(); + input_queue = new utility::queue<input_packet>(); } void got_input() { diff --git a/kernel/source/interrupts.asm b/kernel/source/interrupts.asm index babc020..e0c3cdb 100644 --- a/kernel/source/interrupts.asm +++ b/kernel/source/interrupts.asm @@ -227,14 +227,6 @@ section .bss section .text -write_keyboard_byte: - in al, 0x64 - test al, 0x02 - jnz write_keyboard_byte - mov al, dil - out 0x60, al - ret - extern on_keyboard_interrupt keyboard_isr: @@ -249,6 +241,7 @@ keyboard_isr: push rcx push rax + call wait_read_ps2 in al, 0x60 mov dil, al @@ -269,6 +262,54 @@ keyboard_isr: iretq +extern on_mouse_interrupt + +mouse_isr: + + push r11 + push r10 + push r9 + push r8 + push rsi + push rdi + push rdx + push rcx + push rax + + call wait_read_ps2 + in al, 0x60 + mov dil, al + + call on_mouse_interrupt + + mov al, 0x20 + out 0x20, al + out 0xa0, al + + pop rax + pop rcx + pop rdx + pop rdi + pop rsi + pop r8 + pop r9 + pop r10 + pop r11 + + iretq + +wait_send_ps2: + in al, 0x64 + test al, 0x02 + jnz wait_send_ps2 + ret + +wait_read_ps2: + in al, 0x64 + test al, 0x01 + jz wait_send_ps2 + ret + load_gdt_and_idt: ;fill exception entries in idt @@ -294,7 +335,7 @@ load_gdt_and_idt: out 0x21, al mov al, 0x01 out 0x21, al - mov al, 0xfd ;mask all but irq 1 + mov al, 0xf9 ;mask all but irq 1 and 2 out 0x21, al mov al, 0x11 @@ -305,19 +346,54 @@ load_gdt_and_idt: out 0xa1, al mov al, 0x01 out 0xa1, al - mov al, 0xff ;mask all + mov al, 0xef ;mask all but irq 12 out 0xa1, al + ;register keyboard and mouse interrupts + mov rdi, 0x21 mov rsi, keyboard_isr call set_isr - ;set keyboard config + mov rdi, 0x2c + mov rsi, mouse_isr + call set_isr + + ;set ps2 config + call wait_send_ps2 mov al, 0x60 out 0x64, al - mov dil, 0x01 - call write_keyboard_byte + + call wait_send_ps2 + mov al, 0x03 + out 0x60, al + + ;set mouse defaults + + call wait_send_ps2 + mov al, 0xd4 + out 0x64, al + + call wait_send_ps2 + mov al, 0xf6 + out 0x60, al + + call wait_read_ps2 + in al, 0x60 + + ;enable mouse reporting + + call wait_send_ps2 + mov al, 0xd4 + out 0x64, al + + call wait_send_ps2 + mov al, 0xf4 + out 0x60, al + + call wait_read_ps2 + in al, 0x60 ;make tss entry in gdt diff --git a/kernel/source/interrupts.cpp b/kernel/source/interrupts.cpp index 6e22121..9b6495e 100644 --- a/kernel/source/interrupts.cpp +++ b/kernel/source/interrupts.cpp @@ -1,3 +1,4 @@ +#include <hilbert/kernel/framebuffer.hpp> #include <hilbert/kernel/input.hpp> #include <hilbert/kernel/panic.hpp> @@ -54,7 +55,9 @@ static uint32_t current_flags = 0; static void got_key(uint32_t key) { - input::key_queue->insert(current_flags | key); + input::input_queue->insert({ + .keyboard = current_flags | key, .is_mouse = false}); + input::got_input(); if (key == (input::BREAK | 0x77)) @@ -90,7 +93,7 @@ static void got_key(uint32_t key) { } static uint8_t key_so_far[8]; -uint8_t key_so_far_len = 0; +static uint8_t key_so_far_len = 0; extern "C" void on_keyboard_interrupt(uint8_t byte) { @@ -150,3 +153,45 @@ extern "C" void on_keyboard_interrupt(uint8_t byte) { } } + +static uint8_t mouse_packet_so_far[3]; +static uint8_t mouse_packet_so_far_len = 0; + +extern "C" void on_mouse_interrupt(uint8_t byte) { + + if (mouse_packet_so_far_len == 0 && byte == 0xfa) + //dirty hack + return; + + mouse_packet_so_far[mouse_packet_so_far_len++] = byte; + if (mouse_packet_so_far_len < 3) + return; + + mouse_packet_so_far_len = 0; + + int16_t x_change = mouse_packet_so_far[1]; + int16_t y_change = -(int16_t)mouse_packet_so_far[2]; + if (mouse_packet_so_far[0] & 0x10) + x_change -= 0x100; + if (mouse_packet_so_far[0] & 0x20) + y_change += 0x100; + + input::input_packet packet = { + .mouse = { + .x_change = x_change, .y_change = y_change, + .buttons = (input::buttons_t)(mouse_packet_so_far[0] & 7) }, + .is_mouse = true }; + + if (input::input_queue->count > 0 && + input::input_queue->last_inserted().is_mouse && + input::input_queue->last_inserted().mouse.buttons == + packet.mouse.buttons) { + input::input_queue->last_inserted().mouse.x_change = packet.mouse.x_change; + input::input_queue->last_inserted().mouse.y_change = packet.mouse.y_change; + } + else + input::input_queue->insert(packet); + + input::got_input(); + +} diff --git a/kernel/source/syscall.cpp b/kernel/source/syscall.cpp index 768ff0d..5d9714c 100644 --- a/kernel/source/syscall.cpp +++ b/kernel/source/syscall.cpp @@ -157,7 +157,7 @@ namespace hilbert::kernel::syscall { } - void read_key_packet_syscall( + void get_input_packet_syscall( uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx ) { @@ -165,8 +165,17 @@ namespace hilbert::kernel::syscall { auto *t = application::running_thread; do - if (input::key_queue->count > 0) { - rax = (uint64_t)input::key_queue->take(); + if (input::input_queue->count > 0) { + input::input_packet packet = input::input_queue->take(); + if (packet.is_mouse) { + rax = packet.mouse.buttons | 0x80; + rdi = (uint16_t)packet.mouse.x_change; + rsi = (uint16_t)packet.mouse.y_change; + } + else { + rax = 0; + rdi = packet.keyboard; + } return; } while (application::save_thread_state(t->cpu)); @@ -504,7 +513,7 @@ namespace hilbert::kernel::syscall { &open_file_syscall, &end_this_thread_syscall, &get_new_pages_syscall, - &read_key_packet_syscall, + &get_input_packet_syscall, &create_private_socket_syscall, &create_socket_listener_syscall, &stop_socket_listener_syscall, @@ -520,7 +529,7 @@ namespace hilbert::kernel::syscall { &set_stream_length_syscall }; - static constexpr int max_syscall_number = 18; + static constexpr int max_syscall_number = 19; } diff --git a/libraries/daguerre/include/daguerre.hpp b/libraries/daguerre/include/daguerre.hpp index 274e257..62d10f0 100644 --- a/libraries/daguerre/include/daguerre.hpp +++ b/libraries/daguerre/include/daguerre.hpp @@ -1,6 +1,7 @@ #pragma once #include <stdint.h> +#include <cstring> #include <cstdio> namespace daguerre { @@ -13,14 +14,6 @@ namespace daguerre { uint8_t b; }; - template <class to_type, class from_type> - to_type convert_color(const from_type &from); - - template <> - inline hilbert_color convert_color<hilbert_color, rgb24>(const rgb24 &from) { - return __euler_encode_color(from.r, from.g, from.b); - } - template <class color_t> class image { @@ -88,15 +81,15 @@ namespace daguerre { //from [from_x, from_x + width) x [from_y, from_y + height). template <class color_t> void copy_region( - image<color_t> &to, const image<color_t> &from, unsigned from_x, - unsigned from_y, unsigned to_x, unsigned to_y, unsigned width, - unsigned height) { + image<color_t> &to, unsigned to_x, unsigned to_y, + const image<color_t> &from, unsigned from_x, unsigned from_y, + unsigned width, unsigned height) { color_t *to_start = to.buffer + to.pitch * to_y + to_x; const color_t *from_start = from.buffer + from.pitch * from_y + from_x; for (unsigned y = 0; y < height; ++y) - memcpy( + std::memcpy( to_start + to.pitch * y, from_start + from.pitch * y, width * sizeof(color_t)); @@ -107,12 +100,11 @@ namespace daguerre { //from [from_x, from_x + width) x [from_y, from_y + height). template < class to_color_t, class from_color_t, - to_color_t converter(const from_color_t &) = - convert_color<to_color_t, from_color_t>> - void copy_region( - image<to_color_t> &to, const image<from_color_t> &from, unsigned from_x, - unsigned from_y, unsigned to_x, unsigned to_y, unsigned width, - unsigned height) { + void overlay(to_color_t &dest, const from_color_t &src)> + void overlay_region( + image<to_color_t> &to, unsigned to_x, unsigned to_y, + const image<from_color_t> &from, unsigned from_x, unsigned from_y, + unsigned width, unsigned height) { to_color_t *to_start = to.buffer + to.pitch * to_y + to_x; const from_color_t *from_start = @@ -120,8 +112,12 @@ namespace daguerre { for (unsigned y = 0; y < height; ++y) for (unsigned x = 0; x < width; ++x) - to_start[to.pitch * y + x] = converter(from_start[from.pitch * y + x]); + overlay(to_start[to.pitch * y + x], from_start[from.pitch * y + x]); + + } + static inline void encode(hilbert_color &dest, const rgb24 &src) { + dest = __euler_encode_color(src.r, src.g, src.b); } image<hilbert_color> get_hilbert_framebuffer(); diff --git a/libraries/daguerre/source/daguerre.cpp b/libraries/daguerre/source/daguerre.cpp index fb3ddc7..7c13a88 100644 --- a/libraries/daguerre/source/daguerre.cpp +++ b/libraries/daguerre/source/daguerre.cpp @@ -8,15 +8,22 @@ namespace daguerre { return image<hilbert_color>(ptr, width, height, pitch, false); } + //TODO: make this more robust unsigned read_text_int(std::FILE *input) { unsigned n = 0; char ch; - while (true) { + std::fread(&ch, 1, 1, input); + if (ch == '#') { + do + std::fread(&ch, 1, 1, input); + while (ch != '\n'); std::fread(&ch, 1, 1, input); - if (ch < '0' || ch > '9') - return n; - n = n * 10 + ch - '0'; } + do { + n = n * 10 + ch - '0'; + std::fread(&ch, 1, 1, input); + } while (ch >= '0' && ch <= '9'); + return n; } bool try_load_ppm(std::FILE *input, image<rgb24> &into) { diff --git a/skeleton/assets/pointer.ppm b/skeleton/assets/pointer.ppm Binary files differnew file mode 100644 index 0000000..7169033 --- /dev/null +++ b/skeleton/assets/pointer.ppm diff --git a/skeleton/assets/readme.txt b/skeleton/assets/readme.txt index 56b1a9b..72476c5 100644 --- a/skeleton/assets/readme.txt +++ b/skeleton/assets/readme.txt @@ -2,3 +2,5 @@ the photo in burden.ppm is "selective focus photography snowflakes" by aaron burden. it can be found online at https://unsplash.com/photos/selective-focus-photography-snowflakes-9yhy1FXlKwI. its license can be found online at https://unsplash.com/license. + +the icon in pointer.ppm is by me :) |