Get keyboard events from window manager IPC instead of syscalls, fix ipc

read memory leak, remove debug prints in request_window, add kill
syscall, update SHM base, add window title arg
This commit is contained in:
csd4ni3l 2026-05-30 18:58:01 +02:00
commit 04e87c6099
6 changed files with 85 additions and 286 deletions

View file

@ -9,7 +9,7 @@ typedef struct Window {
uint64_t shm_id;
} Window;
Window request_window(size_t width, size_t height);
Window request_window(size_t width, size_t height, const char* title);
int draw_buffer_to_window(
const uint32_t* buffer,

View file

@ -1,7 +1,6 @@
use crate::{
print,
syscall::{INPUT_READ, syscall2},
};
use alloc::{format, vec::Vec};
use crate::{getpid, io::ipc::read_port_rust};
pub const KEY_RESERVED: u8 = 0;
pub const KEY_ESC: u8 = 1;
@ -93,175 +92,6 @@ pub const KEY_LEFT: u8 = 105;
pub const KEY_RIGHT: u8 = 106;
pub const KEY_DOWN: u8 = 108;
pub struct Mouse {
pub left_button_pressed: bool,
pub right_button_pressed: bool,
pub middle_button_pressed: bool,
pub x_delta: i16,
pub y_delta: i16,
}
impl Mouse {
const fn new() -> Mouse {
Mouse {
left_button_pressed: false,
right_button_pressed: false,
middle_button_pressed: false,
x_delta: 0,
y_delta: 0,
}
}
pub fn button_state(&self) -> (bool, bool, bool) {
(
self.left_button_pressed,
self.right_button_pressed,
self.middle_button_pressed,
)
}
pub fn take_motion(&mut self) -> (i16, i16) {
let old_x_delta = self.x_delta.clone();
let old_y_delta = self.y_delta.clone();
self.x_delta = 0;
self.y_delta = 0;
(old_x_delta, old_y_delta)
}
}
pub const KEY_TO_CHAR: [Option<(char, char)>; 84] = [
None, // 0 KEY_RESERVED
Some(('\x1b', '\x1b')), // 1 KEY_ESC
Some(('1', '!')), // 2 KEY_1
Some(('2', '@')), // 3 KEY_2
Some(('3', '#')), // 4 KEY_3
Some(('4', '$')), // 5 KEY_4
Some(('5', '%')), // 6 KEY_5
Some(('6', '^')), // 7 KEY_6
Some(('7', '&')), // 8 KEY_7
Some(('8', '*')), // 9 KEY_8
Some(('9', '(')), // 10 KEY_9
Some(('0', ')')), // 11 KEY_0
Some(('-', '_')), // 12 KEY_MINUS
Some(('=', '+')), // 13 KEY_EQUAL
Some(('\x08', '\x08')), // 14 KEY_BACKSPACE
Some(('\t', '\t')), // 15 KEY_TAB
Some(('q', 'Q')), // 16 KEY_Q
Some(('w', 'W')), // 17 KEY_W
Some(('e', 'E')), // 18 KEY_E
Some(('r', 'R')), // 19 KEY_R
Some(('t', 'T')), // 20 KEY_T
Some(('y', 'Y')), // 21 KEY_Y
Some(('u', 'U')), // 22 KEY_U
Some(('i', 'I')), // 23 KEY_I
Some(('o', 'O')), // 24 KEY_O
Some(('p', 'P')), // 25 KEY_P
Some(('[', '{')), // 26 KEY_LEFTBRACE
Some((']', '}')), // 27 KEY_RIGHTBRACE
Some(('\n', '\n')), // 28 KEY_ENTER
None, // 29 KEY_LEFTCTRL
Some(('a', 'A')), // 30 KEY_A
Some(('s', 'S')), // 31 KEY_S
Some(('d', 'D')), // 32 KEY_D
Some(('f', 'F')), // 33 KEY_F
Some(('g', 'G')), // 34 KEY_G
Some(('h', 'H')), // 35 KEY_H
Some(('j', 'J')), // 36 KEY_J
Some(('k', 'K')), // 37 KEY_K
Some(('l', 'L')), // 38 KEY_L
Some((';', ':')), // 39 KEY_SEMICOLON
Some(('\'', '"')), // 40 KEY_APOSTROPHE
Some(('`', '~')), // 41 KEY_GRAVE
None, // 42 KEY_LEFTSHIFT
Some(('\\', '|')), // 43 KEY_BACKSLASH
Some(('z', 'Z')), // 44 KEY_Z
Some(('x', 'X')), // 45 KEY_X
Some(('c', 'C')), // 46 KEY_C
Some(('v', 'V')), // 47 KEY_V
Some(('b', 'B')), // 48 KEY_B
Some(('n', 'N')), // 49 KEY_N
Some(('m', 'M')), // 50 KEY_M
Some((',', '<')), // 51 KEY_COMMA
Some(('.', '>')), // 52 KEY_DOT
Some(('/', '?')), // 53 KEY_SLASH
None, // 54 KEY_RIGHTSHIFT
Some(('*', '*')), // 55 KEY_KPASTERISK
None, // 56 KEY_LEFTALT
Some((' ', ' ')), // 57 KEY_SPACE
None, // 58 KEY_CAPSLOCK
None, // 59 KEY_F1
None, // 60 KEY_F2
None, // 61 KEY_F3
None, // 62 KEY_F4
None, // 63 KEY_F5
None, // 64 KEY_F6
None, // 65 KEY_F7
None, // 66 KEY_F8
None, // 67 KEY_F9
None, // 68 KEY_F10
None, // 69 KEY_NUMLOCK
None, // 70 KEY_SCROLLLOCK
Some(('7', '7')), // 71 KEY_KP7
Some(('8', '8')), // 72 KEY_KP8
Some(('9', '9')), // 73 KEY_KP9
Some(('-', '-')), // 74 KEY_KPMINUS
Some(('4', '4')), // 75 KEY_KP4
Some(('5', '5')), // 76 KEY_KP5
Some(('6', '6')), // 77 KEY_KP6
Some((('+'), '+')), // 78 KEY_KPPLUS
Some(('1', '1')), // 79 KEY_KP1
Some(('2', '2')), // 80 KEY_KP2
Some(('3', '3')), // 81 KEY_KP3
Some(('0', '0')), // 82 KEY_KP0
Some(('.', '.')), // 83 KEY_KPDOT
];
pub struct ModState {
shift: bool,
caps_lock: bool,
ctrl: bool,
alt: bool,
}
impl ModState {
pub const fn new() -> Self {
Self {
shift: false,
caps_lock: false,
ctrl: false,
alt: false,
}
}
pub fn update(&mut self, code: u8, value: u32) {
match code {
KEY_LEFTSHIFT | KEY_RIGHTSHIFT => self.shift = value != 0,
KEY_LEFTCTRL => self.ctrl = value != 0,
KEY_CAPSLOCK => self.caps_lock = value != 0,
KEY_LEFTALT => self.alt = value != 0,
_ => {}
}
}
pub fn effective_shift(&self) -> bool {
self.shift ^ self.caps_lock
}
}
pub fn keycode_to_char(keycode: u8, shift: bool) -> Option<char> {
let entry = KEY_TO_CHAR.get(keycode as usize)?.as_ref()?;
Some(if shift { entry.1 } else { entry.0 })
}
pub static mut MODIFIERS: ModState = ModState::new();
pub static mut MOUSE: Mouse = Mouse::new();
#[repr(C)]
#[derive(Clone, Copy)]
pub struct InputEvent {
pub event_type: u16,
pub code: u16,
pub value: u32,
}
#[repr(C)]
#[derive(Clone, Debug, Copy, Default)]
pub struct KeyboardEvent {
@ -273,93 +103,49 @@ pub struct KeyboardEvent {
pub unicode: u32,
}
pub const EVENT_KEY: u16 = 0x01;
pub const EVENT_REL: u16 = 0x02;
pub fn input_read(kbd_buf: *mut KeyboardEvent, _n: u8) -> usize {
let mut event_n = 0;
pub const BTN_LEFT: u16 = 0x110;
pub const BTN_RIGHT: u16 = 0x111;
pub const BTN_MIDDLE: u16 = 0x112;
if let Some((_, message)) = read_port_rust(format!("wm_priv_{}", getpid()), 1) {
let args: Vec<&str> = message.split_whitespace().collect();
let mut args_n = 0;
pub const REL_X: u16 = 0x00;
pub const REL_Y: u16 = 0x01;
pub const REL_WHEEL: u16 = 0x08;
while args_n < args.len() {
match args[args_n] {
"kbd" => {
if args_n + 4 < args.len() {
let key = args[args_n + 1].parse::<u16>().unwrap_or(0);
let mods = args[args_n + 2].parse::<u16>().unwrap_or(0);
let state = args[args_n + 3].parse::<u8>().unwrap_or(0);
let unicode = args[args_n + 4].parse::<u32>().unwrap_or(0);
#[allow(static_mut_refs)]
pub fn handle_event(event: &InputEvent) -> Option<KeyboardEvent> {
if event.event_type == 0 {
return None;
}
match event.event_type {
EVENT_KEY => {
unsafe { MODIFIERS.update(event.code as u8, event.value) };
match event.code {
BTN_LEFT => {
unsafe { MOUSE.left_button_pressed = event.value == 1 };
None
unsafe {
*kbd_buf.add(event_n) = KeyboardEvent {
state,
_pad1: 0,
key,
mods,
_pad2: 0,
unicode,
};
event_n += 1;
}
args_n += 5;
} else {
break;
}
}
BTN_RIGHT => {
unsafe { MOUSE.right_button_pressed = event.value == 1 };
None
"mouse" => {
args_n += 6;
}
BTN_MIDDLE => {
unsafe { MOUSE.middle_button_pressed = event.value == 1 };
None
_ => {
args_n += 1;
}
_ => Some(KeyboardEvent {
state: event.value as u8,
_pad1: 0,
key: event.code as u16,
mods: 0,
_pad2: 0,
unicode: keycode_to_char(event.code as u8, unsafe {
MODIFIERS.effective_shift()
})
.unwrap_or('\0') as u32,
}),
}
}
EVENT_REL => match event.code {
REL_X => {
unsafe { MOUSE.x_delta += event.value as i32 as i16 };
None
}
REL_Y => {
unsafe { MOUSE.y_delta += event.value as i32 as i16 };
None
}
REL_WHEEL => None,
_ => None,
},
_ => {
print("Could not recognize virtio input event from interrupt\n");
None
}
}
}
pub fn input_read(kbd_buf: *mut KeyboardEvent, n: u8) -> usize {
let mut input_buf = [InputEvent {
event_type: 0,
code: 0,
value: 0,
}; 32];
let n = n.min(32);
let len = unsafe { syscall2(INPUT_READ, input_buf.as_mut_ptr() as isize, n as isize) };
let mut current_event_n = 0;
for i in 0..len {
unsafe {
let event = *((input_buf.as_mut_ptr()).add(i as usize));
if let Some(keyboard_event) = handle_event(&event) {
*(kbd_buf.add(current_event_n)) = keyboard_event;
current_event_n += 1;
}
}
}
return current_event_n;
return event_n;
}
#[unsafe(no_mangle)]

View file

@ -1,12 +1,13 @@
use core::ffi::c_char;
use core::ffi::{CStr, c_char};
use alloc::{ffi::CString, string::String};
use alloc::{
ffi::CString,
string::{String, ToString},
vec,
};
use bitflags::bitflags;
use crate::{
mem::malloc,
syscall::{IPC_CREATE, IPC_MANAGE, IPC_READ, IPC_WRITE, syscall2, syscall3},
};
use crate::syscall::{IPC_CREATE, IPC_MANAGE, IPC_READ, IPC_WRITE, syscall2, syscall3};
bitflags! {
#[derive(Debug)]
@ -58,22 +59,18 @@ pub extern "C" fn read_port(name_ptr: *const u8, output_ptr: *mut u8, from: i64)
}
pub fn read_port_rust(name: String, from: i64) -> Option<(u64, String)> {
let name_cstring_opt = CString::new(name);
if let Ok(name_cstring) = name_cstring_opt {
let output_ptr = malloc(256);
return match read_port(name_cstring.as_ptr() as *const u8, output_ptr, from) {
-1 => None,
sender if sender > 0 => {
match unsafe { CString::from_raw(output_ptr as *mut c_char) }.into_string() {
Ok(rust_string) => Some((sender as u64, rust_string)),
_ => None,
}
}
_ => None,
};
} else {
let name_cstring = CString::new(name).ok()?;
let mut buf = vec![0u8; 256];
let sender = read_port(name_cstring.as_ptr() as *const u8, buf.as_mut_ptr(), from);
if sender <= 0 {
return None;
}
let cstr = unsafe { CStr::from_ptr(buf.as_ptr() as *const c_char) };
let msg = cstr.to_str().ok()?.to_string();
Some((sender as u64, msg))
}
#[unsafe(no_mangle)]

View file

@ -1,4 +1,7 @@
use core::ffi::c_char;
use alloc::{
ffi::CString,
format,
string::{String, ToString},
vec::Vec,
@ -10,7 +13,6 @@ use crate::{
ipc::{read_port_rust, write_port_rust},
time::sleep_ms,
},
println,
shm::{SHM_SLOT_SIZE, USER_SHM_BASE, shm_open_rust},
};
@ -26,18 +28,16 @@ pub struct Window {
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn request_window(width: usize, height: usize) -> Window {
pub unsafe extern "C" fn request_window(width: usize, height: usize, title: *mut c_char) -> Window {
let title = unsafe { CString::from_raw(title) };
write_port_rust("window_manager".to_string(), "request_priv_ipc".to_string());
let pid = getpid();
let priv_ipc_name = loop {
if let Some((sender, msg)) = read_port_rust(format!("wm_priv_{}", getpid()), -1) {
println!("{}: {}", sender, msg);
if let Some((_, msg)) = read_port_rust(format!("wm_priv_{}", getpid()), -1) {
if msg.starts_with("ack_request_priv_ipc") {
let parts = msg.split_whitespace().collect::<Vec<&str>>();
println!("{}", parts[1].trim().parse::<isize>().unwrap_or(-1) == pid);
if parts[1].trim().parse::<isize>().unwrap_or(-1) == pid {
break parts[2].to_string();
}
@ -47,15 +47,18 @@ pub unsafe extern "C" fn request_window(width: usize, height: usize) -> Window {
unsafe { sleep_ms(1) };
};
println!("Private IPC Name: {}", priv_ipc_name);
unsafe {
PRIV_IPC_NAME = Some(priv_ipc_name.clone());
}
write_port_rust(
priv_ipc_name.clone(),
format!("request_window_buf {} {}", width, height),
format!(
"request_window_buf {} {} {}",
title.to_str().unwrap_or("noname"),
width,
height
),
);
let (width, height, x, y, shm_name, shm_id) = loop {
@ -87,6 +90,14 @@ pub unsafe extern "C" fn request_window(width: usize, height: usize) -> Window {
}
}
pub unsafe fn request_window_rust(width: usize, height: usize, title: String) -> Window {
if let Ok(c_string) = CString::new(title) {
unsafe { request_window(width, height, c_string.as_ptr() as *mut c_char) }
} else {
panic!()
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn draw_buffer_to_window(
buffer: *const u32,

View file

@ -14,7 +14,7 @@ use core::{
use crate::{
heap::init_heap,
mem::{malloc, memcpy},
syscall::{EXIT, GETPID, WRITE, syscall0, syscall3},
syscall::{EXIT, GETPID, KILL, WRITE, syscall0, syscall1, syscall3},
};
pub mod graphics;
@ -691,6 +691,11 @@ pub unsafe extern "C" fn sscanf(str: *mut u8, fmt: *const u8, args: ...) -> i32
0
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn kill(pid: isize) -> isize {
unsafe { syscall1(KILL, pid) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn __errno_location() -> *mut core::ffi::c_int {
addr_of_mut!(ERRNO)

View file

@ -2,7 +2,7 @@ use alloc::{ffi::CString, string::String};
use crate::syscall::{SHM_OPEN, syscall2};
pub const USER_SHM_BASE: u64 = 0x0000_7000_0000_0000;
pub const USER_SHM_BASE: u64 = 0x0000_4000_0000_0000;
pub const SHM_SLOT_SIZE: u64 = 64 * 1024 * 1024;
#[unsafe(no_mangle)]