### Example changelog header Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/_sources/hacking.md.txt Format for the first line of the debian/changelog file. ```text squeekboard (1.22.0) experimental; urgency=medium ``` -------------------------------- ### Install phoc on Debian-based systems Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/_sources/tutorial.md.txt Use this command to install the phoc compositor required for local testing of Squeekboard. ```bash sudo apt install phoc ``` -------------------------------- ### Install Squeekboard dependencies on Debian Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/_sources/hacking.md.txt Use these commands on a Debian-based system to install necessary build tools and project dependencies. ```sh $ sudo apt-get -y install build-essential $ sudo apt-get -y build-dep . ``` -------------------------------- ### Start Phoc with Squeekboard Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/_sources/hacking.md.txt Command to launch the Phoc compositor with Squeekboard in a nested session. ```sh $ SQUEEKBOARD_DEBUG=force_show GTK_THEME=Adwaita:dark phoc --config 'path-to/phoc.ini' --exec '_build/src/squeekboard' ``` -------------------------------- ### fn start(destination: Destination) -> Result Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/actors/external/screensaver/fn.start.html Initiates the screensaver functionality by targeting the provided destination. ```APIDOC ## fn start(destination: Destination) -> Result ### Description Initiates the screensaver process. This function sends a start command to the specified destination actor. ### Parameters - **destination** (Destination) - Required - The target destination for the screensaver start command. ### Returns - **Result** - Returns an empty result on success, or an Error if the operation fails. ``` -------------------------------- ### fn start(mgr: Manager) -> Result> Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/actors/external/debug/fn.start.html Initializes the debug actor with the specified manager. ```APIDOC ## fn start ### Description Initializes the debug actor using the provided manager instance. ### Signature `fn start(mgr: Manager) -> Result>` ### Parameters - **mgr** (Manager) - Required - The manager instance used to initialize the debug actor. ### Returns - **Result>** - Returns Ok(()) on success, or an error if the initialization fails. ``` -------------------------------- ### Define BTN_START constant Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/keycodes/constant.BTN_START.html Represents the start button keycode as a 32-bit unsigned integer. ```rust pub const BTN_START: u32 = 0x13b; ``` -------------------------------- ### Define KEY_MACRO_RECORD_START constant Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/keycodes/constant.KEY_MACRO_RECORD_START.html Represents the key code for starting a macro recording session. ```rust pub const KEY_MACRO_RECORD_START: u32 = 0x2b0; ``` -------------------------------- ### Define button outlines in YAML Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/_sources/layouts.md.txt Example of defining a default button size in the layout YAML file. ```yaml outlines: default: { width: 32, height: 52 } ``` -------------------------------- ### Function signature for start Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/actors/external/debug/fn.start.html Defines the entry point for the debug actor manager, returning a Result indicating success or failure. ```rust fn start(mgr: Manager) -> Result> ``` -------------------------------- ### Configure Phoc for Squeekboard Testing Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/_sources/hacking.md.txt Example configuration for phoc.ini to simulate PinePhone Pro display dimensions. ```ini [output:WL-1] # Resolution in px. Swap the values to change between vertical or horizontal orientation. mode = 720x1440 # Width and height in mm. phys_width = 68 phys_height = 136 ``` -------------------------------- ### Get Directory String Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/data/loading.rs.html Determines the directory path for layout lookups based on content purpose and overlay. ```rust fn get_directory_string( content_purpose: ContentPurpose, overlay: Option<&str>) -> String { use self::LayoutPurpose::*; ``` -------------------------------- ### Configure Panel Size State Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/panel.rs.html Examples of configuring the panel state with desired dimensions and handling stale versus valid configuration events. ```rust let good_state = state.clone().configure(Size { width: 50, height: 50 }); assert_eq!( good_state, State::SizeAllocated { output, wanted_height: 50, allocated: Size { width: 50, height: 50 }, }, ); ``` ```rust let state = state.configure(Size { width: 50, height: 100 }); let state = state.configure(Size { width: 50, height: 50 }); assert_eq!( state, State::SizeAllocated { output, wanted_height: 50, allocated: Size { width: 50, height: 50 }, }, ); ``` -------------------------------- ### Start Debug D-Bus Service Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/actors/external/debug.rs.html Initializes the D-Bus connection and registers the object server for the debug interface. ```rust fn start(mgr: Manager) -> Result> { let connection = Connection::new_session()?; fdo::DBusProxy::new(&connection)?.request_name( "sm.puri.SqueekDebug", fdo::RequestNameFlags::ReplaceExisting.into(), )?; let mut object_server = ObjectServer::new(&connection); object_server.at(&"/sm/puri/SqueekDebug".try_into()?, mgr)?; loop { if let Err(err) = object_server.try_handle_next() { eprintln!("{}", err); } } } ``` -------------------------------- ### Define a base view Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/_sources/layouts.md.txt The views dictionary defines the layout structure, with 'base' being the required starting view. ```yaml views: base: - "q w e r t y u i o p å" ``` -------------------------------- ### Update NEWS file format Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/_sources/hacking.md.txt Example of the Markdown syntax used to document changes in the NEWS file. ```markdown squeekboard 1.22.0 "Superposition" ----------------------------- * Changes: * Fixed panel sizing when scaling ... ``` -------------------------------- ### gnome_xkb_info_new Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/locale/c/fn.gnome_xkb_info_new.html Initializes a new instance of GnomeXkbInfo. ```APIDOC ## gnome_xkb_info_new ### Description Creates and returns a new instance of `GnomeXkbInfo`. ### Signature `pub unsafe extern "C" fn gnome_xkb_info_new() -> GnomeXkbInfo` ``` -------------------------------- ### generate_keycodes Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/keyboard/fn.generate_keycodes.html Generates a mapping where each key gets a keycode, starting from 9, because 8 results in keycode 0, which the compositor likes to discard. ```APIDOC ## Function: generate_keycodes ### Description Generates a mapping where each key gets a keycode, starting from 9, because 8 results in keycode 0, which the compositor likes to discard. ### Signature `pub fn generate_keycodes<'a, C: IntoIterator>(key_names: C) -> HashMap` ### Parameters - **key_names** (C: IntoIterator) - Required - An iterator of key names to be mapped to keycodes. ### Returns - **HashMap** - A map containing the generated keycode for each provided key name. ``` -------------------------------- ### Test Layout Pop Behavior Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/layout.rs.html Unit test setup for verifying view layout construction with specific button actions. ```rust #[test] fn latch_pop_layout() { let switch = Action::LockView { lock: "locked".into(), unlock: "base".into(), latches: true, looks_locked_from: vec![], }; let submit = Action::Erase; let view = View::new(vec![( 0.0, Row::new(vec![ ( 0.0, Button { action: switch.clone(), ..make_button("switch".into()) }, ), ( 1.0, Button { action: submit.clone(), ..make_button("submit".into()) }, ), ]), )]); ``` -------------------------------- ### Initialize XKB Keymap and State Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/keyboard.rs.html Creates an XKB context and keymap from a string, then initializes the state to verify key symbols. ```rust let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS); let keymap = xkb::Keymap::new_from_string( &context, keymaps[1].clone(), // this index is part of the test xkb::KEYMAP_FORMAT_TEXT_V1, xkb::KEYMAP_COMPILE_NO_FLAGS, ).expect("Failed to create keymap"); let state = xkb::State::new(&keymap); assert_eq!(state.key_get_one_sym(9u32.into()), xkb::keysyms::KEY_a.into()); } ``` -------------------------------- ### Build Squeekboard using Meson and Ninja Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/_sources/hacking.md.txt Commands to configure the build directory and compile the project. ```sh $ meson setup _build $ ninja -C _build ``` -------------------------------- ### Start screensaver actor function signature Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/actors/external/screensaver/fn.start.html Defines the function signature for starting the screensaver actor with a specified destination. ```rust fn start(destination: Destination) -> Result ``` -------------------------------- ### XkbInfo::new Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/locale/struct.XkbInfo.html Creates a new instance of XkbInfo. ```APIDOC ### pub fn new() -> XkbInfo Creates a new instance of the XkbInfo struct. ``` -------------------------------- ### Get String capacity Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/action/type.View.html Returns the current capacity of the String in bytes. ```rust let s = String::with_capacity(10); assert!(s.capacity() >= 10); ``` -------------------------------- ### Get weak reference count Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/actors/popover/type.Destination.html Returns the number of Weak pointers to the allocation. ```rust use std::sync::Arc; let five = Arc::new(5); let _weak_five = Arc::downgrade(&five); // This assertion is deterministic because we haven't shared // the `Arc` or `Weak` between threads. assert_eq!(1, Arc::weak_count(&five)); ``` -------------------------------- ### Implement DivCeil for Millimeter Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/util/trait.DivCeil.html Example implementation of the DivCeil trait for the Millimeter type. ```rust type Output = Millimeter ``` -------------------------------- ### ZwpVirtualKeyboardV1::null Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/vkeyboard/c/struct.ZwpVirtualKeyboardV1.html Creates a new null instance of ZwpVirtualKeyboardV1. ```APIDOC ## pub fn null() -> Self ### Description Creates a new null instance of the ZwpVirtualKeyboardV1 struct. ### Returns - **Self** - A new instance of ZwpVirtualKeyboardV1. ``` -------------------------------- ### Test layout view transitions Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/layout.rs.html Demonstrates initializing a layout and applying view transitions to verify state changes. ```rust let mut layout = Layout { state: LayoutState { current_view: "base".into(), view_latched: LatchedState::Not, active_buttons: ActiveButtons(HashMap::new()), }, shape: LayoutData { keymaps: Vec::new(), kind: ArrangementKind::Base, margins: Margins { top: 0.0, left: 0.0, right: 0.0, bottom: 0.0, }, views: hashmap! { // Both can use the same structure. // Switching doesn't depend on the view shape // as long as the switching button is present. "base".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()), "locked".into() => (c::Point { x: 0.0, y: 0.0 }, view), }, purpose: ContentPurpose::Normal, }, }; // Basic cycle layout.apply_view_transition(&switch); assert_eq!(&layout.state.current_view, "locked"); layout.apply_view_transition(&switch); assert_eq!(&layout.state.current_view, "locked"); layout.apply_view_transition(&submit); assert_eq!(&layout.state.current_view, "locked"); layout.apply_view_transition(&switch); assert_eq!(&layout.state.current_view, "base"); layout.apply_view_transition(&switch); // Unlatch assert_eq!(&layout.state.current_view, "locked"); layout.apply_view_transition(&submit); assert_eq!(&layout.state.current_view, "base"); } ``` -------------------------------- ### Generate Reference Documentation Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/_sources/hacking.md.txt Commands to build local documentation for the project. ```sh $ cd squeekboard_build/ $ .../squeekboard_source/cargo.sh doc --no-deps --document-private-items ``` -------------------------------- ### Get strong reference count Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/actors/popover/type.Destination.html Returns the number of strong Arc pointers to the allocation. ```rust use std::sync::Arc; let five = Arc::new(5); let _also_five = Arc::clone(&five); // This assertion is deterministic because we haven't shared // the `Arc` between threads. assert_eq!(2, Arc::strong_count(&five)); ``` -------------------------------- ### IMService::new Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/imservice/struct.IMService.html Creates a new instance of IMService. ```APIDOC ## pub fn new(im: InputMethod, sender: Threaded) -> Box ### Description Creates a new IMService instance with the provided InputMethod and Application sender. ### Parameters - **im** (InputMethod) - Required - The input method instance. - **sender** (Threaded) - Required - The threaded application sender. ``` -------------------------------- ### Test module declaration Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/data/loading.rs.html Standard test module setup for the layout loading logic. ```rust #[cfg(test)] mod tests { use super::*; ``` -------------------------------- ### Initialize IMService Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/imservice.rs.html Creates a new IMService instance and connects C-level listeners to the input method. ```rust impl IMService { pub fn new( im: c::InputMethod, sender: main::EventLoop, ) -> Box { // IMService will be referenced to by C, // so it needs to stay in the same place in memory via Box let imservice = Box::new(IMService { im, sender, pending: IMProtocolState::default(), current: IMProtocolState::default(), preedit_string: String::new(), serial: Wrapping(0u32), }); unsafe { c::imservice_connect_listeners( im, imservice.as_ref() as *const IMService, ); } imservice } ``` -------------------------------- ### Initialize Squeekboard components Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/main.rs.html Initializes the main loop channels and state manager for the application. ```rust /// Creates what's possible in Rust to eliminate as many FFI calls as possible, /// because types aren't getting checked across their boundaries, /// and that leads to suffering. #[no_mangle] pub extern "C" fn squeek_init() -> RsObjects { // Set up channels let (sender, receiver) = MainContext::channel(Priority::default()); let now = Instant::now(); let state_manager = driver::Threaded::new(sender, state::Application::new(now)); debug::init(state_manager.clone()); ``` -------------------------------- ### Get XDG data directory Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/xdg/fn.data_dir.html Returns the XDG data directory as an Option containing a PathBuf. ```rust fn data_dir() -> Option ``` -------------------------------- ### Handle Settings Action Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/popover.rs.html Registers an action to open the settings panel via FFI. ```rust let settings_action = gio::SimpleAction::new("settings", None); settings_action.set_enabled(popover.settings_active); settings_action.connect_activate(move |_, _| { let s = CString::new("keyboard").unwrap(); unsafe { c::popover_open_settings_panel(s.as_ptr()) }; }); action_group.add_action(&settings_action); menu.insert_action_group("popup", Some(&action_group)); menu.bind_model(Some(&model), Some("popup")); glib::idle_add_local(move || { menu.popup(); glib::ControlFlow::Break }); } ``` -------------------------------- ### Get mutable reference to Arc Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/actors/popover/type.Destination.html Returns a mutable reference if no other Arc or Weak pointers exist. ```rust use std::sync::Arc; let mut x = Arc::new(3); *Arc::get_mut(&mut x).unwrap() = 4; assert_eq!(*x, 4); let _y = Arc::clone(&x); assert!(Arc::get_mut(&mut x).is_none()); ``` -------------------------------- ### Configure Keyboard Layouts Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/_sources/hacking.md.txt Set available input sources using gsettings. ```sh # Define all available layouts. First one is currently selected. $ gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us'), ('xkb', 'de')]" ``` -------------------------------- ### Get scale factor function signature Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/drawing/c/fn.eek_renderer_get_scale_factor.html The function signature for retrieving the scale factor from an EekRenderer. ```rust pub unsafe extern "C" fn eek_renderer_get_scale_factor( renderer: EekRenderer, ) -> u32 ``` -------------------------------- ### Map ContentPurpose to u32 Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/imservice/enum.ContentPurpose.html Example showing how to cast a ContentPurpose variant to its underlying u32 value. ```rust use rs::imservice::ContentPurpose; assert_eq!(ContentPurpose::Alpha as u32, 1); ``` -------------------------------- ### Implement Outcome for Outcome Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/event_loop/trait.Outcome.html Example implementation of the Outcome trait where the associated Commands type is defined. ```rust impl Outcome for Outcome { type Commands = Commands } ``` -------------------------------- ### Test Squeekboard with an Application Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/_sources/hacking.md.txt Commands to run the entry tool, optionally targeting a specific Wayland display. ```sh $ python3 tools/entry.py ``` ```sh $ WAYLAND_DISPLAY=wayland-1 python3 tools/entry.py ``` -------------------------------- ### Initialize the Application state Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/state.rs.html Creates a new Application instance with conservative default values. ```rust pub fn new(now: Instant) -> Self { Self { im: InputMethod::InactiveSince(now), visibility_override: visibility::State::NotForced, physical_keyboard: Presence::Missing, debug_mode_enabled: false, preferred_output: None, outputs: Default::default(), layout_choice: LayoutChoice { name: String::from("us"), source: LayoutSource::Xkb, }, overlay_layout: None, } } ``` -------------------------------- ### Get Layout Kind C Interface Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/layout/c/fn.squeek_layout_get_kind.html Retrieves the kind of the provided layout as a 32-bit unsigned integer. ```rust #[no_mangle] pub extern "C" fn squeek_layout_get_kind(layout: *const Layout) -> u32 ``` -------------------------------- ### pub fn show(window: EekGtkKeyboard, position: Bounds, popover: &State, app_state: Threaded) Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/popover/fn.show.html Displays a popover at a specified position on the provided keyboard window. ```APIDOC ## show ### Description Displays a popover on the EekGtkKeyboard window at the specified bounds. ### Signature `pub fn show(window: EekGtkKeyboard, position: Bounds, popover: &State, app_state: Threaded)` ### Parameters - **window** (EekGtkKeyboard) - The keyboard window instance. - **position** (Bounds) - The coordinates and dimensions for the popover placement. - **popover** (&State) - The state object representing the popover to be shown. - **app_state** (Threaded) - The current application state. ``` -------------------------------- ### Configure Layout and View Transitions Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/layout.rs.html Defines a keyboard view with switchable buttons and demonstrates state transitions between views. ```rust let view = View::new(vec![( 0.0, Row::new(vec![ ( 0.0, Button { action: switch.clone(), ..make_button("switch".into()) }, ), ( 1.0, Button { action: submit.clone(), ..make_button("submit".into()) }, ), ]), )]); let mut layout = Layout { state: LayoutState { current_view: "base".into(), view_latched: LatchedState::Not, active_buttons: ActiveButtons(HashMap::new()), }, shape: LayoutData { keymaps: Vec::new(), kind: ArrangementKind::Base, margins: Margins { top: 0.0, left: 0.0, right: 0.0, bottom: 0.0, }, views: hashmap! { // All can use the same structure. // Switching doesn't depend on the view shape // as long as the switching button is present. "base".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()), "locked".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()), "ĄĘ".into() => (c::Point { x: 0.0, y: 0.0 }, view), }, purpose: ContentPurpose::Normal, }, }; // Latch twice, then Ąto-unlatch across 2 levels layout.apply_view_transition(&switch); println!("{:?}", layout.state.view_latched); assert_eq!(&layout.state.current_view, "locked"); layout.apply_view_transition(&switch_again); println!("{:?}", layout.state.view_latched); assert_eq!(&layout.state.current_view, "ĄĘ"); layout.apply_view_transition(&submit); println!("{:?}", layout.state.view_latched); assert_eq!(&layout.state.current_view, "base"); } ``` -------------------------------- ### Main function signature Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/test_layout/fn.main.html Defines the entry point for the test_layout module. ```rust pub(crate) fn main() ``` -------------------------------- ### Get XDG data directory path Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/xdg/fn.data_path.html Retrieves the path to a specific directory within the XDG data directory. ```rust pub fn data_path

