// SPDX-License-Identifier: GPL-3.0-only /* * Copyright (c) 2024, Richard Acayan. All rights reserved. */ use core::Keyboard; use core::Layout; use core::Part; use core::xkeysym::Keysym; use std::collections::HashMap; use std::fs::File; use std::fs::OpenOptions; use std::io::Seek; use std::io::Write; use std::os::fd::AsFd; use std::process; use wayland::wayland_client::Dispatch; use wayland::wayland_client::QueueHandle; use wayland::wayland_client::protocol::wl_seat::WlSeat; use wayland::wayland_client::protocol::wl_keyboard::KeymapFormat; use wayland::virtual_keyboard_unstable_v1::zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1; use wayland::virtual_keyboard_unstable_v1::zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1; pub struct VirtualKeyboard { vk: ZwpVirtualKeyboardV1, keymap: File, keymap_id: u8, keycodes: HashMap, mod_state: u32, } impl VirtualKeyboard { pub fn new + 'static>(queue: &QueueHandle, vk_man: &ZwpVirtualKeyboardManagerV1, seat: &WlSeat) -> VirtualKeyboard { let vk = vk_man.create_virtual_keyboard(seat, queue, ()); let path = format!("/tmp/ufkbd-keymap-pid{}-1", process::id()); let keymap = File::create(path).unwrap(); VirtualKeyboard { vk, keymap, keymap_id: 1, keycodes: HashMap::new(), mod_state: 0, } } fn write_key(&mut self, part: &Part, keycode: u8) { let sym = part.sym(); let lower = &sym.name().unwrap()[3..]; let upper = &Part::modify_shift(sym).name().unwrap()[3..]; write!(self.keymap, " key {{ [ {}, {} ] }};\n", keycode, lower, upper).unwrap(); if sym == Keysym::Shift_L { write!(self.keymap, " modifier_map Shift {{ }};\n", keycode).unwrap(); } else if sym == Keysym::Control_L { write!(self.keymap, " modifier_map Control {{ }};\n", keycode).unwrap(); } else if sym == Keysym::Alt_L { write!(self.keymap, " modifier_map Mod1 {{ }};\n", keycode).unwrap(); } } } impl Keyboard for VirtualKeyboard { fn press(&mut self, sym: Keysym) { if sym == Keysym::NoSymbol || sym == Keysym::XF86_Fn { return; } match sym { Keysym::Shift_L => { self.mod_state |= 0x1; self.vk.modifiers(self.mod_state, 0, 0, 0); }, Keysym::Control_L => { self.mod_state |= 0x4; self.vk.modifiers(self.mod_state, 0, 0, 0); }, Keysym::Alt_L => { self.mod_state |= 0x8; self.vk.modifiers(self.mod_state, 0, 0, 0); }, _ => (), } let keycode = *self.keycodes.get(&sym).unwrap(); self.vk.key(0, keycode as u32, 1); } fn release(&mut self, sym: Keysym) { if sym == Keysym::NoSymbol || sym == Keysym::XF86_Fn { return; } match sym { Keysym::Shift_L => { self.mod_state &= !0x1; self.vk.modifiers(self.mod_state, 0, 0, 0); }, Keysym::Control_L => { self.mod_state &= !0x4; self.vk.modifiers(self.mod_state, 0, 0, 0); }, Keysym::Alt_L => { self.mod_state &= !0x8; self.vk.modifiers(self.mod_state, 0, 0, 0); }, _ => (), } let keycode = *self.keycodes.get(&sym).unwrap(); self.vk.key(0, keycode as u32, 0); } fn change_layout(&mut self, layout: &Layout) { let mut keycode = 8; self.keymap_id = match self.keymap_id { 0 => 1, 1 => 0, _ => panic!("There should only be up to two keymaps"), }; let path = format!("/tmp/ufkbd-keymap-pid{}-{}", process::id(), self.keymap_id); self.keymap = OpenOptions::new() .read(true) .write(true) .create(true) .truncate(true) .open(path) .unwrap(); self.keymap.write(b"xkb_keymap {\n").unwrap(); self.keymap.write(b" xkb_symbols \"ufkbd\" {\n").unwrap(); for row in layout.rows() { for key in row { for part in &key.parts { if part.sym() == Keysym::NoSymbol || part.sym() == Keysym::XF86_Fn { continue; } self.keycodes.insert(part.sym(), keycode - 8); self.write_key(part, keycode); keycode += 1; } } } self.keymap.write(b" };\n").unwrap(); self.keymap.write(b"\n").unwrap(); self.keymap.write(b" xkb_keycodes \"ufkbd\" {\n").unwrap(); self.keymap.write(b" minimum = 8;\n").unwrap(); self.keymap.write(b" maximum = 255;\n").unwrap(); for i in 8..keycode { write!(self.keymap, " = {};\n", i, i).unwrap(); } self.keymap.write(b" indicator 1 = \"Caps Lock\";\n").unwrap(); self.keymap.write(b" };\n").unwrap(); self.keymap.write(b"\n").unwrap(); self.keymap.write(b" xkb_types \"ufkbd\" {\n").unwrap(); self.keymap.write(b" type \"TWO_LEVEL\" {\n").unwrap(); self.keymap.write(b" modifiers = Shift;\n").unwrap(); self.keymap.write(b" map[Shift] = Level2;\n").unwrap(); self.keymap.write(b" level_name[Level1] = \"Base\";\n").unwrap(); self.keymap.write(b" level_name[Level2] = \"Shift\";\n").unwrap(); self.keymap.write(b" };\n").unwrap(); self.keymap.write(b" };\n").unwrap(); self.keymap.write(b"\n").unwrap(); self.keymap.write(b" xkb_compatibility \"ufkbd\" {\n").unwrap(); self.keymap.write(b" };\n").unwrap(); self.keymap.write(b"};\n").unwrap(); let len = self.keymap.stream_position().unwrap() as u32; self.vk.keymap(KeymapFormat::XkbV1 as u32, self.keymap.as_fd(), len); } }