Files
RedBear-OS/ps2d/src/state.rs
T
bjorn3 c2fd9125a7 Fix absolute mouse events with vmmouse
It is no longer possible to query the display size from inputd, so defer
conversion to display pixel coordinates to orbital instead. This also
avoids a lot of work every mouse event to query the display size as
orbital saves this information already.
2024-01-12 18:31:08 +01:00

361 lines
14 KiB
Rust

use std::fs::File;
use std::io::Write;
use std::os::unix::io::AsRawFd;
use std::str;
use orbclient::{KeyEvent, MouseEvent, MouseRelativeEvent, ButtonEvent, ScrollEvent};
use crate::controller::Ps2;
use crate::vm;
bitflags! {
pub struct MousePacketFlags: u8 {
const LEFT_BUTTON = 1;
const RIGHT_BUTTON = 1 << 1;
const MIDDLE_BUTTON = 1 << 2;
const ALWAYS_ON = 1 << 3;
const X_SIGN = 1 << 4;
const Y_SIGN = 1 << 5;
const X_OVERFLOW = 1 << 6;
const Y_OVERFLOW = 1 << 7;
}
}
pub struct Ps2d<F: Fn(u8,bool) -> char> {
ps2: Ps2,
vmmouse: bool,
vmmouse_relative: bool,
input: File,
extended: bool,
lshift: bool,
rshift: bool,
mouse_x: i32,
mouse_y: i32,
mouse_left: bool,
mouse_middle: bool,
mouse_right: bool,
packets: [u8; 4],
packet_i: usize,
extra_packet: bool,
//Keymap function
get_char: F
}
impl<F: Fn(u8,bool) -> char> Ps2d<F> {
pub fn new(input: File, keymap: F) -> Self {
let mut ps2 = Ps2::new();
let extra_packet = ps2.init().expect("ps2d: failed to initialize");
let vmmouse_relative = true;
let vmmouse = vm::enable(vmmouse_relative);
Ps2d {
ps2,
vmmouse,
vmmouse_relative,
input,
extended: false,
lshift: false,
rshift: false,
mouse_x: 0,
mouse_y: 0,
mouse_left: false,
mouse_middle: false,
mouse_right: false,
packets: [0; 4],
packet_i: 0,
extra_packet,
get_char: keymap
}
}
pub fn irq(&mut self) {
while let Some((keyboard, data)) = self.ps2.next() {
self.handle(keyboard, data);
}
}
pub fn handle(&mut self, keyboard: bool, data: u8) {
if keyboard {
if data == 0xE0 {
self.extended = true;
} else {
let (ps2_scancode, pressed) = if data >= 0x80 {
(data - 0x80, false)
} else {
(data, true)
};
let scancode = if self.extended {
self.extended = false;
match ps2_scancode {
//TODO: media keys
//TODO: 0x1C => orbclient::K_NUM_ENTER,
//TODO: 0x1D => orbclient::K_RIGHT_CTRL,
0x20 => 0x80 + 0x20, //TODO: orbclient::K_VOLUME_MUTE,
0x2E => 0x80 + 0x2E, //TODO: orbclient::K_VOLUME_DOWN,
0x30 => 0x80 + 0x30, //TODO: orbclient::K_VOLUME_UP,
//TODO: 0x35 => orbclient::K_NUM_SLASH,
0x38 => orbclient::K_ALT_GR,
0x47 => orbclient::K_HOME,
0x48 => orbclient::K_UP,
0x49 => orbclient::K_PGUP,
0x4B => orbclient::K_LEFT,
0x4D => orbclient::K_RIGHT,
0x4F => orbclient::K_END,
0x50 => orbclient::K_DOWN,
0x51 => orbclient::K_PGDN,
//TODO: 0x52 => orbclient::K_INSERT,
0x53 => orbclient::K_DEL,
0x5B => 0x5B, //TODO: orbclient::K_LEFT_SUPER,
//TODO: 0x5C => orbclient::K_RIGHT_SUPER,
//TODO: 0x5D => orbclient::K_APP,
//TODO power keys
/* 0x80 to 0xFF used for press/release detection */
_ => {
if pressed {
println!("ps2d: unknown extended scancode {:02X}", ps2_scancode);
}
0
}
}
} else {
match ps2_scancode {
/* 0x00 unused */
0x01 => orbclient::K_ESC,
0x02 => orbclient::K_1,
0x03 => orbclient::K_2,
0x04 => orbclient::K_3,
0x05 => orbclient::K_4,
0x06 => orbclient::K_5,
0x07 => orbclient::K_6,
0x08 => orbclient::K_7,
0x09 => orbclient::K_8,
0x0A => orbclient::K_9,
0x0B => orbclient::K_0,
0x0C => orbclient::K_MINUS,
0x0D => orbclient::K_EQUALS,
0x0E => orbclient::K_BKSP,
0x0F => orbclient::K_TAB,
0x10 => orbclient::K_Q,
0x11 => orbclient::K_W,
0x12 => orbclient::K_E,
0x13 => orbclient::K_R,
0x14 => orbclient::K_T,
0x15 => orbclient::K_Y,
0x16 => orbclient::K_U,
0x17 => orbclient::K_I,
0x18 => orbclient::K_O,
0x19 => orbclient::K_P,
0x1A => orbclient::K_BRACE_OPEN,
0x1B => orbclient::K_BRACE_CLOSE,
0x1C => orbclient::K_ENTER,
0x1D => orbclient::K_CTRL,
0x1E => orbclient::K_A,
0x1F => orbclient::K_S,
0x20 => orbclient::K_D,
0x21 => orbclient::K_F,
0x22 => orbclient::K_G,
0x23 => orbclient::K_H,
0x24 => orbclient::K_J,
0x25 => orbclient::K_K,
0x26 => orbclient::K_L,
0x27 => orbclient::K_SEMICOLON,
0x28 => orbclient::K_QUOTE,
0x29 => orbclient::K_TICK,
0x2A => orbclient::K_LEFT_SHIFT,
0x2B => orbclient::K_BACKSLASH,
0x2C => orbclient::K_Z,
0x2D => orbclient::K_X,
0x2E => orbclient::K_C,
0x2F => orbclient::K_V,
0x30 => orbclient::K_B,
0x31 => orbclient::K_N,
0x32 => orbclient::K_M,
0x33 => orbclient::K_COMMA,
0x34 => orbclient::K_PERIOD,
0x35 => orbclient::K_SLASH,
0x36 => orbclient::K_RIGHT_SHIFT,
//TODO: 0x37 => orbclient::K_NUM_ASTERISK,
0x38 => orbclient::K_ALT,
0x39 => orbclient::K_SPACE,
0x3A => orbclient::K_CAPS,
0x3B => orbclient::K_F1,
0x3C => orbclient::K_F2,
0x3D => orbclient::K_F3,
0x3E => orbclient::K_F4,
0x3F => orbclient::K_F5,
0x40 => orbclient::K_F6,
0x41 => orbclient::K_F7,
0x42 => orbclient::K_F8,
0x43 => orbclient::K_F9,
0x44 => orbclient::K_F10,
//TODO: 0x45 => orbclient::K_NUM_LOCK,
//TODO: 0x46 => orbclient::K_SCROLL_LOCK,
0x47 => orbclient::K_NUM_7,
0x48 => orbclient::K_NUM_8,
0x49 => orbclient::K_NUM_9,
//TODO: 0x4A => orbclient::K_NUM_MINUS,
0x4B => orbclient::K_NUM_4,
0x4C => orbclient::K_NUM_5,
0x4D => orbclient::K_NUM_6,
//TODO: 0x4E => orbclient::K_NUM_PLUS,
0x4F => orbclient::K_NUM_1,
0x50 => orbclient::K_NUM_2,
0x51 => orbclient::K_NUM_3,
0x52 => orbclient::K_NUM_0,
//TODO: 0x53 => orbclient::K_NUM_PERIOD,
/* 0x54 to 0x56 unused */
0x57 => orbclient::K_F11,
0x58 => orbclient::K_F12,
/* 0x59 to 0x7F unused */
/* 0x80 to 0xFF used for press/release detection */
_ => {
if pressed {
println!("ps2d: unknown scancode {:02X}", ps2_scancode);
}
0
}
}
};
if scancode == orbclient::K_LEFT_SHIFT {
self.lshift = pressed;
} else if scancode == orbclient::K_RIGHT_SHIFT {
self.rshift = pressed;
}
if scancode != 0 {
self.input.write(&KeyEvent {
character: (self.get_char)(ps2_scancode, self.lshift || self.rshift),
scancode,
pressed
}.to_event()).expect("ps2d: failed to write key event");
}
}
} else if self.vmmouse {
for _i in 0..256 {
let (status, _, _, _, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_STATUS, 0) };
//TODO if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR)
let queue_length = status & 0xffff;
if queue_length == 0 {
break;
}
if queue_length % 4 != 0 {
eprintln!("ps2d: queue length not a multiple of 4: {}", queue_length);
break;
}
let (status, dx, dy, dz, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_DATA, 4) };
if self.vmmouse_relative {
if dx != 0 || dy != 0 {
self.input.write(&MouseRelativeEvent {
dx: dx as i32,
dy: dy as i32,
}.to_event()).expect("ps2d: failed to write mouse event");
}
} else {
let x = dx as i32;
let y = dy as i32;
if x != self.mouse_x || y != self.mouse_y {
self.mouse_x = x;
self.mouse_y = y;
self.input
.write(&MouseEvent { x, y }.to_event())
.expect("ps2d: failed to write mouse event");
}
};
if dz != 0 {
self.input.write(&ScrollEvent {
x: 0,
y: -(dz as i32),
}.to_event()).expect("ps2d: failed to write scroll event");
}
let left = status & vm::LEFT_BUTTON == vm::LEFT_BUTTON;
let middle = status & vm::MIDDLE_BUTTON == vm::MIDDLE_BUTTON;
let right = status & vm::RIGHT_BUTTON == vm::RIGHT_BUTTON;
if left != self.mouse_left || middle != self.mouse_middle || right != self.mouse_right {
self.mouse_left = left;
self.mouse_middle = middle;
self.mouse_right = right;
self.input.write(&ButtonEvent {
left: left,
middle: middle,
right: right,
}.to_event()).expect("ps2d: failed to write button event");
}
}
} else {
self.packets[self.packet_i] = data;
self.packet_i += 1;
let flags = MousePacketFlags::from_bits_truncate(self.packets[0]);
if ! flags.contains(MousePacketFlags::ALWAYS_ON) {
eprintln!("ps2d: mouse misalign {:X}", self.packets[0]);
self.packets = [0; 4];
self.packet_i = 0;
} else if self.packet_i >= self.packets.len() || (!self.extra_packet && self.packet_i >= 3) {
if ! flags.contains(MousePacketFlags::X_OVERFLOW) && ! flags.contains(MousePacketFlags::Y_OVERFLOW) {
let mut dx = self.packets[1] as i32;
if flags.contains(MousePacketFlags::X_SIGN) {
dx -= 0x100;
}
let mut dy = -(self.packets[2] as i32);
if flags.contains(MousePacketFlags::Y_SIGN) {
dy += 0x100;
}
let mut dz = 0;
if self.extra_packet {
let mut scroll = (self.packets[3] & 0xF) as i8;
if scroll & (1 << 3) == 1 << 3 {
scroll -= 16;
}
dz = -scroll as i32;
}
if dx != 0 || dy != 0 {
self.input.write(&MouseRelativeEvent {
dx: dx,
dy: dy,
}.to_event()).expect("ps2d: failed to write mouse event");
}
if dz != 0 {
self.input.write(&ScrollEvent {
x: 0,
y: dz,
}.to_event()).expect("ps2d: failed to write scroll event");
}
let left = flags.contains(MousePacketFlags::LEFT_BUTTON);
let middle = flags.contains(MousePacketFlags::MIDDLE_BUTTON);
let right = flags.contains(MousePacketFlags::RIGHT_BUTTON);
if left != self.mouse_left || middle != self.mouse_middle || right != self.mouse_right {
self.mouse_left = left;
self.mouse_middle = middle;
self.mouse_right = right;
self.input.write(&ButtonEvent {
left: left,
middle: middle,
right: right,
}.to_event()).expect("ps2d: failed to write button event");
}
} else {
eprintln!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]);
}
self.packets = [0; 4];
self.packet_i = 0;
}
}
}
}