255 lines
5.9 KiB
Rust
255 lines
5.9 KiB
Rust
use crate::{
|
|
nodes::items::panel::KEYMAPS,
|
|
wayland::{core::surface::Surface, util::ClientExt},
|
|
};
|
|
use dashmap::{DashMap, DashSet};
|
|
use memfd::MemfdOptions;
|
|
use slotmap::{DefaultKey, KeyData};
|
|
use std::{
|
|
collections::HashSet,
|
|
io::Write,
|
|
os::{
|
|
fd::IntoRawFd,
|
|
unix::io::{FromRawFd, OwnedFd},
|
|
},
|
|
sync::{Arc, Weak},
|
|
};
|
|
use tokio::sync::Mutex;
|
|
pub use waynest::server::protocol::core::wayland::wl_keyboard::*;
|
|
use waynest::{
|
|
server::{Client, Dispatcher, Result},
|
|
wire::ObjectId,
|
|
};
|
|
|
|
#[derive(Default)]
|
|
struct ModifierState {
|
|
pressed_keys: HashSet<u32>,
|
|
mods_depressed: u32,
|
|
mods_latched: u32,
|
|
mods_locked: u32,
|
|
group: u32,
|
|
}
|
|
|
|
impl ModifierState {
|
|
fn update_key(&mut self, key: u32, pressed: bool) -> bool {
|
|
let changed = if pressed {
|
|
self.pressed_keys.insert(key)
|
|
} else {
|
|
self.pressed_keys.remove(&key)
|
|
};
|
|
|
|
if changed {
|
|
self.update_modifiers();
|
|
}
|
|
changed
|
|
}
|
|
|
|
fn update_modifiers(&mut self) {
|
|
let mut mods = 0;
|
|
|
|
// Update modifier state based on currently pressed keys
|
|
for key in &self.pressed_keys {
|
|
match *key {
|
|
input_event_codes::KEY_LEFTSHIFT!() | input_event_codes::KEY_RIGHTSHIFT!() => {
|
|
mods |= 1
|
|
}
|
|
input_event_codes::KEY_LEFTCTRL!() | input_event_codes::KEY_RIGHTCTRL!() => {
|
|
mods |= 4
|
|
}
|
|
input_event_codes::KEY_LEFTALT!() | input_event_codes::KEY_RIGHTALT!() => mods |= 8,
|
|
input_event_codes::KEY_LEFTMETA!() | input_event_codes::KEY_RIGHTMETA!() => {
|
|
mods |= 64
|
|
}
|
|
input_event_codes::KEY_CAPSLOCK!() => self.mods_locked ^= 1,
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
self.mods_depressed = mods;
|
|
}
|
|
}
|
|
|
|
#[derive(Dispatcher)]
|
|
pub struct Keyboard {
|
|
pub id: ObjectId,
|
|
focused_surface: Mutex<Weak<Surface>>,
|
|
modifier_state: Mutex<ModifierState>,
|
|
pressed_keys: DashMap<ObjectId, DashSet<u32>>,
|
|
current_keymap_id: Mutex<u64>,
|
|
}
|
|
|
|
impl Keyboard {
|
|
pub fn new(id: ObjectId) -> Self {
|
|
Self {
|
|
id,
|
|
focused_surface: Mutex::new(Weak::new()),
|
|
modifier_state: Mutex::new(ModifierState::default()),
|
|
pressed_keys: DashMap::default(),
|
|
current_keymap_id: Mutex::new(0),
|
|
}
|
|
}
|
|
|
|
async fn send_keymap(&self, client: &mut Client, keymap: &[u8]) -> Result<()> {
|
|
let mut file = MemfdOptions::default()
|
|
.create("stardust-keymap")
|
|
.map_err(|e| waynest::server::Error::Custom(e.to_string()))?
|
|
.into_file();
|
|
file.set_len(keymap.len() as u64)?;
|
|
file.write_all(keymap)?;
|
|
file.flush()?;
|
|
|
|
let fd = unsafe { OwnedFd::from_raw_fd(file.into_raw_fd()) };
|
|
|
|
// Send keymap to client
|
|
self.keymap(
|
|
client,
|
|
self.id,
|
|
KeymapFormat::XkbV1,
|
|
fd,
|
|
keymap.len() as u32,
|
|
)
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// has to be the wayland key, so -8 or whatever
|
|
pub async fn handle_keyboard_key(
|
|
&self,
|
|
client: &mut Client,
|
|
surface: Arc<Surface>,
|
|
keymap_id: u64,
|
|
key: u32,
|
|
pressed: bool,
|
|
) -> Result<()> {
|
|
// KEYMAP UPDATES
|
|
{
|
|
let mut old_keymap_id = self.current_keymap_id.lock().await;
|
|
|
|
if *old_keymap_id != keymap_id {
|
|
let keymap_key = DefaultKey::from(KeyData::from_ffi(keymap_id));
|
|
|
|
// Get keymap data and drop the lock immediately
|
|
let keymap_data = {
|
|
let keymap_lock = KEYMAPS.lock();
|
|
keymap_lock
|
|
.get(keymap_key)
|
|
.map(|s| s.as_bytes().to_vec())
|
|
.unwrap_or_default()
|
|
};
|
|
|
|
// Now we can safely await
|
|
self.send_keymap(client, &keymap_data).await?;
|
|
};
|
|
*old_keymap_id = keymap_id;
|
|
drop(old_keymap_id);
|
|
}
|
|
|
|
// PRESSED KEYS UPDATE
|
|
let pressed_keys = self.pressed_keys.entry(surface.id).or_default();
|
|
if pressed {
|
|
pressed_keys.insert(key);
|
|
} else {
|
|
pressed_keys.remove(&key);
|
|
}
|
|
// println!("pressed keys: {:?}", &*pressed_keys);
|
|
|
|
// FOCUS UPDATES
|
|
let mut focused = self.focused_surface.lock().await;
|
|
let mut modifier_state = self.modifier_state.lock().await;
|
|
|
|
let refocus = focused.as_ptr() != Arc::as_ptr(&surface);
|
|
// If we're entering a new surface
|
|
if refocus {
|
|
// Send leave to old surface if it exists and is still alive
|
|
if let Some(old_surface) = focused.upgrade() {
|
|
let serial = client.next_event_serial();
|
|
self.leave(client, old_surface.id, serial, self.id).await?;
|
|
// println!("Left surface {}", old_surface.id);
|
|
}
|
|
|
|
// Send enter to new surface
|
|
let serial = client.next_event_serial();
|
|
self.enter(
|
|
client,
|
|
self.id,
|
|
serial,
|
|
surface.id,
|
|
pressed_keys.iter().flat_map(|k| k.to_ne_bytes()).collect(),
|
|
)
|
|
.await?;
|
|
// println!("Entered new surface {}", surface.id);
|
|
|
|
// Update focused surface
|
|
*focused = Arc::downgrade(&surface);
|
|
}
|
|
|
|
// KEY EVENT SENDING
|
|
let serial = client.next_event_serial();
|
|
// println!(
|
|
// "Sent key {key} {}",
|
|
// if pressed { "pressed" } else { "released" }
|
|
// );
|
|
self.key(
|
|
client,
|
|
self.id,
|
|
serial,
|
|
client.display().creation_time.elapsed().as_millis() as u32, // time
|
|
key,
|
|
if pressed {
|
|
KeyState::Pressed
|
|
} else {
|
|
KeyState::Released
|
|
},
|
|
)
|
|
.await?;
|
|
|
|
// MODIFIER UPDATES
|
|
// Update modifier state and send modifiers event if changed
|
|
if refocus || modifier_state.update_key(key, pressed) {
|
|
// println!("Update modifiers");
|
|
let serial = client.next_event_serial();
|
|
self.modifiers(
|
|
client,
|
|
self.id,
|
|
serial,
|
|
modifier_state.mods_depressed,
|
|
modifier_state.mods_latched,
|
|
modifier_state.mods_locked,
|
|
modifier_state.group,
|
|
)
|
|
.await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn reset(&self, client: &mut Client) -> Result<()> {
|
|
let mut modifier_state = self.modifier_state.lock().await;
|
|
modifier_state.pressed_keys.clear();
|
|
modifier_state.mods_depressed = 0;
|
|
modifier_state.mods_latched = 0;
|
|
modifier_state.mods_locked = 0;
|
|
modifier_state.group = 0;
|
|
|
|
let serial = client.next_event_serial();
|
|
self.modifiers(
|
|
client,
|
|
self.id,
|
|
serial,
|
|
modifier_state.mods_depressed,
|
|
modifier_state.mods_latched,
|
|
modifier_state.mods_locked,
|
|
modifier_state.group,
|
|
)
|
|
.await
|
|
}
|
|
}
|
|
|
|
impl WlKeyboard for Keyboard {
|
|
/// https://wayland.app/protocols/wayland#wl_keyboard:request:release
|
|
async fn release(&self, _client: &mut Client, _sender_id: ObjectId) -> Result<()> {
|
|
Ok(())
|
|
}
|
|
}
|