(path: P) -> Option where P: AsRef, ``` -------------------------------- ### Initialize Popover Display Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/popover.rs.html Prepares the popover state by aggregating system and overlay layouts and translating them for the UI. ```rust pub fn show( window: EekGtkKeyboard, position: Bounds, popover: &actors::popover::State, app_state: receiver::State, ) { unsafe { gtk::set_initialized() }; let window = unsafe { gtk::Widget::from_glib_none(window.0) }; let overlay_layouts = resources::get_overlays().into_iter() .map(|name| LayoutId::Local(name.to_string())); let settings = get_settings("org.gnome.desktop.input-sources"); let inputs = settings .map(|settings| { let inputs = settings.value("sources"); variants::get_tuples(inputs) }) .unwrap_or_else(|| Vec::new()); let system_layouts: Vec = inputs.into_iter() .map(|(kind, name)| LayoutId::System { kind, name }) .collect(); let all_layouts: Vec = system_layouts.clone() .into_iter() .chain(overlay_layouts) .collect(); let translated_names = translate_layout_names(&system_layouts); // sorted collection of language layouts let mut human_names: Vec<(OwnedTranslation, LayoutId)> = translated_names .into_iter() .zip(system_layouts.clone().into_iter()) .collect(); ``` -------------------------------- ### System and Media Key Constants Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/keycodes.rs.html Definitions for various media, system, and application-specific keys. ```rust pub const KEY_OK: u32 = 0x160; pub const KEY_SELECT: u32 = 0x161; pub const KEY_GOTO: u32 = 0x162; pub const KEY_CLEAR: u32 = 0x163; pub const KEY_POWER2: u32 = 0x164; pub const KEY_OPTION: u32 = 0x165; pub const KEY_INFO: u32 = 0x166; pub const KEY_TIME: u32 = 0x167; pub const KEY_VENDOR: u32 = 0x168; pub const KEY_ARCHIVE: u32 = 0x169; pub const KEY_PROGRAM: u32 = 0x16a; pub const KEY_CHANNEL: u32 = 0x16b; pub const KEY_FAVORITES: u32 = 0x16c; pub const KEY_EPG: u32 = 0x16d; pub const KEY_PVR: u32 = 0x16e; pub const KEY_MHP: u32 = 0x16f; pub const KEY_LANGUAGE: u32 = 0x170; pub const KEY_TITLE: u32 = 0x171; pub const KEY_SUBTITLE: u32 = 0x172; pub const KEY_ANGLE: u32 = 0x173; pub const KEY_FULL_SCREEN: u32 = 0x174; pub const KEY_ZOOM: u32 = KEY_FULL_SCREEN; pub const KEY_MODE: u32 = 0x175; pub const KEY_KEYBOARD: u32 = 0x176; pub const KEY_ASPECT_RATIO: u32 = 0x177; pub const KEY_SCREEN: u32 = KEY_ASPECT_RATIO; pub const KEY_PC: u32 = 0x178; pub const KEY_TV: u32 = 0x179; pub const KEY_TV2: u32 = 0x17a; pub const KEY_VCR: u32 = 0x17b; pub const KEY_VCR2: u32 = 0x17c; pub const KEY_SAT: u32 = 0x17d; pub const KEY_SAT2: u32 = 0x17e; pub const KEY_CD: u32 = 0x17f; pub const KEY_TAPE: u32 = 0x180; pub const KEY_RADIO: u32 = 0x181; pub const KEY_TUNER: u32 = 0x182; pub const KEY_PLAYER: u32 = 0x183; pub const KEY_TEXT: u32 = 0x184; pub const KEY_DVD: u32 = 0x185; pub const KEY_AUX: u32 = 0x186; pub const KEY_MP3: u32 = 0x187; pub const KEY_AUDIO: u32 = 0x188; pub const KEY_VIDEO: u32 = 0x189; pub const KEY_DIRECTORY: u32 = 0x18a; pub const KEY_LIST: u32 = 0x18b; pub const KEY_MEMO: u32 = 0x18c; pub const KEY_CALENDAR: u32 = 0x18d; pub const KEY_RED: u32 = 0x18e; pub const KEY_GREEN: u32 = 0x18f; pub const KEY_YELLOW: u32 = 0x190; pub const KEY_BLUE: u32 = 0x191; pub const KEY_CHANNELUP: u32 = 0x192; pub const KEY_CHANNELDOWN: u32 = 0x193; pub const KEY_FIRST: u32 = 0x194; pub const KEY_LAST: u32 = 0x195; pub const KEY_AB: u32 = 0x196; pub const KEY_NEXT: u32 = 0x197; pub const KEY_RESTART: u32 = 0x198; pub const KEY_SLOW: u32 = 0x199; pub const KEY_SHUFFLE: u32 = 0x19a; pub const KEY_BREAK: u32 = 0x19b; pub const KEY_PREVIOUS: u32 = 0x19c; pub const KEY_DIGITS: u32 = 0x19d; pub const KEY_TEEN: u32 = 0x19e; pub const KEY_TWEN: u32 = 0x19f; pub const KEY_VIDEOPHONE: u32 = 0x1a0; pub const KEY_GAMES: u32 = 0x1a1; pub const KEY_ZOOMIN: u32 = 0x1a2; pub const KEY_ZOOMOUT: u32 = 0x1a3; pub const KEY_ZOOMRESET: u32 = 0x1a4; pub const KEY_WORDPROCESSOR: u32 = 0x1a5; pub const KEY_EDITOR: u32 = 0x1a6; pub const KEY_SPREADSHEET: u32 = 0x1a7; pub const KEY_GRAPHICSEDITOR: u32 = 0x1a8; pub const KEY_PRESENTATION: u32 = 0x1a9; pub const KEY_DATABASE: u32 = 0x1aa; pub const KEY_NEWS: u32 = 0x1ab; pub const KEY_VOICEMAIL: u32 = 0x1ac; pub const KEY_ADDRESSBOOK: u32 = 0x1ad; pub const KEY_MESSENGER: u32 = 0x1ae; pub const KEY_DISPLAYTOGGLE: u32 = 0x1af; pub const KEY_BRIGHTNESS_TOGGLE: u32 = KEY_DISPLAYTOGGLE; pub const KEY_SPELLCHECK: u32 = 0x1b0; pub const KEY_LOGOFF: u32 = 0x1b1; pub const KEY_DOLLAR: u32 = 0x1b2; pub const KEY_EURO: u32 = 0x1b3; ``` -------------------------------- ### Implement XkbInfo wrapper Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/locale.rs.html Provides a safe Rust wrapper around the GnomeXkbInfo C structure, including resource cleanup. ```rust pub struct XkbInfo(c::GnomeXkbInfo); impl XkbInfo { pub fn new() -> XkbInfo { XkbInfo(unsafe { c::gnome_xkb_info_new() }) } pub fn get_display_name(&self, id: &str) -> Result { let id = cstring_safe(id); let id_ref = id.as_ptr(); let mut display_name: *const c_char = ptr::null(); let found = unsafe { c::gnome_xkb_info_get_layout_info( self.0, id_ref, &mut display_name as *mut *const c_char, ptr::null(), ptr::null(), ptr::null(), ) }; if found != 0 && !display_name.is_null() { let display_name = unsafe { CStr::from_ptr(display_name) }; display_name.to_str() .map(str::to_string) .map_err(Error::StringConversion) } else { Err(Error::NoInfo) } } } impl Drop for XkbInfo { fn drop(&mut self) { unsafe { c::g_object_unref(self.0) } } } ``` -------------------------------- ### Get Current Layout Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/popover.rs.html Determines the active layout by checking for overlays first, falling back to the primary system layout. ```rust /// Takes into account first any overlays, then system layouts from the list fn get_current_layout( popover: &actors::popover::State, system_layouts: &Vec, ) -> Option { match &popover.overlay { Some(name) => Some(LayoutId::Local(name.into())), None => system_layouts.get(0).map(LayoutId::clone), } } ``` -------------------------------- ### Get Preferred Layout Names Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/data/loading.rs.html Calculates a prioritized list of layout names, including base variants and fallback defaults. ```rust fn get_preferred_names(name: &str, kind: ArrangementKind) -> Vec<(ArrangementKind, String)> { let mut ret = _get_arrangement_names(name, kind); let base_name_preferences = { let mut parts = name.splitn(2, '+'); match parts.next() { Some(base) => { // The name is already equal to base, so nothing to add if base == name { vec![] } else { _get_arrangement_names(base, kind) } }, // The layout's base name starts with a "+". Weird but OK. None => { log_print!(logging::Level::Surprise, "Base layout name is empty: {}", name); vec![] } } }; ret.extend(base_name_preferences.into_iter()); let fallback_names = _get_arrangement_names(FALLBACK_LAYOUT_NAME, kind); ret.extend(fallback_names.into_iter()); ret } ``` -------------------------------- ### Layout::from_file Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/data/parsing/struct.Layout.html Loads a keyboard layout from a file path. ```APIDOC ## pub fn from_file(path: PathBuf) -> Result ### Description Loads a keyboard layout configuration from a file at the provided path. ### Parameters - **path** (PathBuf) - Required - The filesystem path to the layout file. ### Returns - **Result** - Returns the loaded Layout or an Error if the file could not be read or parsed. ``` -------------------------------- ### Get a raw pointer to Arc data Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/actors/popover/type.Destination.html Provides a raw pointer to the data without consuming the Arc or affecting reference counts. ```rust use std::sync::Arc; let x = Arc::new("hello".to_owned()); let y = Arc::clone(&x); let x_ptr = Arc::as_ptr(&x); assert_eq!(x_ptr, Arc::as_ptr(&y)); assert_eq!(unsafe { &*x_ptr }, "hello"); ``` -------------------------------- ### pub fn init(destination: Destination) Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/actors/external/screensaver/fn.init.html Initializes the screensaver actor to begin listening for screen lock changes. This function takes a destination parameter to route the events. ```APIDOC ## Function: init ### Description Initializes the screensaver actor to listen for screen lock changes. ### Signature `pub fn init(destination: Destination)` ### Parameters - **destination** (Destination) - The destination to which screensaver events will be sent. ``` -------------------------------- ### Generate Keycodes Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/keyboard.rs.html Generates a mapping of key names to KeyCode objects, starting from an offset of 9 to avoid compositor issues with keycode 0. ```rust pub fn generate_keycodes<'a, C: IntoIterator>( key_names: C, ) -> HashMap { // Some clients try to interpret keymaps as if they were input-sequences coming from evdev. // Workaround: Only use keycodes which directly produce characters. let allowed = [KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_BACKSLASH, KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M, KEY_COMMA, KEY_DOT, KEY_SLASH]; let keycode_offset = 8; let mut keycode_map = HashMap::from_iter( // Sort to remove a source of indeterminism in keycode assignment. sorted(key_names.into_iter()) .zip(util::cycle_count((9..255).filter(|x| allowed.contains(&(x - keycode_offset))))) .map(|(name, (mut code, mut keymap_idx))| { // Some apps expect specific keycodes for certain characters/functions. // Reserve the first 2 keymaps (0 and 1) for sorting those manually, // and use keymap_idx 2 and higher for other keycodes, // to not assign identical keycodes twice. // TODO: Add the "Shift"-modifier for keycodes on keymap 1. keymap_idx = keymap_idx + 2; if name == "1" { code = KEY_1 + keycode_offset; keymap_idx = 0 } if name == "2" { code = KEY_2 + keycode_offset; keymap_idx = 0 } if name == "3" { code = KEY_3 + keycode_offset; keymap_idx = 0 } if name == "4" { code = KEY_4 + keycode_offset; keymap_idx = 0 } if name == "5" { code = KEY_5 + keycode_offset; keymap_idx = 0 } if name == "6" { code = KEY_6 + keycode_offset; keymap_idx = 0 } if name == "7" { code = KEY_7 + keycode_offset; keymap_idx = 0 } if name == "8" { code = KEY_8 + keycode_offset; keymap_idx = 0 } if name == "9" { code = KEY_9 + keycode_offset; keymap_idx = 0 } if name == "0" { code = KEY_0 + keycode_offset; keymap_idx = 0 } if name == "a" { code = KEY_A + keycode_offset; keymap_idx = 0 } if name == "b" { code = KEY_B + keycode_offset; keymap_idx = 0 } if name == "c" { code = KEY_C + keycode_offset; keymap_idx = 0 } if name == "d" { code = KEY_D + keycode_offset; keymap_idx = 0 } if name == "e" { code = KEY_E + keycode_offset; keymap_idx = 0 } if name == "f" { code = KEY_F + keycode_offset; keymap_idx = 0 } if name == "g" { code = KEY_G + keycode_offset; keymap_idx = 0 } if name == "h" { code = KEY_H + keycode_offset; keymap_idx = 0 } if name == "i" { code = KEY_I + keycode_offset; keymap_idx = 0 } if name == "j" { code = KEY_J + keycode_offset; keymap_idx = 0 } if name == "k" { code = KEY_K + keycode_offset; keymap_idx = 0 } if name == "l" { code = KEY_L + keycode_offset; keymap_idx = 0 } if name == "m" { code = KEY_M + keycode_offset; keymap_idx = 0 } if name == "n" { code = KEY_N + keycode_offset; keymap_idx = 0 } if name == "o" { code = KEY_O + keycode_offset; keymap_idx = 0 } if name == "p" { code = KEY_P + keycode_offset; keymap_idx = 0 } if name == "q" { code = KEY_Q + keycode_offset; keymap_idx = 0 } if name == "r" { code = KEY_R + keycode_offset; keymap_idx = 0 } if name == "s" { code = KEY_S + keycode_offset; keymap_idx = 0 } if name == "t" { code = KEY_T + keycode_offset; keymap_idx = 0 } if name == "u" { code = KEY_U + keycode_offset; keymap_idx = 0 } if name == "v" { code = KEY_V + keycode_offset; keymap_idx = 0 } ``` -------------------------------- ### Initialize a View Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/layout.rs.html Constructs a new View, ensuring rows are sorted and centered based on their width. ```rust impl View { pub fn new(rows: Vec<(f64, Row)>) -> View { // Make sure rows are sorted by offset. debug_assert!({ let mut sorted = rows.clone(); sorted.sort_by(|(f1, _), (f2, _)| f1.partial_cmp(f2).unwrap()); sorted.iter().map(|(f, _)| *f).collect::>() == rows.iter().map(|(f, _)| *f).collect::>() }); // No need to call `get_rows()`, // as the biggest row is the most far reaching in both directions // because they are all centered. let width = find_max_double(rows.iter(), |(_offset, row)| row.size.width); let height = rows.iter().next_back() .map(|(y_offset, row)| row.size.height + y_offset) .unwrap_or(0.0); // Center the rows let rows = rows.into_iter().map(|(y_offset, row)| {( c::Point { x: (width - row.size.width) / 2.0, y: y_offset, }, row, )}).collect::>(); View { rows, size: Size { width, height } } } ``` -------------------------------- ### Update Panel State and Assert Resize Command Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/panel.rs.html Demonstrates updating the panel state with a show command and verifying the resulting resize instruction. ```rust let (state, cmds) = dbg!(state).update(Command::Show { output, height: PixelSize { pixels: 50, scale_factor: 1 }, }); assert_eq!( cmds, vec![Update::Resize { height: 50 }], "{:?}", state, ); ``` -------------------------------- ### Implement LayoutData Methods Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/layout.rs.html Methods for querying button placement and calculating layout dimensions. ```rust impl LayoutData { fn get_button(&self, button: &ButtonPosition) -> Option<&Button> { let (_, view) = self.views.get(&button.view)?; let (_, row) = view.rows.get(button.row)?; let (_, key) = row.buttons.get(button.position_in_row)?; Some(key) } fn find_button_place(&self, button: &ButtonPosition) -> Option { let (_, view) = self.views.get(&button.view)?; procedures::find_button_place(view, (button.row, button.position_in_row)) } /// Calculates size without margins fn calculate_inner_size(&self) -> Size { View::calculate_super_size( self.views.iter().map(|(_, (_offset, v))| v).collect() ) } /// Size including margins fn calculate_size(&self) -> Size { let inner_size = self.calculate_inner_size(); Size { width: self.margins.left + inner_size.width + self.margins.right, height: ( self.margins.top + inner_size.height + self.margins.bottom ), } } pub fn calculate_transformation( &self, available: Size, ) -> c::Transformation { let gsettings = Settings::new("sm.puri.Squeekboard"); let stretch_layout_to_fit_panel = gsettings.boolean ("layout-shape-changes-to-fit-panel"); ``` -------------------------------- ### Retrieve input sources configuration Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/_sources/tutorial.md.txt Use this command to identify the current input sources and their associated layout names. ```sh $ gsettings get org.gnome.desktop.input-sources sources ``` -------------------------------- ### Initialize single key map Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/keyboard/fn.single_key_map_new.html Returns an array of 256 optional strings representing a keyboard key map. ```rust fn single_key_map_new() -> [Option; 256] ``` -------------------------------- ### Phoc configuration for basic/compact layout testing Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/_sources/layouts.md.txt Use these settings in Phoc to simulate a basic or compact keyboard shape. ```sh [output:WL-1] mode = 360x720 phys_width = 60 phys_height = 120 scale = 1.00 ``` -------------------------------- ### View utility methods Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/layout.rs.html Methods for retrieving view size, rows, and calculating super-size for multiple views. ```rust pub fn get_size(&self) -> Size { self.size.clone() } /// Returns positioned rows, with appropriate x offsets (centered) pub fn get_rows(&self) -> &Vec<(c::Point, Row)> { &self.rows } /// Returns a size which contains all the views /// if they are all centered on the same point. pub fn calculate_super_size(views: Vec<&View>) -> Size { Size { height: find_max_double( views.iter(), |view| view.size.height, ), width: find_max_double( views.iter(), |view| view.size.width, ), } } } ``` -------------------------------- ### Layout::from_resource Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/data/parsing/struct.Layout.html Loads a keyboard layout from a named resource. ```APIDOC ## pub fn from_resource(name: &str) -> Result ### Description Loads a keyboard layout configuration from a specified resource name. ### Parameters - **name** (&str) - Required - The name of the resource to load. ### Returns - **Result** - Returns the loaded Layout or a LoadError if the resource could not be found or parsed. ``` -------------------------------- ### fn to_layout_sources Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/data/loading/fn.to_layout_sources.html Converts layout paths into data sources for the keyboard layout system. ```APIDOC ## fn to_layout_sources ### Description Transforms an iterator of layout paths and their associated arrangement kinds into an iterator of data sources. ### Signature `fn to_layout_sources(layout_paths: impl Iterator, filesystem_path: Option) -> impl Iterator` ### Parameters - **layout_paths** (impl Iterator) - An iterator of tuples containing the arrangement kind and the layout path string. - **filesystem_path** (Option) - An optional base path for the filesystem to resolve the layout sources. ### Returns - **Iterator** (impl Iterator) - An iterator yielding tuples of the arrangement kind and the resolved data source. ``` -------------------------------- ### Verify hint order Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/src/rs/data/loading.rs.html Checks that content purpose hints correctly influence the layout loading order. ```rust #[test] fn test_preferences_order_hint() { let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Terminal, None, None); assert_eq!( sources.collect::>(), vec!( (ArrangementKind::Base, DataSource::Resource("terminal/nb".into())), ( ArrangementKind::Base, DataSource::Resource("terminal/us".into()) ), ) ); } ``` -------------------------------- ### String::new Usage Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/action/type.View.html Creates a new empty String. ```rust let s = String::new(); ``` -------------------------------- ### pub fn from_cstr(s: &CStr) -> KeyMap Source: https://world.pages.gitlab.gnome.org/Phosh/squeekboard/doc/rs/vkeyboard/c/struct.KeyMap.html Creates a new KeyMap instance from a C-style string. ```APIDOC ## pub fn from_cstr(s: &CStr) -> KeyMap ### Description Creates a new KeyMap instance from a provided C-style string. ### Parameters - **s** (&CStr) - Required - The C-style string used to initialize the KeyMap. ### Returns - **KeyMap** - A new instance of the KeyMap struct. ```