Skip to content

Commit

Permalink
WIP Add cosmic-keymap-unstable-v1 protocol
Browse files Browse the repository at this point in the history
Includes example client using `cosmic-client-toolkit`.
  • Loading branch information
ids1024 committed Nov 18, 2024
1 parent ec1616b commit 3b3fad1
Show file tree
Hide file tree
Showing 6 changed files with 405 additions and 0 deletions.
1 change: 1 addition & 0 deletions client-toolkit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ png = "0.17.5"
raw-window-handle = "0.5.0"
wayland-backend = { version = "0.3.2", features = ["client_system"] }
winit = "0.28.0"
xkbcommon = "0.7.0"

[features]
default = []
Expand Down
212 changes: 212 additions & 0 deletions client-toolkit/examples/keymap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
use cosmic_client_toolkit::keymap::{KeymapHandler, KeymapState};
use cosmic_protocols::keymap::v1::client::zcosmic_keymap_v1;
use sctk::{
registry::{ProvidesRegistryState, RegistryState},
registry_handlers,
seat::{
keyboard::{KeyEvent, KeyboardHandler, Keymap, Keysym, Modifiers},
Capability, SeatHandler, SeatState,
},
};
use std::{
io::{self, Write},
str::FromStr,
};
use wayland_client::{
globals::registry_queue_init,
protocol::{wl_keyboard, wl_seat, wl_surface},
Connection, QueueHandle,
};
use xkbcommon::xkb;

struct AppData {
registry_state: RegistryState,
seat_state: SeatState,
keyboard: Option<wl_keyboard::WlKeyboard>,
keymap_state: KeymapState,
keymap: Option<xkb::Keymap>,
group: Option<u32>,
}

impl ProvidesRegistryState for AppData {
fn registry(&mut self) -> &mut RegistryState {
&mut self.registry_state
}

registry_handlers![SeatState,];
}

impl SeatHandler for AppData {
fn seat_state(&mut self) -> &mut SeatState {
&mut self.seat_state
}

fn new_seat(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_seat::WlSeat) {}

fn new_capability(
&mut self,
_conn: &Connection,
qh: &QueueHandle<Self>,
seat: wl_seat::WlSeat,
capability: Capability,
) {
if capability == Capability::Keyboard {
let keyboard = self.seat_state.get_keyboard(qh, &seat, None).unwrap();
self.keyboard = Some(keyboard);
}
}

fn remove_capability(
&mut self,
_conn: &Connection,
_: &QueueHandle<Self>,
_: wl_seat::WlSeat,
_capability: Capability,
) {
}

fn remove_seat(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_seat::WlSeat) {}
}

impl KeyboardHandler for AppData {
fn enter(
&mut self,
_: &Connection,
_: &QueueHandle<Self>,
_: &wl_keyboard::WlKeyboard,
_surface: &wl_surface::WlSurface,
_: u32,
_: &[u32],
_keysyms: &[Keysym],
) {
}

fn leave(
&mut self,
_: &Connection,
_: &QueueHandle<Self>,
_: &wl_keyboard::WlKeyboard,
_surface: &wl_surface::WlSurface,
_: u32,
) {
}

fn press_key(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_: &wl_keyboard::WlKeyboard,
_: u32,
_event: KeyEvent,
) {
}

fn release_key(
&mut self,
_: &Connection,
_: &QueueHandle<Self>,
_: &wl_keyboard::WlKeyboard,
_: u32,
_event: KeyEvent,
) {
}

fn update_modifiers(
&mut self,
_: &Connection,
_: &QueueHandle<Self>,
_: &wl_keyboard::WlKeyboard,
_serial: u32,
_modifiers: Modifiers,
_layout: u32,
) {
}

fn update_keymap(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_keyboard: &wl_keyboard::WlKeyboard,
keymap: Keymap<'_>,
) {
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let keymap = xkb::Keymap::new_from_string(
&context,
keymap.as_string(),
xkb::KEYMAP_FORMAT_TEXT_V1,
xkb::KEYMAP_COMPILE_NO_FLAGS,
)
.unwrap();
self.keymap = Some(keymap);
}
}

impl KeymapHandler for AppData {
fn group(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_keyboard: &wl_keyboard::WlKeyboard,
_keymap: &zcosmic_keymap_v1::ZcosmicKeymapV1,
group: u32,
) {
self.group = Some(group);
}
}

fn main() {
let conn = Connection::connect_to_env().unwrap();
let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
let qh = event_queue.handle();

let registry_state = RegistryState::new(&globals);
let seat_state = SeatState::new(&globals, &qh);
let keymap_state = KeymapState::new(&registry_state, &qh);
let mut app_data = AppData {
registry_state,
seat_state,
keymap_state,
keyboard: None,
keymap: None,
group: None,
};

while app_data.keymap.is_none() {
event_queue.blocking_dispatch(&mut app_data).unwrap();
}

let keyboard = app_data.keyboard.as_ref().unwrap();
let cosmic_keymap = app_data.keymap_state.get_keymap(&keyboard, &qh).unwrap();

while app_data.group.is_none() {
event_queue.blocking_dispatch(&mut app_data).unwrap();
}
let group = app_data.group.unwrap();

let keymap = app_data.keymap.as_ref().unwrap();
for (n, name) in keymap.layouts().enumerate() {
// Bold active layout
if n as u32 == group {
print!("\x1b[1m");
}
println!("{}: {}", n, name);
if n as u32 == group {
print!("\x1b[22m");
}
}
print!("Choose layout: ");

io::stdout().flush().unwrap();
let mut line = String::new();
io::stdin().read_line(&mut line).unwrap();
let index = u32::from_str(line.trim()).unwrap();

cosmic_keymap.set_group(index);

event_queue.roundtrip(&mut app_data).unwrap();
}

