diff --git a/wlx-overlay-s/src/backend/wayvr/client.rs b/wlx-overlay-s/src/backend/wayvr/client.rs index de5a793..39b1a9d 100644 --- a/wlx-overlay-s/src/backend/wayvr/client.rs +++ b/wlx-overlay-s/src/backend/wayvr/client.rs @@ -7,7 +7,7 @@ use smithay::{ reexports::wayland_server, utils::SerialCounter, }; -use xkbcommon::xkb::{self, KEYMAP_FORMAT_USE_ORIGINAL}; +use xkbcommon::xkb; use crate::backend::wayvr::{ExternalProcessRequest, WayVRTask}; diff --git a/wlx-overlay-s/src/backend/wayvr/mod.rs b/wlx-overlay-s/src/backend/wayvr/mod.rs index 401d5f3..66919a4 100644 --- a/wlx-overlay-s/src/backend/wayvr/mod.rs +++ b/wlx-overlay-s/src/backend/wayvr/mod.rs @@ -32,7 +32,6 @@ use smithay::{ selection::data_device::DataDeviceState, shell::xdg::{ToplevelSurface, XdgShellState}, shm::ShmState, - xwayland_keyboard_grab::XWaylandKeyboardGrabHandler, }, }; use std::{ diff --git a/wlx-overlay-s/src/overlays/keyboard/builder.rs b/wlx-overlay-s/src/overlays/keyboard/builder.rs index 49d2e02..4989fb1 100644 --- a/wlx-overlay-s/src/overlays/keyboard/builder.rs +++ b/wlx-overlay-s/src/overlays/keyboard/builder.rs @@ -1,6 +1,7 @@ use std::{collections::HashMap, rc::Rc}; -use glam::{Affine3A, FloatExt, Mat4, Quat, Vec2, Vec3, vec2, vec3}; +use crate::{gui::panel::GuiPanel, state::AppState, subsystem::hid::XkbKeymap}; +use glam::{FloatExt, Mat4, Vec2, Vec3, vec2}; use wgui::{ animation::{Animation, AnimationEasing}, assets::AssetPath, @@ -17,43 +18,22 @@ use wgui::{ util::WLength, }, }; -use wlx_common::windowing::{OverlayWindowState, Positioning}; - -use crate::{ - gui::panel::GuiPanel, - state::AppState, - subsystem::hid::{ALT, CTRL, META, SHIFT, SUPER, XkbKeymap}, - windowing::window::OverlayWindowConfig, -}; use super::{ - KEYBOARD_NAME, KeyButtonData, KeyState, KeyboardBackend, KeyboardState, handle_press, - handle_release, - layout::{self, AltModifier, KeyCapType}, + KeyButtonData, KeyState, KeyboardState, handle_press, handle_release, + layout::{self, KeyCapType}, }; const BACKGROUND_PADDING: f32 = 16.0; const PIXELS_PER_UNIT: f32 = 80.; #[allow(clippy::too_many_lines, clippy::significant_drop_tightening)] -pub fn create_keyboard( +pub(super) fn create_keyboard_panel( app: &mut AppState, - mut keymap: Option, -) -> anyhow::Result { - let layout = layout::Layout::load_from_disk(); - let state = KeyboardState { - modifiers: 0, - alt_modifier: match layout.alt_modifier { - AltModifier::Shift => SHIFT, - AltModifier::Ctrl => CTRL, - AltModifier::Alt => ALT, - AltModifier::Super => SUPER, - AltModifier::Meta => META, - _ => 0, - }, - processes: vec![], - }; - + keymap: Option<&XkbKeymap>, + state: KeyboardState, + layout: &layout::Layout, +) -> anyhow::Result> { let mut panel = GuiPanel::new_blank(app, state, Default::default())?; let globals = app.wgui_globals.clone(); @@ -75,11 +55,7 @@ pub fn create_keyboard( }, )?; - let has_altgr = keymap.as_ref().is_some_and(XkbKeymap::has_altgr); - - if !layout.auto_labels.unwrap_or(true) { - keymap = None; - } + let has_altgr = keymap.as_ref().is_some_and(|m| XkbKeymap::has_altgr(*m)); let parse_doc_params = wgui::parser::ParseDocumentParams { globals, @@ -111,7 +87,7 @@ pub fn create_keyboard( height: length(PIXELS_PER_UNIT), }; - let Some(key) = layout.get_key_data(keymap.as_ref(), has_altgr, col, row) else { + let Some(key) = layout.get_key_data(keymap, has_altgr, col, row) else { let _ = panel.layout.add_child( div.id, WidgetDiv::create(), @@ -273,24 +249,7 @@ pub fn create_keyboard( panel.layout.update(vec2(2048., 2048.), 0.0)?; panel.parser_state = gui_state_key; - let width = layout.row_size * 0.05 * app.session.config.keyboard_scale; - - Ok(OverlayWindowConfig { - name: KEYBOARD_NAME.into(), - default_state: OverlayWindowState { - grabbable: true, - positioning: Positioning::Anchored, - interactable: true, - curvature: Some(0.15), - transform: Affine3A::from_scale_rotation_translation( - Vec3::ONE * width, - Quat::from_rotation_x(-10f32.to_radians()), - vec3(0.0, -0.65, -0.5), - ), - ..OverlayWindowState::default() - }, - ..OverlayWindowConfig::from_backend(Box::new(KeyboardBackend { panel })) - }) + Ok(panel) } const BUTTON_HOVER_SCALE: f32 = 0.1; diff --git a/wlx-overlay-s/src/overlays/keyboard/mod.rs b/wlx-overlay-s/src/overlays/keyboard/mod.rs index 4006de2..703f85f 100644 --- a/wlx-overlay-s/src/overlays/keyboard/mod.rs +++ b/wlx-overlay-s/src/overlays/keyboard/mod.rs @@ -1,22 +1,29 @@ use std::{ cell::Cell, + collections::HashMap, process::{Child, Command}, }; -use wgui::{ - drawing, - event::{InternalStateChangeEvent, MouseButton, MouseButtonIndex}, -}; - use crate::{ backend::input::{HoverResult, PointerHit}, gui::panel::GuiPanel, + overlays::keyboard::{builder::create_keyboard_panel, layout::AltModifier}, state::AppState, - subsystem::hid::{ALT, CTRL, KeyModifier, META, SHIFT, SUPER, VirtualKey, WheelDelta}, - windowing::backend::{ - FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender, + subsystem::hid::{ + ALT, CTRL, KeyModifier, META, SHIFT, SUPER, VirtualKey, WheelDelta, XkbKeymap, + }, + windowing::{ + backend::{FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender}, + window::OverlayWindowConfig, }, }; +use glam::{Affine3A, Quat, Vec3, vec3}; +use slotmap::{SlotMap, new_key_type}; +use wgui::{ + drawing, + event::{InternalStateChangeEvent, MouseButton, MouseButtonIndex}, +}; +use wlx_common::windowing::{OverlayWindowState, Positioning}; pub mod builder; mod layout; @@ -24,31 +31,147 @@ mod layout; pub const KEYBOARD_NAME: &str = "kbd"; const AUTO_RELEASE_MODS: [KeyModifier; 5] = [SHIFT, CTRL, ALT, SUPER, META]; +pub fn create_keyboard( + app: &mut AppState, + mut keymap: Option, +) -> anyhow::Result { + let layout = layout::Layout::load_from_disk(); + let default_state = KeyboardState { + modifiers: 0, + alt_modifier: match layout.alt_modifier { + AltModifier::Shift => SHIFT, + AltModifier::Ctrl => CTRL, + AltModifier::Alt => ALT, + AltModifier::Super => SUPER, + AltModifier::Meta => META, + _ => 0, + }, + processes: vec![], + }; + + if !layout.auto_labels.unwrap_or(true) { + keymap = None; + } + + let width = layout.row_size * 0.05 * app.session.config.keyboard_scale; + + let mut backend = KeyboardBackend { + keymap_panels: SlotMap::default(), + keymap_ids: HashMap::default(), + active_keymap: KeyboardPanelKey::default(), + default_state, + layout, + }; + + backend.active_keymap = backend.add_new_keymap(keymap.as_ref(), app)?; + + Ok(OverlayWindowConfig { + name: KEYBOARD_NAME.into(), + default_state: OverlayWindowState { + grabbable: true, + positioning: Positioning::Anchored, + interactable: true, + curvature: Some(0.15), + transform: Affine3A::from_scale_rotation_translation( + Vec3::ONE * width, + Quat::from_rotation_x(-10f32.to_radians()), + vec3(0.0, -0.65, -0.5), + ), + ..OverlayWindowState::default() + }, + ..OverlayWindowConfig::from_backend(Box::new(backend)) + }) +} + +new_key_type! { + struct KeyboardPanelKey; +} + struct KeyboardBackend { - panel: GuiPanel, + keymap_panels: SlotMap>, + keymap_ids: HashMap, + active_keymap: KeyboardPanelKey, + default_state: KeyboardState, + layout: layout::Layout, +} + +impl KeyboardBackend { + fn add_new_keymap( + &mut self, + keymap: Option<&XkbKeymap>, + app: &mut AppState, + ) -> anyhow::Result { + let panel = create_keyboard_panel(app, keymap, self.default_state.take(), &self.layout)?; + + let id = self.keymap_panels.insert(panel); + if let Some(layout_name) = keymap.and_then(|k| k.inner.layouts().next()) { + self.keymap_ids.insert(layout_name.into(), id); + } else { + log::error!("XKB keymap without a layout!"); + }; + Ok(id) + } + + fn switch_keymap(&mut self, keymap: &XkbKeymap, app: &mut AppState) -> anyhow::Result<()> { + let Some(layout_name) = keymap.inner.layouts().next() else { + log::error!("XKB keymap without a layout!"); + return Ok(()); + }; + + if let Some(new_key) = self.keymap_ids.get(layout_name) { + if self.active_keymap.eq(new_key) { + return Ok(()); + } + self.internal_switch_keymap(*new_key); + } else { + let new_key = self.add_new_keymap(Some(keymap), app)?; + self.internal_switch_keymap(new_key); + } + Ok(()) + } + + fn internal_switch_keymap(&mut self, new_key: KeyboardPanelKey) { + let state_from = self + .keymap_panels + .get_mut(self.active_keymap) + .unwrap() + .state + .take(); + + self.active_keymap = new_key; + + self.keymap_panels + .get_mut(self.active_keymap) + .unwrap() + .state = state_from; + } + + fn panel(&mut self) -> &mut GuiPanel { + self.keymap_panels.get_mut(self.active_keymap).unwrap() // want panic + } } impl OverlayBackend for KeyboardBackend { fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> { - self.panel.init(app) + self.panel().init(app) } fn should_render(&mut self, app: &mut AppState) -> anyhow::Result { - self.panel.should_render(app) + self.panel().should_render(app) } fn render(&mut self, app: &mut AppState, rdr: &mut RenderResources) -> anyhow::Result<()> { - self.panel.render(app, rdr) + self.panel().render(app, rdr) } fn frame_meta(&mut self) -> Option { - self.panel.frame_meta() + self.panel().frame_meta() } fn pause(&mut self, app: &mut AppState) -> anyhow::Result<()> { - self.panel.state.modifiers = 0; + self.panel().state.modifiers = 0; app.hid_provider.set_modifiers_routed(0); - self.panel.pause(app) + self.panel().pause(app) } fn resume(&mut self, app: &mut AppState) -> anyhow::Result<()> { - self.panel.resume(app)?; - self.panel.push_event( + self.panel().resume(app)?; + self.panel().push_event( app, &wgui::event::Event::InternalStateChange(InternalStateChangeEvent { metadata: 0 }), ); @@ -56,27 +179,27 @@ impl OverlayBackend for KeyboardBackend { } fn notify(&mut self, app: &mut AppState, event_data: OverlayEventData) -> anyhow::Result<()> { - self.panel.notify(app, event_data) + self.panel().notify(app, event_data) } fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) { - self.panel.on_pointer(app, hit, pressed); - self.panel.push_event( + self.panel().on_pointer(app, hit, pressed); + self.panel().push_event( app, &wgui::event::Event::InternalStateChange(InternalStateChangeEvent { metadata: 0 }), ); } fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: WheelDelta) { - self.panel.on_scroll(app, hit, delta); + self.panel().on_scroll(app, hit, delta); } fn on_left(&mut self, app: &mut AppState, pointer: usize) { - self.panel.on_left(app, pointer); + self.panel().on_left(app, pointer); } fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> HoverResult { - self.panel.on_hover(app, hit) + self.panel().on_hover(app, hit) } fn get_interaction_transform(&mut self) -> Option { - self.panel.get_interaction_transform() + self.panel().get_interaction_transform() } } @@ -86,6 +209,20 @@ struct KeyboardState { processes: Vec, } +impl KeyboardState { + fn take(&mut self) -> Self { + Self { + modifiers: self.modifiers, + alt_modifier: self.alt_modifier, + processes: { + let mut processes = vec![]; + std::mem::swap(&mut processes, &mut self.processes); + processes + }, + } + } +} + const KEY_AUDIO_WAV: &[u8] = include_bytes!("../../res/421581.wav"); fn play_key_click(app: &mut AppState) { diff --git a/wlx-overlay-s/src/state.rs b/wlx-overlay-s/src/state.rs index 4b90d64..596b95c 100644 --- a/wlx-overlay-s/src/state.rs +++ b/wlx-overlay-s/src/state.rs @@ -1,8 +1,7 @@ use glam::Affine3A; use idmap::IdMap; use smallvec::{SmallVec, smallvec}; -use smithay::backend::renderer::Texture; -use std::{ops::Not, sync::Arc}; +use std::sync::Arc; use wgui::{ font_config::WguiFontConfig, gfx::WGfx, globals::WguiGlobals, parser::parse_color_hex, renderer_vk::context::SharedContext as WSharedContext, diff --git a/wlx-overlay-s/src/subsystem/hid/mod.rs b/wlx-overlay-s/src/subsystem/hid/mod.rs index 4ffe476..f0a8e2b 100644 --- a/wlx-overlay-s/src/subsystem/hid/mod.rs +++ b/wlx-overlay-s/src/subsystem/hid/mod.rs @@ -574,12 +574,12 @@ pub const fn get_key_type(key: VirtualKey) -> KeyType { } pub struct XkbKeymap { - pub keymap: xkb::Keymap, + pub inner: xkb::Keymap, } impl XkbKeymap { pub fn label_for_key(&self, key: VirtualKey, modifier: KeyModifier) -> String { - let mut state = xkb::State::new(&self.keymap); + let mut state = xkb::State::new(&self.inner); if modifier > 0 && let Some(mod_key) = MODS_TO_KEYS.get(modifier) { @@ -592,8 +592,8 @@ impl XkbKeymap { } pub fn has_altgr(&self) -> bool { - let state0 = xkb::State::new(&self.keymap); - let mut state1 = xkb::State::new(&self.keymap); + let state0 = xkb::State::new(&self.inner); + let mut state1 = xkb::State::new(&self.inner); state1.update_key( xkb::Keycode::from(VirtualKey::Meta as u32), xkb::KeyDirection::Down, diff --git a/wlx-overlay-s/src/subsystem/hid/wayland.rs b/wlx-overlay-s/src/subsystem/hid/wayland.rs index 052b134..1fe9624 100644 --- a/wlx-overlay-s/src/subsystem/hid/wayland.rs +++ b/wlx-overlay-s/src/subsystem/hid/wayland.rs @@ -122,7 +122,7 @@ impl Dispatch for WlKeymapHandler { break; } - state.keymap = Some(XkbKeymap { keymap }); + state.keymap = Some(XkbKeymap { inner: keymap }); } Ok(None) => { log::error!("Could not load keymap: no keymap"); diff --git a/wlx-overlay-s/src/subsystem/hid/x11.rs b/wlx-overlay-s/src/subsystem/hid/x11.rs index 168ee07..89a1750 100644 --- a/wlx-overlay-s/src/subsystem/hid/x11.rs +++ b/wlx-overlay-s/src/subsystem/hid/x11.rs @@ -31,5 +31,5 @@ pub fn get_keymap_x11() -> anyhow::Result { } let keymap = keymap_new_from_device(&context, &conn, device_id, xkb::KEYMAP_COMPILE_NO_FLAGS); - Ok(XkbKeymap { keymap }) + Ok(XkbKeymap { inner: keymap }) } diff --git a/wlx-overlay-s/src/windowing/manager.rs b/wlx-overlay-s/src/windowing/manager.rs index 0eca306..555b7cd 100644 --- a/wlx-overlay-s/src/windowing/manager.rs +++ b/wlx-overlay-s/src/windowing/manager.rs @@ -15,7 +15,7 @@ use crate::{ FRAME_COUNTER, backend::task::OverlayTask, overlays::{ - anchor::create_anchor, edit::EditWrapperManager, keyboard::builder::create_keyboard, + anchor::create_anchor, edit::EditWrapperManager, keyboard::create_keyboard, screen::create_screens, toast::Toast, watch::create_watch, }, state::AppState,