Skip to content

Commit

Permalink
Multiple clients
Browse files Browse the repository at this point in the history
  • Loading branch information
ids1024 committed Sep 25, 2024
1 parent 46e07d4 commit 370a84f
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 136 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 6 additions & 10 deletions src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1669,18 +1669,14 @@ impl State {
}

// TODO modifiers queue
if self.common.atspi_ei.has_keyboard_grab {
if self.common.atspi_ei.has_keyboard_grab()
|| self
.common
.atspi_ei
.has_key_grab(modifiers.serialized.layout_effective, event.key_code())
{
return FilterResult::Intercept(None);
}
for grab in &self.common.atspi_ei.key_grabs {
if grab.mods == modifiers.serialized.layout_effective
&& grab.virtual_mods == self.common.atspi_ei.active_virtual_mods
&& grab.key == event.key_code()
{
tracing::error!("Grab matched: {:?}", grab);
return FilterResult::Intercept(None);
}
}

// handle the rest of the global shortcuts
let mut clear_queue = true;
Expand Down
262 changes: 153 additions & 109 deletions src/wayland/handlers/atspi.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// SPDX-License-Identifier: GPL-3.0-only

use cosmic_comp_config::XkbConfig;
use once_cell::sync::Lazy;
use cosmic_protocols::atspi::v1::server::cosmic_atspi_manager_v1::CosmicAtspiManagerV1;
use reis::{
calloop::{EisRequestSource, EisRequestSourceEvent},
eis::{self, device::DeviceType},
request::{Connection, Device, DeviceCapability, EisRequest, Seat},
};
use smithay::{
backend::input::KeyState,
backend::input::{KeyState, Keycode},
input::keyboard::ModifiersState,
utils::{SealedFile, SerialCounter},
};
use std::{
Expand All @@ -29,69 +30,26 @@ pub static EI_SERIAL_COUNTER: SerialCounter = SerialCounter::new();
#[derive(PartialEq, Debug)]
pub struct AtspiKeyGrab {
pub mods: u32,
pub virtual_mods: HashSet<xkb::Keycode>,
pub key: xkb::Keycode,
pub virtual_mods: HashSet<Keycode>,
pub key: Keycode,
}

#[derive(Debug, Default)]
pub struct AtspiEiState {
modifiers: smithay::input::keyboard::ModifiersState,
struct AtspiClient {
key_grabs: Vec<AtspiKeyGrab>,
has_keyboard_grab: bool,
// TODO: purge old instances
keyboards: Vec<(Connection, Device, eis::Keyboard)>,
pub key_grabs: Vec<AtspiKeyGrab>,
pub virtual_mods: HashSet<xkb::Keycode>,
pub active_virtual_mods: HashSet<xkb::Keycode>,
pub has_keyboard_grab: bool
}

impl AtspiEiState {
pub fn input(
impl AtspiClient {
fn add_keyboard(
&mut self,
modifiers: &smithay::input::keyboard::ModifiersState,
keysym: &smithay::input::keyboard::KeysymHandle,
state: KeyState,
time: u64,
connection: &Connection,
seat: &Seat,
keymap: &xkb::Keymap,
modifiers: &ModifiersState,
) {
let state = match state {
KeyState::Pressed => eis::keyboard::KeyState::Press,
KeyState::Released => eis::keyboard::KeyState::Released,
};
if &self.modifiers != modifiers {
self.modifiers = *modifiers;
for (_, _, keyboard) in &self.keyboards {
keyboard.modifiers(
EI_SERIAL_COUNTER.next_serial().into(),
modifiers.serialized.depressed,
modifiers.serialized.locked,
modifiers.serialized.latched,
modifiers.serialized.layout_effective,
);
}
}
for (connection, device, keyboard) in &self.keyboards {
keyboard.key(keysym.raw_code().raw() - 8, state);
device.device().frame(EI_SERIAL_COUNTER.next_serial().into(), time);
let _ = connection.flush();
}
}

fn update_virtual_mods(&mut self) {
self.virtual_mods.clear();
self.virtual_mods
.extend(self.key_grabs.iter().flat_map(|grab| &grab.virtual_mods));
}

pub fn update_keymap(&mut self, xkb_config: XkbConfig) {
let keymap = keymap_or_default(xkb_config);
let old_keyboards = mem::take(&mut self.keyboards);
for (connection, device, _keyboard) in old_keyboards {
device.remove();
self.add_keyboard(&connection, device.seat(), &keymap);
let _ = connection.flush();
}
}

fn add_keyboard(&mut self, connection: &Connection, seat: &Seat, keymap: &xkb::Keymap) {
let keymap_text = keymap.get_as_string(xkb::KEYMAP_FORMAT_TEXT_V1);
let name = CStr::from_bytes_with_nul(b"eis-keymap\0").unwrap();
let file = SealedFile::with_content(name, &CString::new(keymap_text).unwrap()).unwrap();
Expand All @@ -117,102 +75,186 @@ impl AtspiEiState {

keyboard.modifiers(
EI_SERIAL_COUNTER.next_serial().into(),
self.modifiers.serialized.depressed,
self.modifiers.serialized.locked,
self.modifiers.serialized.latched,
self.modifiers.serialized.layout_effective,
modifiers.serialized.depressed,
modifiers.serialized.locked,
modifiers.serialized.latched,
modifiers.serialized.layout_effective,
);

device
.device()
.start_emulating(EI_SERIAL_COUNTER.next_serial().into(), 0);

self.keyboards
.push((connection.clone(), device, keyboard));
self.keyboards.push((connection.clone(), device, keyboard));
}
}

static SERVER_INTERFACES: Lazy<HashMap<&'static str, u32>> = Lazy::new(|| {
let mut m = HashMap::new();
m.insert("ei_callback", 1);
m.insert("ei_connection", 1);
m.insert("ei_seat", 1);
m.insert("ei_device", 1);
m.insert("ei_pingpong", 1);
m.insert("ei_keyboard", 1);
m
});
#[derive(Debug, Default)]
pub struct AtspiEiState {
modifiers: ModifiersState,
clients: HashMap<CosmicAtspiManagerV1, AtspiClient>,
pub virtual_mods: HashSet<Keycode>,
pub active_virtual_mods: HashSet<Keycode>,
}

impl AtspiEiState {
pub fn input(
&mut self,
modifiers: &smithay::input::keyboard::ModifiersState,
keysym: &smithay::input::keyboard::KeysymHandle,
state: KeyState,
time: u64,
) {
let state = match state {
KeyState::Pressed => eis::keyboard::KeyState::Press,
KeyState::Released => eis::keyboard::KeyState::Released,
};
if &self.modifiers != modifiers {
self.modifiers = *modifiers;
for client in self.clients.values() {
for (_, _, keyboard) in &client.keyboards {
keyboard.modifiers(
EI_SERIAL_COUNTER.next_serial().into(),
modifiers.serialized.depressed,
modifiers.serialized.locked,
modifiers.serialized.latched,
modifiers.serialized.layout_effective,
);
}
}
}
for client in self.clients.values() {
for (connection, device, keyboard) in &client.keyboards {
keyboard.key(keysym.raw_code().raw() - 8, state);
device
.device()
.frame(EI_SERIAL_COUNTER.next_serial().into(), time);
let _ = connection.flush();
}
}
}

pub fn has_keyboard_grab(&self) -> bool {
self.clients.values().any(|client| client.has_keyboard_grab)
}

/// Key grab exists for mods, key, with active virtual mods
pub fn has_key_grab(&self, mods: u32, key: Keycode) -> bool {
self.clients
.values()
.flat_map(|client| &client.key_grabs)
.any(|grab| {
grab.mods == mods
&& grab.virtual_mods == self.active_virtual_mods
&& grab.key == key
})
}

fn update_virtual_mods(&mut self) {
self.virtual_mods.clear();
self.virtual_mods.extend(
self.clients
.values()
.flat_map(|client| &client.key_grabs)
.flat_map(|grab| &grab.virtual_mods),
);
}

pub fn update_keymap(&mut self, xkb_config: XkbConfig) {
let keymap = keymap_or_default(xkb_config);
for client in self.clients.values_mut() {
let old_keyboards = mem::take(&mut client.keyboards);
for (connection, device, _keyboard) in old_keyboards {
device.remove();
client.add_keyboard(&connection, device.seat(), &keymap, &self.modifiers);
let _ = connection.flush();
}
}
}
}

impl AtspiHandler for State {
fn add_key_event_socket(&mut self, socket: UnixStream) {
let context = eis::Context::new(socket).unwrap(); // XXX
let source = EisRequestSource::new(context, &SERVER_INTERFACES, 0);
fn client_connected(&mut self, manager: &CosmicAtspiManagerV1, socket: UnixStream) {
self.common
.atspi_ei
.clients
.insert(manager.clone(), AtspiClient::default());

let context = eis::Context::new(socket).unwrap();
let source = EisRequestSource::new(context, 0);
let manager = manager.clone();
self.common
.event_loop_handle
.insert_source(source, |event, connected_state, state| {
Ok(handle_event(event, connected_state, state))
.insert_source(source, move |event, connected_state, state| {
Ok(handle_event(&manager, event, connected_state, state))
})
.unwrap(); // XXX
.unwrap();
}

fn client_disconnected(&mut self, manager: &CosmicAtspiManagerV1) {
self.common.atspi_ei.clients.remove(manager);
self.common.atspi_ei.update_virtual_mods();
}

fn add_key_grab(&mut self, mods: u32, virtual_mods: Vec<u32>, key: u32) {
tracing::error!("add_key_grab: {:?}", (mods, &virtual_mods, key));
fn add_key_grab(
&mut self,
manager: &CosmicAtspiManagerV1,
mods: u32,
virtual_mods: Vec<u32>,
key: u32,
) {
let grab = AtspiKeyGrab {
mods,
virtual_mods: virtual_mods.into_iter().map(|x| (x + 8).into()).collect(),
key: (key + 8).into(),
};
self.common.atspi_ei.key_grabs.push(grab);
let client = self.common.atspi_ei.clients.get_mut(manager).unwrap();
client.key_grabs.push(grab);
self.common.atspi_ei.update_virtual_mods();
}

fn remove_key_grab(&mut self, mods: u32, virtual_mods: Vec<u32>, key: u32) {
tracing::error!("remove_key_grab: {:?}", (mods, &virtual_mods, key));
fn remove_key_grab(
&mut self,
manager: &CosmicAtspiManagerV1,
mods: u32,
virtual_mods: Vec<u32>,
key: u32,
) {
let grab = AtspiKeyGrab {
mods,
virtual_mods: virtual_mods.into_iter().map(|x| (x + 8).into()).collect(),
key: (key + 8).into(),
};
if let Some(idx) = self
.common
.atspi_ei
.key_grabs
.iter()
.position(|x| *x == grab)
{
self.common.atspi_ei.key_grabs.remove(idx);
let client = self.common.atspi_ei.clients.get_mut(manager).unwrap();
if let Some(idx) = client.key_grabs.iter().position(|x| *x == grab) {
client.key_grabs.remove(idx);
}
self.common.atspi_ei.update_virtual_mods();
}

fn grab_keyboard(&mut self) {
self.common.atspi_ei.has_keyboard_grab = true;
fn grab_keyboard(&mut self, manager: &CosmicAtspiManagerV1) {
let client = self.common.atspi_ei.clients.get_mut(manager).unwrap();
client.has_keyboard_grab = true;
}

fn ungrab_keyboard(&mut self) {
self.common.atspi_ei.has_keyboard_grab = false;
}

fn destroy(&mut self) {
let state = &mut self.common.atspi_ei;
state.virtual_mods.clear();
state.key_grabs.clear();
state.keyboards.clear();
state.has_keyboard_grab = false;
fn ungrab_keyboard(&mut self, manager: &CosmicAtspiManagerV1) {
let client = self.common.atspi_ei.clients.get_mut(manager).unwrap();
client.has_keyboard_grab = false;
}
}

fn handle_event(
event: Result<EisRequestSourceEvent, reis::request::Error>,
manager: &CosmicAtspiManagerV1,
event: Result<EisRequestSourceEvent, reis::Error>,
connection: &Connection,
state: &mut State,
) -> calloop::PostAction {
let client = state.common.atspi_ei.clients.get_mut(manager).unwrap();
match event {
Ok(EisRequestSourceEvent::Connected) => {
if connection.context_type() != reis::ei::handshake::ContextType::Receiver {
return calloop::PostAction::Remove;
}
// TODO multiple seats
let _seat = connection.add_seat(Some("default"), &[DeviceCapability::Keyboard]);
}
Ok(EisRequestSourceEvent::Request(EisRequest::Disconnect)) => {
Expand All @@ -223,10 +265,12 @@ fn handle_event(
&& request.capabilities & 2 << DeviceCapability::Keyboard as u64 != 0
{
let keymap = keymap_or_default(state.common.config.xkb_config());
state
.common
.atspi_ei
.add_keyboard(connection, &request.seat, &keymap);
client.add_keyboard(
connection,
&request.seat,
&keymap,
&state.common.atspi_ei.modifiers,
);
}
}
Ok(EisRequestSourceEvent::Request(request)) => {
Expand Down
Loading

0 comments on commit 370a84f

Please sign in to comment.