sctk::delegate_registry!(AppData);
sctk::delegate_seat!(AppData);
sctk::delegate_keyboard!(AppData);
cosmic_client_toolkit::delegate_keymap!(AppData);
104 changes: 104 additions & 0 deletions client-toolkit/src/keymap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use cosmic_protocols::keymap::v1::client::{zcosmic_keymap_manager_v1, zcosmic_keymap_v1};
use sctk::registry::RegistryState;
use wayland_client::{protocol::wl_keyboard, Connection, Dispatch, QueueHandle};

pub trait KeymapHandler: Sized {
fn group(
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
keyboard: &wl_keyboard::WlKeyboard,
keymap: &zcosmic_keymap_v1::ZcosmicKeymapV1,
group: u32,
);
}

pub struct KeymapState {
pub keymap_manager: Option<zcosmic_keymap_manager_v1::ZcosmicKeymapManagerV1>,
}

impl KeymapState {
pub fn new<D>(registry: &RegistryState, qh: &QueueHandle<D>) -> Self
where
D: Dispatch<zcosmic_keymap_manager_v1::ZcosmicKeymapManagerV1, ()> + 'static,
{
let keymap_manager = registry
.bind_one::<zcosmic_keymap_manager_v1::ZcosmicKeymapManagerV1, _, _>(qh, 1..=1, ())
.ok();

Self { keymap_manager }
}

pub fn get_keymap<D>(
&self,
keyboard: &wl_keyboard::WlKeyboard,
qh: &QueueHandle<D>,
) -> Option<zcosmic_keymap_v1::ZcosmicKeymapV1>
where
D: Dispatch<zcosmic_keymap_v1::ZcosmicKeymapV1, KeymapUserData> + 'static,
{
Some(self.keymap_manager.as_ref()?.get_keymap(
keyboard,
qh,
KeymapUserData {
keyboard: keyboard.clone(),
},
))
}
}

impl<D> Dispatch<zcosmic_keymap_manager_v1::ZcosmicKeymapManagerV1, (), D> for KeymapState
where
D: Dispatch<zcosmic_keymap_manager_v1::ZcosmicKeymapManagerV1, ()>,
{
fn event(
_: &mut D,
_: &zcosmic_keymap_manager_v1::ZcosmicKeymapManagerV1,
event: zcosmic_keymap_manager_v1::Event,
_: &(),
_: &Connection,
_: &QueueHandle<D>,
) {
match event {
_ => unreachable!(),
}
}
}

#[doc(hidden)]
pub struct KeymapUserData {
keyboard: wl_keyboard::WlKeyboard,
}

impl<D> Dispatch<zcosmic_keymap_v1::ZcosmicKeymapV1, KeymapUserData, D> for KeymapState
where
D: Dispatch<zcosmic_keymap_v1::ZcosmicKeymapV1, KeymapUserData> + KeymapHandler,
{
fn event(
state: &mut D,
keymap: &zcosmic_keymap_v1::ZcosmicKeymapV1,
event: zcosmic_keymap_v1::Event,
data: &KeymapUserData,
conn: &Connection,
qh: &QueueHandle<D>,
) {
match event {
zcosmic_keymap_v1::Event::Group { group } => {
state.group(conn, qh, &data.keyboard, keymap, group);
}
_ => unreachable!(),
}
}
}

#[macro_export]
macro_rules! delegate_keymap {
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
$crate::wayland_client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
$crate::cosmic_protocols::keymap::v1::client::zcosmic_keymap_manager_v1::ZcosmicKeymapManagerV1: ()
] => $crate::keymap::KeymapState);
$crate::wayland_client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
$crate::cosmic_protocols::keymap::v1::client::zcosmic_keymap_v1::ZcosmicKeymapV1: $crate::keymap::KeymapUserData
] => $crate::keymap::KeymapState);
};
}
1 change: 1 addition & 0 deletions client-toolkit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub use wayland_protocols;
pub mod egl;
#[cfg(feature = "gl")]
pub mod gl;
pub mod keymap;
pub mod screencopy;
pub mod toplevel_info;
pub mod toplevel_management;
Expand Down
12 changes: 12 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,15 @@ pub mod atspi {
);
}
}

pub mod keymap {
//! Set keymap group.
#[allow(missing_docs)]
pub mod v1 {
wayland_protocol!(
"./unstable/cosmic-keymap-unstable-v1.xml",
[]
);
}
}
Loading

0 comments on commit 3b3fad1

Please sign in to comment.