unfettered-keyboard/src/wayland/keyboard.rs
Richard Acayan 78f389beaa treewide: use Rust 2018 import paths
Rust 2018 is required for D-Bus support with tokio/zbus.
2024-07-24 22:32:00 -04:00

226 lines
7.3 KiB
Rust

// SPDX-License-Identifier: GPL-3.0-only
/*
* Copyright (c) 2024, Richard Acayan. All rights reserved.
*/
use crate::core::Keyboard;
use crate::core::Layout;
use crate::core::Part;
use crate::wayland::virtual_keyboard_unstable_v1::zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1;
use crate::wayland::virtual_keyboard_unstable_v1::zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1;
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_client::Dispatch;
use wayland_client::QueueHandle;
use wayland_client::protocol::wl_seat::WlSeat;
use wayland_client::protocol::wl_keyboard::KeymapFormat;
use xkeysym::Keysym;
pub struct VirtualKeyboard {
vk: ZwpVirtualKeyboardV1,
keymap: File,
keymap_id: u8,
keycodes: HashMap<Keysym, u8>,
pressed: [Keysym; 248],
mod_state: u32,
}
impl VirtualKeyboard {
pub fn new<T: Dispatch<ZwpVirtualKeyboardV1, ()>
+ 'static>(queue: &QueueHandle<T>,
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::with_capacity(248),
pressed: [Keysym::NoSymbol; 248],
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..];
writeln!(self.keymap, " key <I{:03}> {{ [ {}, {} ] }};",
keycode, lower, upper).unwrap();
if sym == Keysym::Shift_L {
writeln!(self.keymap,
" modifier_map Shift {{ <I{:03}> }};",
keycode).unwrap();
} else if sym == Keysym::Control_L {
writeln!(self.keymap,
" modifier_map Control {{ <I{:03}> }};",
keycode).unwrap();
} else if sym == Keysym::Alt_L {
writeln!(self.keymap,
" modifier_map Mod1 {{ <I{:03}> }};",
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.pressed[keycode as usize] = sym;
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.pressed[keycode as usize] = Keysym::NoSymbol;
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_all(b"xkb_keymap {\n").unwrap();
self.keymap.write_all(b" xkb_symbols \"ufkbd\" {\n").unwrap();
self.keycodes.clear();
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;
}
if self.keycodes.contains_key(&part.sym()) {
continue;
}
self.keycodes.insert(part.sym(), keycode - 8);
self.write_key(part, keycode);
keycode += 1;
}
}
}
self.keymap.write_all(b" };\n").unwrap();
self.keymap.write_all(b"\n").unwrap();
self.keymap.write_all(b" xkb_keycodes \"ufkbd\" {\n").unwrap();
self.keymap.write_all(b" minimum = 8;\n").unwrap();
self.keymap.write_all(b" maximum = 255;\n").unwrap();
for i in 8..keycode {
writeln!(self.keymap, " <I{:03}> = {};", i, i).unwrap();
}
self.keymap.write_all(b" indicator 1 = \"Caps Lock\";\n").unwrap();
self.keymap.write_all(b" };\n").unwrap();
self.keymap.write_all(b"\n").unwrap();
self.keymap.write_all(b" xkb_types \"ufkbd\" {\n").unwrap();
self.keymap.write_all(b" type \"TWO_LEVEL\" {\n").unwrap();
self.keymap.write_all(b" modifiers = Shift;\n").unwrap();
self.keymap.write_all(b" map[Shift] = Level2;\n").unwrap();
self.keymap.write_all(b" level_name[Level1] = \"Base\";\n").unwrap();
self.keymap.write_all(b" level_name[Level2] = \"Shift\";\n").unwrap();
self.keymap.write_all(b" };\n").unwrap();
self.keymap.write_all(b" };\n").unwrap();
self.keymap.write_all(b"\n").unwrap();
self.keymap.write_all(b" xkb_compatibility \"ufkbd\" {\n").unwrap();
self.keymap.write_all(b" };\n").unwrap();
self.keymap.write_all(b"};\n").unwrap();
if self.mod_state != 0 {
self.vk.modifiers(0, 0, 0, 0);
}
for (code, sym) in self.pressed.iter().enumerate() {
if *sym != Keysym::NoSymbol {
self.vk.key(0, code as u32, 0);
}
}
let len = self.keymap.stream_position().unwrap() as u32;
self.vk.keymap(KeymapFormat::XkbV1 as u32, self.keymap.as_fd(), len);
if self.mod_state != 0 {
self.vk.modifiers(self.mod_state, 0, 0, 0);
}
for sym in &self.pressed {
if *sym != Keysym::NoSymbol {
let code = *self.keycodes.get(&sym).unwrap();
self.vk.key(0, code as u32, 1);
}
}
}
}