use rt::os::{syscall6, SYS_MMAP, SYS_MUNMAP};
use super::proto::*;
use super::wire::{sys_close, Args, A};
use super::xkb::{wl_mods, wl_mods_set, xkb_dead_reset, xkb_dump, xkb_is_dead, xkb_is_modifier, xkb_key, xkb_key_typed,
xkb_mod_bit, xkb_parse, xkb_set_mods, xkb_use_fallback};
use super::Wl;
use crate::{
Event, BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, BTN_X1, BTN_X2, E_DOWN, E_FOCUS_IN, E_FOCUS_OUT, E_KEY_DOWN, E_KEY_UP,
E_LEAVE, E_MOVE, E_TEXT, E_UP, E_WHEEL, PW_MAX,
};
const BTN_CODE_LEFT: u32 = 0x110;
static BTN_MAP: [u8; 7] = [BTN_LEFT, BTN_RIGHT, BTN_MIDDLE, BTN_X1, BTN_X2, BTN_X2, BTN_X1];
pub(crate) const FINGERS: usize = 10;
pub(crate) const FINGER_TOOL: i32 = 1000;
#[derive(Clone, Copy, Default)]
pub(crate) struct Finger {
pub used: bool,
id: i32, pub win: i32,
off: [i32; 2], pub at: [i32; 2], }
pub(crate) struct Input {
pub ptr: u32, pub kb: u32, pub touch: u32, pub fingers: [Finger; FINGERS],
touch_clock: Option<i32>,
pub csd: u32, pub enter_serial: u32,
pub btn_serial: u32,
pub input_serial: u32,
pub ptr_in: bool,
pub mx: i32,
pub my: i32,
btn_mask: u32,
pub kb_focus: bool,
pub kb_win: i32, pub kb_child: i32, pub evwin: i32, pub ptr_win: i32, pub off_x: i32, pub off_y: i32,
pub s120_test: i32, kb_ready: bool,
rep_key: u32, rep_next: u64,
rep_rate: i32,
rep_delay: i32,
ax_val: [i32; 2], ax_disc: [i32; 2],
ax_120: [i32; 2],
ax_flags: u32, }
impl Input {
pub fn new() -> Input {
Input {
ptr: 0,
kb: 0,
touch: 0,
fingers: [Finger { used: false, id: 0, win: 0, off: [0; 2], at: [0; 2] }; FINGERS],
touch_clock: None,
csd: 0,
enter_serial: 0,
btn_serial: 0,
input_serial: 0,
ptr_in: false,
mx: 0,
my: 0,
btn_mask: 0,
kb_focus: false,
kb_win: 0,
kb_child: -1,
evwin: 0,
ptr_win: -1,
off_x: 0,
off_y: 0,
s120_test: 0,
kb_ready: false,
rep_key: 0,
rep_next: 0,
rep_rate: 25,
rep_delay: 600,
ax_val: [0; 2],
ax_disc: [0; 2],
ax_120: [0; 2],
ax_flags: 0,
}
}
}
impl Wl {
pub(crate) fn push(&mut self, typ: u8, btn: u8, x: i32, y: i32, data: u32) {
let win = (self.inp.evwin as u32 & (PW_MAX as u32 - 1)) as u8;
crate::evq_push(Event { typ, btn, mods: wl_mods() as u8, win, x, y, data });
}
fn ptr_evwin(&mut self) {
self.inp.evwin = self.inp.ptr_win.max(0);
}
fn ptr_px(&self, fixed: i32) -> i32 {
let w = self.inp.ptr_win.max(0) as usize & (PW_MAX - 1);
let r = &self.win[w];
let s = if r.flags & super::window::WLWF_USED != 0 { r.s120 } else { self.inp.s120_test };
(fixed as i64 * s as i64 / 30720) as i32
}
pub(crate) fn left_held(&self) -> bool {
self.inp.btn_mask & 1 << BTN_LEFT != 0
}
pub(crate) fn held_buttons(&self) -> u32 {
self.inp.btn_mask
}
pub(crate) fn ptr_px_of(&self, w: usize, fixed: i32) -> i32 {
let s = self.win[w & (PW_MAX - 1)].s120.max(1);
(fixed as i64 * s as i64 / 30720) as i32
}
pub(crate) fn release_buttons(&mut self) {
self.ptr_evwin();
for b in 1..=5u8 {
if self.inp.btn_mask & 1 << b != 0 {
self.inp.btn_mask &= !(1 << b);
let (x, y) = (self.inp.mx, self.inp.my);
self.push(E_UP, b, x, y, 0);
}
}
}
pub(crate) fn input_service(&mut self, now: u64) -> u64 {
if self.inp.rep_key == 0 {
return u64::MAX;
}
if !self.inp.kb_focus {
self.inp.rep_key = 0;
return u64::MAX;
}
if now < self.inp.rep_next {
return self.inp.rep_next;
}
self.inp.evwin = self.kb_target();
let (vk, text) = xkb_key(self.inp.rep_key - 1);
if vk != 0 {
self.push(E_KEY_DOWN, 0, 0, 0, vk | 0x8000_0000);
}
if text != 0 {
self.push(E_TEXT, 0, 0, 0, text);
}
if self.inp.rep_rate <= 0 {
self.inp.rep_key = 0;
return u64::MAX;
}
let iv = (1_000_000 / self.inp.rep_rate as u32) as u64;
let mut next = self.inp.rep_next + iv;
if next <= now {
next = now + iv; }
self.inp.rep_next = next;
next
}
}
pub(crate) fn wlh_seat_caps(wl: &mut Wl, _id: u32, a: &Args, _u: u64) {
let caps = a.u(0);
if caps & 1 != 0 {
if wl.inp.ptr == 0 {
let p = wl.w.send(wl.g.seat, &SEAT_GET_POINTER, &[A::N(&IFACE_WL_POINTER)]);
wl.inp.ptr = p;
if wl.g.csm != 0 {
wl.inp.csd = wl.w.send(wl.g.csm, &CSM_GET_POINTER, &[A::N(&IFACE_WP_CSD), A::O(p)]);
}
}
} else if wl.inp.ptr != 0 {
let p = wl.inp.ptr;
wl.inp.ptr = 0;
wl.inp.ptr_in = false;
if wl.g.seat_ver >= 3 {
wl.w.send(p, &POINTER_RELEASE, &[]);
}
}
if caps & 4 != 0 {
if wl.inp.touch == 0 {
wl.inp.touch = wl.w.send(wl.g.seat, &SEAT_GET_TOUCH, &[A::N(&IFACE_WL_TOUCH)]);
}
} else if wl.inp.touch != 0 {
let t = wl.inp.touch;
wl.inp.touch = 0;
wl.fingers_cancel();
if wl.g.seat_ver >= 3 {
wl.w.send(t, &TOUCH_RELEASE, &[]);
}
}
if caps & 2 != 0 {
if wl.inp.kb == 0 {
wl.inp.kb = wl.w.send(wl.g.seat, &SEAT_GET_KEYBOARD, &[A::N(&IFACE_WL_KEYBOARD)]);
}
} else if wl.inp.kb != 0 {
let k = wl.inp.kb;
wl.inp.kb = 0;
wl.inp.rep_key = 0;
if wl.g.seat_ver >= 3 {
wl.w.send(k, &KEYBOARD_RELEASE, &[]);
}
}
}
impl Wl {
fn finger_px(&self, w: usize, fixed: i32) -> i32 {
let r = &self.win[w & (PW_MAX - 1)];
let s = if r.flags & super::window::WLWF_USED != 0 { r.s120 } else { self.inp.s120_test };
(fixed as i64 * s as i64 / 30720) as i32
}
fn finger_slot(&self, id: i32) -> Option<usize> {
self.inp.fingers.iter().position(|f| f.used && f.id == id)
}
fn finger_push(&mut self, k: usize, phase: crate::FingerPhase, age: u32) {
let f = self.inp.fingers[k];
let win = (f.win as u32 & (PW_MAX as u32 - 1)) as u8;
let mut e = crate::finger_event(win, phase, k as u8, f.at[0], f.at[1], age);
e.mods = wl_mods() as u8;
crate::evq_push(e);
}
pub(crate) fn finger_on(&self, w: usize) -> Option<(usize, i32, i32)> {
self.inp.fingers.iter().position(|f| f.used && f.win == w as i32).map(|k| (k, self.inp.fingers[k].at[0], self.inp.fingers[k].at[1]))
}
pub(crate) fn fingers_cancel(&mut self) {
if self.drag.on && self.drag.tool >= FINGER_TOOL {
self.child_drag_end();
}
for k in 0..FINGERS {
if self.inp.fingers[k].used {
self.finger_push(k, crate::FingerPhase::Cancel, 0);
self.inp.fingers[k].used = false;
}
}
}
}
pub(crate) fn wlh_touch_down(wl: &mut Wl, _id: u32, a: &Args, _u: u64) {
let surf = a.u(2);
let mut w = wl.find(surf);
let mut off = [0; 2];
if w < 0 {
let (px, py) = (wl.inp.off_x, wl.inp.off_y);
w = wl.popup_ptr(surf);
off = [wl.inp.off_x, wl.inp.off_y];
wl.inp.off_x = px;
wl.inp.off_y = py;
if w < 0 {
return;
}
}
wl.inp.btn_serial = a.u(0);
wl.inp.input_serial = a.u(0);
let id = a.i(3);
if let Some(k) = wl.finger_slot(id) {
wl.finger_push(k, crate::FingerPhase::Cancel, 0); wl.inp.fingers[k].used = false;
}
let Some(k) = wl.inp.fingers.iter().position(|f| !f.used) else { return };
let at = [wl.finger_px(w as usize, a.i(4)) + off[0], wl.finger_px(w as usize, a.i(5)) + off[1]];
wl.inp.fingers[k] = Finger { used: true, id, win: w, off, at };
wl.child_press(w, at[0], at[1]); let age = crate::evq::finger_age(&mut wl.inp.touch_clock, a.u(1));
wl.finger_push(k, crate::FingerPhase::Down, age);
}
pub(crate) fn wlh_touch_up(wl: &mut Wl, _id: u32, a: &Args, _u: u64) {
let Some(k) = wl.finger_slot(a.i(2)) else { return };
if wl.drag.on && wl.drag.tool == FINGER_TOOL + k as i32 {
wl.child_drag_end();
}
let age = crate::evq::finger_age(&mut wl.inp.touch_clock, a.u(1));
wl.finger_push(k, crate::FingerPhase::Up, age);
wl.inp.fingers[k].used = false;
}
pub(crate) fn wlh_touch_motion(wl: &mut Wl, _id: u32, a: &Args, _u: u64) {
let Some(k) = wl.finger_slot(a.i(1)) else { return };
let f = wl.inp.fingers[k];
let w = f.win as usize;
let at = [wl.finger_px(w, a.i(2)) + f.off[0], wl.finger_px(w, a.i(3)) + f.off[1]];
wl.inp.fingers[k].at = at;
if wl.drag.on && wl.drag.tool == FINGER_TOOL + k as i32 {
wl.child_drag_motion(f.win, at[0], at[1]); return;
}
let age = crate::evq::finger_age(&mut wl.inp.touch_clock, a.u(0));
wl.finger_push(k, crate::FingerPhase::Move, age);
}
pub(crate) fn wlh_touch_cancel(wl: &mut Wl, _id: u32, _a: &Args, _u: u64) {
wl.fingers_cancel();
}
pub(crate) fn wlh_ptr_enter(wl: &mut Wl, _id: u32, a: &Args, _u: u64) {
wl.inp.enter_serial = a.u(0);
wl.inp.off_x = 0;
wl.inp.off_y = 0;
wl.popup_ptr_reset();
let surf = a.u(1);
let mut w = wl.find(surf);
if w < 0 {
w = wl.popup_ptr(surf); if w < 0 {
return;
}
}
wl.inp.ptr_win = w;
wl.inp.evwin = w;
wl.inp.ptr_in = true;
wl.inp.mx = wl.ptr_px(a.i(2)) + wl.inp.off_x;
wl.inp.my = wl.ptr_px(a.i(3)) + wl.inp.off_y;
wl.cursor_apply();
let (x, y) = (wl.inp.mx, wl.inp.my);
wl.push(E_MOVE, 0, x, y, 0);
}
pub(crate) fn wlh_ptr_leave(wl: &mut Wl, _id: u32, _a: &Args, _u: u64) {
if wl.drag.on && wl.drag.tool < 0 {
wl.child_drag_end(); }
if !wl.inp.ptr_in {
return;
}
wl.inp.ptr_in = false;
wl.release_buttons();
wl.ptr_evwin();
wl.push(E_LEAVE, 0, 0, 0, 0);
wl.inp.ptr_win = -1;
}
pub(crate) fn wlh_ptr_motion(wl: &mut Wl, _id: u32, a: &Args, _u: u64) {
wl.inp.mx = wl.ptr_px(a.i(1)) + wl.inp.off_x; wl.inp.my = wl.ptr_px(a.i(2)) + wl.inp.off_y;
if wl.drag.on && wl.drag.tool < 0 {
let (x, y) = (wl.inp.mx, wl.inp.my);
wl.child_drag_ptr_motion(x, y); return;
}
wl.ptr_evwin();
let (x, y) = (wl.inp.mx, wl.inp.my);
wl.push(E_MOVE, 0, x, y, 0);
}
pub(crate) fn wlh_ptr_button(wl: &mut Wl, _id: u32, a: &Args, _u: u64) {
wl.inp.btn_serial = a.u(0);
wl.inp.input_serial = a.u(0);
let b = a.u(2).wrapping_sub(BTN_CODE_LEFT);
if wl.drag.on && wl.drag.tool < 0 {
if a.u(3) == 0 && b <= 6 && wl.drag.btns & 1 << BTN_MAP[b as usize] != 0 {
wl.child_drag_end();
} else {
wl.drag.other = true; }
return;
}
if b > 6 {
return;
}
let btn = BTN_MAP[b as usize];
let typ = if a.u(3) != 0 {
wl.inp.btn_mask |= 1 << btn;
let (w, x, y) = (wl.inp.ptr_win, wl.inp.mx, wl.inp.my);
wl.child_press(w, x, y); E_DOWN
} else {
if wl.inp.btn_mask & 1 << btn == 0 {
return; }
wl.inp.btn_mask &= !(1 << btn);
E_UP
};
wl.ptr_evwin();
let (x, y) = (wl.inp.mx, wl.inp.my);
wl.push(typ, btn, x, y, 0);
}
pub(crate) fn wlh_ptr_axis(wl: &mut Wl, id: u32, a: &Args, u: u64) {
let ax = a.u(1);
if ax > 1 {
return;
}
wl.inp.ax_val[ax as usize] = wl.inp.ax_val[ax as usize].wrapping_add(a.i(2));
if wl.g.seat_ver < 5 {
wlh_ptr_frame(wl, id, a, u); }
}
pub(crate) fn wlh_ptr_discrete(wl: &mut Wl, _id: u32, a: &Args, _u: u64) {
let ax = a.u(0);
if ax > 1 {
return;
}
wl.inp.ax_disc[ax as usize] = wl.inp.ax_disc[ax as usize].wrapping_add(a.i(1));
wl.inp.ax_flags |= 1 << ax;
}
pub(crate) fn wlh_ptr_value120(wl: &mut Wl, _id: u32, a: &Args, _u: u64) {
let ax = a.u(0);
if ax > 1 {
return;
}
wl.inp.ax_120[ax as usize] = wl.inp.ax_120[ax as usize].wrapping_add(a.i(1));
wl.inp.ax_flags |= 1 << (ax + 2);
}
pub(crate) fn wlh_ptr_frame(wl: &mut Wl, _id: u32, _a: &Args, _u: u64) {
if wl.drag.on && wl.drag.tool < 0 {
let wheel = wl.inp.ax_flags != 0 || wl.inp.ax_val != [0; 2];
wl.child_drag_frame(wheel);
}
let mut d = [0i32; 2]; for ax in 0..2 {
let f = wl.inp.ax_flags;
let v = if f & 1 << (ax + 2) != 0 {
wl.inp.ax_120[ax]
} else if f & 1 << ax != 0 {
wl.inp.ax_disc[ax].wrapping_mul(120)
} else {
((wl.inp.ax_val[ax] as i64 * 12) >> 8) as i32
};
let v = v.clamp(-32767, 32767);
d[ax] = if ax == 0 { -v } else { v }; }
wl.inp.ax_flags = 0;
wl.inp.ax_val = [0; 2];
wl.inp.ax_disc = [0; 2];
wl.inp.ax_120 = [0; 2];
if d[0] | d[1] == 0 {
return;
}
let data = (d[0] as u32 & 0xFFFF) | (d[1] as u32) << 16;
wl.ptr_evwin();
let (x, y) = (wl.inp.mx, wl.inp.my);
wl.push(E_WHEEL, 0, x, y, data);
}
pub(crate) fn wlh_kb_keymap(wl: &mut Wl, _id: u32, a: &Args, _u: u64) {
let fmt = a.u(0);
let fd = a.u(1) as i32;
let size = a.u(2) as usize;
wl.inp.kb_ready = true;
let mut ok = false;
if fmt == 1 && size != 0 {
let p = unsafe { syscall6(SYS_MMAP, 0, size, 1, 2, fd as u32 as usize, 0) };
if !(-4095..0).contains(&p) {
let text = unsafe { core::slice::from_raw_parts(p as *const u8, size) };
ok = xkb_parse(text) == 0;
unsafe { syscall6(SYS_MUNMAP, p as usize, size, 0, 0, 0, 0) };
}
}
if !ok {
crate::write_stderr(b"wayland: keymap not usable, using the built-in US layout\n");
xkb_use_fallback();
}
sys_close(fd);
if crate::env("jfgui_XKBDUMP").is_some() {
xkb_dump();
}
}
pub(crate) fn wlh_kb_enter(wl: &mut Wl, _id: u32, a: &Args, _u: u64) {
wl.inp.input_serial = a.u(0);
let w = wl.find(a.u(1));
if w < 0 {
return;
}
wl.inp.kb_win = w;
wl.inp.evwin = wl.kb_target();
wl.inp.kb_focus = true;
wl.push(E_FOCUS_IN, 0, 0, 0, 0);
}
pub(crate) fn wlh_kb_leave(wl: &mut Wl, _id: u32, _a: &Args, _u: u64) {
xkb_dead_reset();
wl.inp.kb_focus = false;
wl.inp.rep_key = 0;
wl.inp.evwin = wl.kb_target();
wl.push(E_FOCUS_OUT, 0, 0, 0, 0);
}
pub(crate) fn wlh_kb_key(wl: &mut Wl, _id: u32, a: &Args, _u: u64) {
wl.inp.input_serial = a.u(0);
let key = a.u(2); let down = a.u(3) != 0;
if key >= 256 {
return;
}
if !wl.inp.kb_ready {
wl.inp.kb_ready = true;
xkb_use_fallback();
}
let mb = xkb_mod_bit(key);
if mb != 0 {
wl_mods_set(if down { wl_mods() | mb } else { wl_mods() & !mb });
}
wl.inp.evwin = wl.kb_target();
if down {
let dead = xkb_is_dead(key);
let (vk, text) = xkb_key_typed(key); if vk != 0 {
wl.push(E_KEY_DOWN, 0, 0, 0, vk);
}
for t in text.into_iter().filter(|&t| t != 0) {
wl.push(E_TEXT, 0, 0, 0, t);
}
if dead {
wl.inp.rep_key = 0; } else if !xkb_is_modifier(key) && wl.inp.rep_rate > 0 {
wl.inp.rep_key = key + 1;
wl.inp.rep_next = crate::time_us() + (wl.inp.rep_delay as u32).wrapping_mul(1000) as u64;
}
} else {
let (vk, _) = xkb_key(key);
if key + 1 == wl.inp.rep_key {
wl.inp.rep_key = 0;
}
if vk != 0 {
wl.push(E_KEY_UP, 0, 0, 0, vk);
}
}
}
pub(crate) fn wlh_kb_modifiers(_wl: &mut Wl, _id: u32, a: &Args, _u: u64) {
xkb_set_mods(a.u(1), a.u(2), a.u(3), a.u(4));
}
pub(crate) fn wlh_kb_repeat(wl: &mut Wl, _id: u32, a: &Args, _u: u64) {
wl.inp.rep_rate = a.i(0).clamp(0, 1000); wl.inp.rep_delay = a.i(1).clamp(0, 60_000);
}