diff --git a/Cargo.lock b/Cargo.lock index 375aa93..031c856 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -757,10 +757,12 @@ name = "cursor-move-webapp" version = "0.1.0" dependencies = [ "dioxus", + "dioxus-html", "memfile", "rustix 1.1.4", "serde", "tokio", + "wasmtimer", "wayland-client", "wayland-protocols", "wayland-protocols-misc", @@ -5590,6 +5592,20 @@ dependencies = [ "semver", ] +[[package]] +name = "wasmtimer" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + [[package]] name = "wayland-backend" version = "0.3.12" diff --git a/crates/cursor-move-webapp/Cargo.toml b/crates/cursor-move-webapp/Cargo.toml index 9b8fdf2..d74a50f 100644 --- a/crates/cursor-move-webapp/Cargo.toml +++ b/crates/cursor-move-webapp/Cargo.toml @@ -8,6 +8,7 @@ edition = "2024" [dependencies] dioxus = { version = "0.7.3", features = ["router", "fullstack", "logger"] } +dioxus-html = { version = "0.7.3", features = ["serialize"] } serde = { version = "1.0.228", features = ["derive"] } wayland-client = { version = "0.31.12", optional = true } @@ -18,6 +19,7 @@ wayland-protocols-misc = { version = "0.3.10", features = ["client"], optional = wayland-protocols = { version = "0.32.10", features = ["client", "staging"], optional = true } xkb = {version = "0.3.0", optional = true} memfile = {version = "0.3.2", optional = true} +wasmtimer = "0.4.3" [features] default = ["web"] diff --git a/crates/cursor-move-webapp/assets/styling/controls.module.css b/crates/cursor-move-webapp/assets/styling/controls.module.css new file mode 100644 index 0000000..20c62df --- /dev/null +++ b/crates/cursor-move-webapp/assets/styling/controls.module.css @@ -0,0 +1,3 @@ +.controls { + flex-grow: 1; +} diff --git a/crates/cursor-move-webapp/assets/styling/keyboard_area.module.css b/crates/cursor-move-webapp/assets/styling/keyboard_area.module.css new file mode 100644 index 0000000..8362b83 --- /dev/null +++ b/crates/cursor-move-webapp/assets/styling/keyboard_area.module.css @@ -0,0 +1,8 @@ +.keyboard-area { + height: 48px; + + input { + width: 100%; + height: 100%; + } +} diff --git a/crates/cursor-move-webapp/assets/styling/main.css b/crates/cursor-move-webapp/assets/styling/main.css index 07bd1dc..814f086 100644 --- a/crates/cursor-move-webapp/assets/styling/main.css +++ b/crates/cursor-move-webapp/assets/styling/main.css @@ -3,8 +3,9 @@ body, #main { margin: 0; padding: 0; - min-height: 100vh; - width: 100vw; + min-height: 100dvh; + width: 100dvw; + overflow: hidden; } #main { diff --git a/crates/cursor-move-webapp/assets/styling/mouse_area.module.css b/crates/cursor-move-webapp/assets/styling/mouse_area.module.css index 2be2e3a..62e637c 100644 --- a/crates/cursor-move-webapp/assets/styling/mouse_area.module.css +++ b/crates/cursor-move-webapp/assets/styling/mouse_area.module.css @@ -1,5 +1,6 @@ .mouse-area { - background-color: white; + background: radial-gradient(#0004 15%, transparent 20%), white; + background-size: 15px 15px; touch-action: none; flex-grow: 1; diff --git a/crates/cursor-move-webapp/src/components/controls.rs b/crates/cursor-move-webapp/src/components/controls.rs new file mode 100644 index 0000000..5dc812c --- /dev/null +++ b/crates/cursor-move-webapp/src/components/controls.rs @@ -0,0 +1,99 @@ +use dioxus::{ + fullstack::{CborEncoding, WebSocketOptions, Websocket, extract::State, use_websocket}, + html::{ + geometry::{ElementSpace, euclid::Point2D}, + input_data::MouseButton, + }, + logger::tracing, + prelude::*, +}; +use serde::{Deserialize, Serialize}; + +use crate::components::{KeyboardArea, MouseArea}; + +#[component] +pub fn Controls() -> Element { + #[css_module("/assets/styling/controls.module.css")] + struct Styles; + + let mut socket = use_websocket(move || mouse_move(WebSocketOptions::new())); + + use_future(move || async move { + loop { + // Wait for the socket to connect + _ = socket.connect().await; + + // Loop poll with recv. Throws an error when the connection closes, making it possible + // to run code before the socket re-connects when the name input changes + while let Ok(message) = socket.recv().await { + tracing::info!("Received message: {:?}", message); + } + } + }); + + let event_handler = use_callback(move |evt| { + spawn(async move { + _ = socket.send(evt).await; + }); + }); + + rsx! { + div { + class: Styles::controls, + MouseArea { onevent: event_handler } + KeyboardArea { onevent: event_handler } + } + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub enum ClientEvent { + MouseMove { dx: f64, dy: f64 }, + MouseScroll { dx: f64, dy: f64 }, + Click { button: MouseButton }, + KeyPressEvent { key: String }, + TextInputStartEvent, + TextInputEvent { text: String }, + TextInputDoneEvent { text: String }, +} + +#[derive(Serialize, Deserialize, Debug)] +enum ServerEvent { + Ping, +} + +#[expect(clippy::unused_async)] +#[get("/api/mouse_move_ws", mouse_service: State)] +async fn mouse_move( + options: WebSocketOptions +) -> Result> { + Ok(options.on_upgrade(move |mut socket| async move { + _ = socket.send(ServerEvent::Ping).await; + + while let Ok(event) = socket.recv().await { + match event { + ClientEvent::MouseMove { dx, dy } => { + mouse_service.move_mouse(dx, dy).await; + }, + ClientEvent::MouseScroll { dx, dy } => { + mouse_service.mouse_scroll(dx, dy).await; + }, + ClientEvent::Click { button } => { + mouse_service.click(button).await; + }, + ClientEvent::KeyPressEvent { key } => { + mouse_service.key_press_event(key).await; + }, + ClientEvent::TextInputEvent { text } => { + mouse_service.text_input(text).await; + }, + ClientEvent::TextInputStartEvent => { + mouse_service.text_input_start().await; + }, + ClientEvent::TextInputDoneEvent { text } => { + mouse_service.text_input_end(text).await; + }, + } + } + })) +} diff --git a/crates/cursor-move-webapp/src/components/keyboard_area.rs b/crates/cursor-move-webapp/src/components/keyboard_area.rs new file mode 100644 index 0000000..885c39d --- /dev/null +++ b/crates/cursor-move-webapp/src/components/keyboard_area.rs @@ -0,0 +1,57 @@ +use dioxus::prelude::*; + +use crate::components::controls::ClientEvent; + +#[component] +pub fn KeyboardArea(onevent: EventHandler) -> Element { + #[css_module("/assets/styling/keyboard_area.module.css")] + struct Styles; + + let mut input_state = use_signal(String::new); + let input_handler = use_callback(move |evt: Event| { + let v = evt.value(); + input_state.set(v.clone()); + + onevent.call(ClientEvent::TextInputEvent { text: v }) + }); + let key_press_handler = use_callback(move |evt: Event| { + if input_state.read().is_empty() { + match evt.key() { + Key::Character(_) => {}, + _ => { + onevent.call(ClientEvent::KeyPressEvent { + key: evt.key().to_string(), + }); + }, + } + } else if evt.key() == Key::Enter { + onevent.call(ClientEvent::TextInputDoneEvent { + text: input_state.replace(String::new()), + }); + } + }); + let input_focus_handler = use_callback(move |_: Event| { + input_state.set(String::new()); + onevent.call(ClientEvent::TextInputStartEvent); + }); + + let input_blur_handler = use_callback(move |_: Event| { + onevent.call(ClientEvent::TextInputDoneEvent { + text: input_state.replace(String::new()), + }); + }); + + rsx! { + div { + class: Styles::keyboard_area, + + input { + oninput: input_handler, + value: input_state, + onkeydown: key_press_handler, + onfocus: input_focus_handler, + onblur: input_blur_handler + } + } + } +} diff --git a/crates/cursor-move-webapp/src/components/mod.rs b/crates/cursor-move-webapp/src/components/mod.rs index a3263ad..f319458 100644 --- a/crates/cursor-move-webapp/src/components/mod.rs +++ b/crates/cursor-move-webapp/src/components/mod.rs @@ -1,2 +1,6 @@ +mod controls; +mod keyboard_area; mod mouse_area; +pub use controls::Controls; +pub use keyboard_area::KeyboardArea; pub use mouse_area::MouseArea; diff --git a/crates/cursor-move-webapp/src/components/mouse_area.rs b/crates/cursor-move-webapp/src/components/mouse_area.rs index 0caf6d1..e684f41 100644 --- a/crates/cursor-move-webapp/src/components/mouse_area.rs +++ b/crates/cursor-move-webapp/src/components/mouse_area.rs @@ -1,5 +1,10 @@ +use std::{ + collections::{HashMap, VecDeque}, + ops::Sub, + time::Duration, +}; + use dioxus::{ - fullstack::{CborEncoding, WebSocketOptions, Websocket, extract::State, use_websocket}, html::{ geometry::{ElementSpace, euclid::Point2D}, input_data::MouseButton, @@ -7,184 +12,160 @@ use dioxus::{ logger::tracing, prelude::*, }; -use serde::{Deserialize, Serialize}; +use dioxus_html::geometry::euclid::Vector2D; + +use crate::{components::controls::ClientEvent, utils::mouse_filter_buffer::MouseFilterBuffer}; + +const FLING_START_THRESHOLD_VELOCITY: f64 = 500.0; +const FLING_STOP_THRESHOLD_VELOCITY: f64 = 100.0; +const FLING_DAMPENING: f64 = 0.98; + +pub struct PointerRegistryData { + initial_position: Point2D, + + last_positions: MouseFilterBuffer, +} + +pub struct FlingerData { + velocity: Vector2D, +} + +#[derive(Default)] +pub struct PointerRegistry { + pointers: HashMap, +} + +#[derive(Default)] +pub struct FlingerRegistry { + flinger: Option, +} #[component] -pub fn MouseArea() -> Element { +pub fn MouseArea(onevent: EventHandler) -> Element { #[css_module("/assets/styling/mouse_area.module.css")] struct Styles; - let mut last_cursor_position = use_signal::>>(|| None); - - let mut socket = use_websocket(move || mouse_move(WebSocketOptions::new())); - - use_future(move || async move { - loop { - // Wait for the socket to connect - _ = socket.connect().await; - - // Loop poll with recv. Throws an error when the connection closes, making it possible - // to run code before the socket re-connects when the name input changes - while let Ok(message) = socket.recv().await { - tracing::info!("Received message: {:?}", message); - } - } - }); + let mut registry = use_signal::(PointerRegistry::default); + let mut flingers = use_signal::(FlingerRegistry::default); let pointer_move_handler = use_callback(move |evt: Event| { - if evt.held_buttons().contains(MouseButton::Primary) { + let mut registry = registry.write(); + if let Some(data) = registry.pointers.get_mut(&evt.pointer_id()) { evt.prevent_default(); let point = evt.element_coordinates(); - let last_position = last_cursor_position.write().replace(point); + let last_position = data.last_positions.back(); + let delta = point - last_position.position; - if let Some(last_position) = last_position { - let delta = point - last_position; + data.last_positions + .push(point, wasmtimer::std::SystemTime::now()); - spawn(async move { - _ = socket - .send(ClientEvent::MouseMove { - dx: delta.x, - dy: delta.y, - }) - .await; + if registry.pointers.len() == 1 { + onevent.call(ClientEvent::MouseMove { + dx: delta.x, + dy: delta.y, + }); + } else if registry.pointers.len() == 2 { + onevent.call(ClientEvent::MouseScroll { + dx: -delta.x, + dy: -delta.y, }); } } }); let pointer_down_handler = use_callback(move |evt: Event| { + //If any pointer is down, we cancel the flingers + flingers.write().flinger.take(); + let point = evt.element_coordinates(); - *last_cursor_position.write() = Some(point); + + registry.write().pointers.insert( + evt.pointer_id(), + PointerRegistryData { + last_positions: MouseFilterBuffer::new( + 10, + point, + wasmtimer::std::SystemTime::now(), + ), + initial_position: point, + }, + ); }); + let pointer_up_handler = use_callback(move |evt: Event| { + let point = evt.element_coordinates(); + let mut registry = registry.write(); + let data = registry.pointers.remove(&evt.pointer_id()); + if let Some(data) = data { + let distance_moved = data.initial_position - point; + let release_velocity = data.last_positions.average_velocity_since( + wasmtimer::std::SystemTime::now().sub(Duration::from_millis(100)), + ); + tracing::info!("Release Velocity: {:?}", release_velocity.length()); - let pointer_click_handler = use_callback(move |evt: Event| { - spawn(async move { - _ = socket.send(ClientEvent::Click).await; - }); - }); - - let key_down_handler = use_callback(move |evt: Event| { - spawn(async move { - _ = socket - .send(ClientEvent::KeyEvent { - key: evt.key().to_string(), - is_pressed: true, - }) - .await; - }); - }); - - // let key_up_handler = use_callback(move |evt: Event| { - // spawn(async move { - // _ = socket - // .send(ClientEvent::KeyEvent { - // key: evt.key().to_string(), - // is_pressed: false, - // }) - // .await; - // }); - // }); - - let mut input_state = use_signal(String::new); - let input_handler = use_callback(move |evt: Event| { - let v = evt.value(); - input_state.set(v.clone()); - - spawn(async move { - _ = socket.send(ClientEvent::TextInputEvent { text: v }).await; - }); - }); - let key_press_handler = use_callback(move |evt: Event| { - if evt.key() == Key::Enter { - spawn(async move { - _ = socket - .send(ClientEvent::TextInputDoneEvent { - text: input_state.replace(String::new()), - }) - .await; - }); + if distance_moved.length() <= 1.0 { + match registry.pointers.len() { + 0 => { + onevent.call(ClientEvent::Click { + button: MouseButton::Primary, + }); + }, + 1 => { + onevent.call(ClientEvent::Click { + button: MouseButton::Secondary, + }); + }, + _ => {}, + } + } else if release_velocity.length() > FLING_START_THRESHOLD_VELOCITY { + //We only fling if there are no other pointers + if registry.pointers.is_empty() { + flingers.write().flinger = Some(FlingerData { + velocity: release_velocity, + }); + } + } } }); - let input_focus_handler = use_callback(move |evt: Event| { - input_state.set(String::new()); - spawn(async move { - _ = socket.send(ClientEvent::TextInputStartEvent).await; - }); - }); - let input_blur_handler = use_callback(move |evt: Event| { - spawn(async move { - _ = socket - .send(ClientEvent::TextInputDoneEvent { - text: input_state.replace(String::new()), - }) - .await; - }); + use_future(move || async move { + let mut last_frame_time = wasmtimer::std::SystemTime::now(); + + loop { + wasmtimer::tokio::sleep(Duration::from_millis(16)).await; + let new_frame_time = wasmtimer::std::SystemTime::now(); + let delta_seconds = new_frame_time + .duration_since(last_frame_time) + .unwrap() + .as_secs_f64(); + last_frame_time = new_frame_time; + + let mut flinger = flingers.write(); + let new_flinger = flinger.flinger.as_ref().and_then(|flinger| { + if flinger.velocity.length() < FLING_STOP_THRESHOLD_VELOCITY { + None + } else { + onevent.call(ClientEvent::MouseMove { + dx: flinger.velocity.x * delta_seconds, + dy: flinger.velocity.y * delta_seconds, + }); + + //tracing::info!("Fling: {:?}", flinger.velocity); + Some(FlingerData { + velocity: flinger.velocity * FLING_DAMPENING, + }) + } + }); + flinger.flinger = new_flinger; + } }); rsx! { div { - input { - oninput: input_handler, - value: input_state, - onkeypress: key_press_handler, - onfocus: input_focus_handler, - onblur: input_blur_handler } - div { - class: Styles::mouse_area, + class: Styles::mouse_area, - onpointermove: pointer_move_handler, - onpointerdown: pointer_down_handler, - onclick: pointer_click_handler - } + onpointermove: pointer_move_handler, + onpointerdown: pointer_down_handler, + onpointerup: pointer_up_handler, } } } - -#[derive(Serialize, Deserialize, Debug)] -enum ClientEvent { - MouseMove { dx: f64, dy: f64 }, - Click, - KeyEvent { key: String, is_pressed: bool }, - TextInputStartEvent, - TextInputEvent { text: String }, - TextInputDoneEvent { text: String }, -} - -#[derive(Serialize, Deserialize, Debug)] -enum ServerEvent { - Ping, -} - -#[expect(clippy::unused_async)] -#[get("/api/mouse_move_ws", mouse_service: State)] -async fn mouse_move( - options: WebSocketOptions -) -> Result> { - Ok(options.on_upgrade(move |mut socket| async move { - _ = socket.send(ServerEvent::Ping).await; - - while let Ok(event) = socket.recv().await { - match event { - ClientEvent::MouseMove { dx, dy } => { - mouse_service.move_mouse(dx, dy).await; - }, - ClientEvent::Click => { - mouse_service.click().await; - }, - ClientEvent::KeyEvent { key, is_pressed } => { - mouse_service.key_event(key, is_pressed).await; - }, - ClientEvent::TextInputEvent { text } => { - mouse_service.text_input(text).await; - }, - ClientEvent::TextInputStartEvent => { - mouse_service.text_input_start().await; - }, - ClientEvent::TextInputDoneEvent { text } => { - mouse_service.text_input_end(text).await; - }, - } - } - })) -} diff --git a/crates/cursor-move-webapp/src/main.rs b/crates/cursor-move-webapp/src/main.rs index d171f40..749da33 100644 --- a/crates/cursor-move-webapp/src/main.rs +++ b/crates/cursor-move-webapp/src/main.rs @@ -4,6 +4,7 @@ use dioxus::prelude::*; use views::{Home, Navbar}; mod components; +mod utils; mod views; #[cfg(feature = "server")] @@ -45,6 +46,7 @@ fn App() -> Element { rsx! { document::Link { rel: "icon", href: FAVICON } document::Link { rel: "stylesheet", href: MAIN_CSS } + document::Meta { name: "viewport", content: "width=device-width, initial-scale=1.0" } Router:: {} } diff --git a/crates/cursor-move-webapp/src/server/input_proxy_service.rs b/crates/cursor-move-webapp/src/server/input_proxy_service.rs index fb4cef8..9a77df1 100644 --- a/crates/cursor-move-webapp/src/server/input_proxy_service.rs +++ b/crates/cursor-move-webapp/src/server/input_proxy_service.rs @@ -4,13 +4,14 @@ use dioxus::{ fullstack::{FullstackContext, extract::FromRef}, logger::tracing, }; +use dioxus_html::input_data::MouseButton; use memfile::MemFile; use rustix::time::{ClockId, clock_gettime}; use tokio::sync::Mutex; use wayland_client::{ Connection, Dispatch, EventQueue, Proxy, QueueHandle, protocol::{ - wl_pointer::ButtonState, + wl_pointer::{Axis, ButtonState}, wl_registry::{Event, WlRegistry}, wl_seat::{self, WlSeat}, }, @@ -29,12 +30,12 @@ use wayland_protocols_wlr::virtual_pointer::v1::client::{ zwlr_virtual_pointer_v1::ZwlrVirtualPointerV1, }; -use crate::server::keymap; +use crate::server::keymap::{self, web_key_to_linux_keycode}; // https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h const BUTTON_LEFT: u32 = 0x110; -const BTN_RIGHT: u32 = 0x111; -const BTN_MIDDLE: u32 = 0x112; +const BUTTON_RIGHT: u32 = 0x111; +const BUTTON_MIDDLE: u32 = 0x112; // https://wayland.app/protocols/wayland#wl_keyboard:enum:keymap_format const NO_KEYMAP: u32 = 0; @@ -78,37 +79,72 @@ impl InputProxyService { } } - pub async fn click(&self) { + pub async fn mouse_scroll( + &self, + dx: f64, + dy: f64, + ) { let guard = self.input_proxy_service_state.lock().await; if let Some(pointer) = &guard.state.virtual_pointer() { - tracing::info!("Do click"); let time = get_wayland_timestamp(); - - pointer.button(time, BUTTON_LEFT, ButtonState::Pressed); - pointer.frame(); - pointer.button(time, BUTTON_LEFT, ButtonState::Released); + pointer.axis(time, Axis::HorizontalScroll, dx); + pointer.axis(time, Axis::VerticalScroll, dy); pointer.frame(); guard.event_queue.flush().unwrap(); } } - pub async fn key_event( + pub async fn click( + &self, + button: MouseButton, + ) { + let guard = self.input_proxy_service_state.lock().await; + if let Some(pointer) = &guard.state.virtual_pointer() { + tracing::info!("Do click"); + let time = get_wayland_timestamp(); + + let button = match button { + MouseButton::Primary => BUTTON_LEFT, + MouseButton::Secondary => BUTTON_RIGHT, + MouseButton::Auxiliary => BUTTON_MIDDLE, + MouseButton::Fourth | MouseButton::Fifth | MouseButton::Unknown => { + return; + }, + }; + + pointer.button(time, button, ButtonState::Pressed); + pointer.frame(); + pointer.button(time, button, ButtonState::Released); + pointer.frame(); + guard.event_queue.flush().unwrap(); + } + } + + pub async fn key_press_event( &self, key: String, - is_pressed: bool, ) { - todo!(); + let guard = self.input_proxy_service_state.lock().await; + + if let Some(keyboard) = guard.state.virtual_keyboard() { + let time = get_wayland_timestamp(); + let key = web_key_to_linux_keycode(key.as_str()).unwrap(); + keyboard.key(time, key, 1); + keyboard.key(time, key, 0); + + guard.event_queue.flush().unwrap(); + } } pub async fn text_input_start(&self) { let mut guard = self.input_proxy_service_state.lock().await; - if let Some(keyboard) = guard.state.input_method_mut() { - keyboard.input_method_state += 1; + if let Some(ime) = guard.state.input_method_mut() { + ime.input_method_state += 1; tracing::info!("Text Input Start"); - keyboard.input_method.delete_surrounding_text(4, 4); - keyboard.input_method.commit(keyboard.input_method_state); + ime.input_method.delete_surrounding_text(4, 4); + ime.input_method.commit(ime.input_method_state); guard.event_queue.flush().unwrap(); } @@ -119,12 +155,12 @@ impl InputProxyService { ) { let mut guard = self.input_proxy_service_state.lock().await; - if let Some(keyboard) = guard.state.input_method_mut() { - keyboard.input_method_state += 1; + if let Some(ime) = guard.state.input_method_mut() { + ime.input_method_state += 1; tracing::info!("Text Input {key}"); - keyboard.input_method.set_preedit_string(key, 0, 0); - keyboard.input_method.commit(keyboard.input_method_state); + ime.input_method.set_preedit_string(key, 0, 0); + ime.input_method.commit(ime.input_method_state); guard.event_queue.flush().unwrap(); } } @@ -134,12 +170,12 @@ impl InputProxyService { ) { let mut guard = self.input_proxy_service_state.lock().await; - if let Some(keyboard) = guard.state.input_method_mut() { - keyboard.input_method_state += 1; + if let Some(ime) = guard.state.input_method_mut() { + ime.input_method_state += 1; tracing::info!("Text Input End"); - keyboard.input_method.commit_string(text); - keyboard.input_method.commit(keyboard.input_method_state); + ime.input_method.commit_string(text); + ime.input_method.commit(ime.input_method_state); guard.event_queue.flush().unwrap(); } } diff --git a/crates/cursor-move-webapp/src/server/keymap.rs b/crates/cursor-move-webapp/src/server/keymap.rs index de52a2f..93c6432 100644 --- a/crates/cursor-move-webapp/src/server/keymap.rs +++ b/crates/cursor-move-webapp/src/server/keymap.rs @@ -1,10 +1,12 @@ +use dioxus::logger::tracing; + fn is_key_string(s: &str) -> bool { s.chars().all(|c| !c.is_control()) && s.chars().skip(1).all(|c| !c.is_ascii()) } pub fn web_key_to_linux_keycode(s: &str) -> Option { + tracing::info!("Converting {s}"); match s { - //s if is_key_string(s) => Ok(Character(s.to_string())), "Unidentified" => todo!(), "Alt" => Some(KEY_LEFTALT), "AltGraph" => Some(KEY_RIGHTALT), @@ -20,17 +22,17 @@ pub fn web_key_to_linux_keycode(s: &str) -> Option { "SymbolLock" => todo!(), "Hyper" => todo!(), "Super" => todo!(), - "Enter" => todo!(), - "Tab" => todo!(), - "ArrowDown" => todo!(), - "ArrowLeft" => todo!(), - "ArrowRight" => todo!(), - "ArrowUp" => todo!(), - "End" => todo!(), - "Home" => todo!(), - "PageDown" => todo!(), - "PageUp" => todo!(), - "Backspace" => todo!(), + "Enter" => Some(KEY_ENTER), + "Tab" => Some(KEY_TAB), + "ArrowDown" => Some(KEY_DOWN), + "ArrowLeft" => Some(KEY_LEFT), + "ArrowRight" => Some(KEY_RIGHT), + "ArrowUp" => Some(KEY_UP), + "End" => Some(KEY_END), + "Home" => Some(KEY_HOME), + "PageDown" => Some(KEY_PAGEDOWN), + "PageUp" => Some(KEY_PAGEUP), + "Backspace" => Some(KEY_BACKSPACE), "Clear" => todo!(), "Copy" => todo!(), "CrSel" => todo!(), @@ -82,7 +84,7 @@ pub fn web_key_to_linux_keycode(s: &str) -> Option { "NextCandidate" => todo!(), "NonConvert" => todo!(), "PreviousCandidate" => todo!(), - "Process" => todo!(), + "Process" => None, "SingleCandidate" => todo!(), "HangulMode" => todo!(), "HanjaMode" => todo!(), @@ -277,41 +279,30 @@ pub fn web_key_to_linux_keycode(s: &str) -> Option { "VideoModeNext" => todo!(), "Wink" => todo!(), "ZoomToggle" => todo!(), - "F1" => todo!(), - "F2" => todo!(), - "F3" => todo!(), - "F4" => todo!(), - "F5" => todo!(), - "F6" => todo!(), - "F7" => todo!(), - "F8" => todo!(), - "F9" => todo!(), - "F10" => todo!(), - "F11" => todo!(), - "F12" => todo!(), - "F13" => todo!(), - "F14" => todo!(), - "F15" => todo!(), - "F16" => todo!(), - "F17" => todo!(), - "F18" => todo!(), - "F19" => todo!(), - "F20" => todo!(), - "F21" => todo!(), - "F22" => todo!(), - "F23" => todo!(), - "F24" => todo!(), - "F25" => todo!(), - "F26" => todo!(), - "F27" => todo!(), - "F28" => todo!(), - "F29" => todo!(), - "F30" => todo!(), - "F31" => todo!(), - "F32" => todo!(), - "F33" => todo!(), - "F34" => todo!(), - "F35" => todo!(), + "F1" => Some(KEY_F1), + "F2" => Some(KEY_F2), + "F3" => Some(KEY_F3), + "F4" => Some(KEY_F4), + "F5" => Some(KEY_F5), + "F6" => Some(KEY_F6), + "F7" => Some(KEY_F7), + "F8" => Some(KEY_F8), + "F9" => Some(KEY_F9), + "F10" => Some(KEY_F10), + "F11" => Some(KEY_F11), + "F12" => Some(KEY_F12), + "F13" => Some(KEY_F13), + "F14" => Some(KEY_F14), + "F15" => Some(KEY_F15), + "F16" => Some(KEY_F16), + "F17" => Some(KEY_F17), + "F18" => Some(KEY_F18), + "F19" => Some(KEY_F19), + "F20" => Some(KEY_F20), + "F21" => Some(KEY_F21), + "F22" => Some(KEY_F22), + "F23" => Some(KEY_F23), + "F24" => Some(KEY_F24), _ => todo!(), } } @@ -567,1466 +558,3 @@ const KEY_RFKILL : u32 = 247 /* Key that controls all radios */; const KEY_MICMUTE : u32 = 248 /* Mute / unmute the microphone */; pub const KEYMAP: &str = "xkb_keymap {}"; - -pub const KEYMAP_: &str = "xkb_keymap {\ -xkb_keycodes \"(unnamed)\" {\ - minimum = 8;\ - maximum = 255;\ - = 9;\ - = 10;\ - = 11;\ - = 12;\ - = 13;\ - = 14;\ - = 15;\ - = 16;\ - = 17;\ - = 18;\ - = 19;\ - = 20;\ - = 21;\ - = 22;\ - = 23;\ - = 24;\ - = 25;\ - = 26;\ - = 27;\ - = 28;\ - = 29;\ - = 30;\ - = 31;\ - = 32;\ - = 33;\ - = 34;\ - = 35;\ - = 36;\ - = 37;\ - = 38;\ - = 39;\ - = 40;\ - = 41;\ - = 42;\ - = 43;\ - = 44;\ - = 45;\ - = 46;\ - = 47;\ - = 48;\ - = 49;\ - = 50;\ - = 51;\ - = 52;\ - = 53;\ - = 54;\ - = 55;\ - = 56;\ - = 57;\ - = 58;\ - = 59;\ - = 60;\ - = 61;\ - = 62;\ - = 63;\ - = 64;\ - = 65;\ - = 66;\ - = 67;\ - = 68;\ - = 69;\ - = 70;\ - = 71;\ - = 72;\ - = 73;\ - = 74;\ - = 75;\ - = 76;\ - = 77;\ - = 78;\ - = 79;\ - = 80;\ - = 81;\ - = 82;\ - = 83;\ - = 84;\ - = 85;\ - = 86;\ - = 87;\ - = 88;\ - = 89;\ - = 90;\ - = 91;\ - = 92;\ - = 94;\ - = 95;\ - = 96;\ - = 97;\ - = 98;\ - = 99;\ - = 100;\ - = 101;\ - = 102;\ - = 103;\ - = 104;\ - = 105;\ - = 106;\ - = 107;\ - = 108;\ - = 109;\ - = 110;\ - = 111;\ - = 112;\ - = 113;\ - = 114;\ - = 115;\ - = 116;\ - = 117;\ - = 118;\ - = 119;\ - = 120;\ - = 121;\ - = 122;\ - = 123;\ - = 124;\ - = 125;\ - = 126;\ - = 127;\ - = 128;\ - = 129;\ - = 130;\ - = 131;\ - = 132;\ - = 133;\ - = 134;\ - = 135;\ - = 136;\ - = 137;\ - = 138;\ - = 139;\ - = 140;\ - = 141;\ - = 142;\ - = 143;\ - = 144;\ - = 145;\ - = 146;\ - = 147;\ - = 148;\ - = 149;\ - = 150;\ - = 151;\ - = 152;\ - = 153;\ - = 154;\ - = 155;\ - = 156;\ - = 157;\ - = 158;\ - = 159;\ - = 160;\ - = 161;\ - = 162;\ - = 163;\ - = 164;\ - = 165;\ - = 166;\ - = 167;\ - = 168;\ - = 169;\ - = 170;\ - = 171;\ - = 172;\ - = 173;\ - = 174;\ - = 175;\ - = 176;\ - = 177;\ - = 178;\ - = 179;\ - = 180;\ - = 181;\ - = 182;\ - = 183;\ - = 184;\ - = 185;\ - = 186;\ - = 187;\ - = 188;\ - = 189;\ - = 190;\ - = 191;\ - = 192;\ - = 193;\ - = 194;\ - = 195;\ - = 196;\ - = 197;\ - = 198;\ - = 199;\ - = 200;\ - = 201;\ - = 202;\ - = 203;\ - = 204;\ - = 205;\ - = 206;\ - = 207;\ - = 208;\ - = 209;\ - = 210;\ - = 211;\ - = 212;\ - = 213;\ - = 214;\ - = 215;\ - = 216;\ - = 217;\ - = 218;\ - = 219;\ - = 220;\ - = 221;\ - = 222;\ - = 223;\ - = 224;\ - = 225;\ - = 226;\ - = 227;\ - = 228;\ - = 229;\ - = 230;\ - = 231;\ - = 232;\ - = 233;\ - = 234;\ - = 235;\ - = 236;\ - = 237;\ - = 238;\ - = 239;\ - = 240;\ - = 241;\ - = 242;\ - = 243;\ - = 244;\ - = 245;\ - = 246;\ - = 247;\ - = 248;\ - = 249;\ - = 250;\ - = 251;\ - = 252;\ - = 253;\ - = 254;\ - = 255;\ - indicator 1 = \"Caps Lock\";\ - indicator 2 = \"Num Lock\";\ - indicator 3 = \"Scroll Lock\";\ - indicator 4 = \"Compose\";\ - indicator 5 = \"Kana\";\ - indicator 6 = \"Sleep\";\ - indicator 7 = \"Suspend\";\ - indicator 8 = \"Mute\";\ - indicator 9 = \"Misc\";\ - indicator 10 = \"Mail\";\ - indicator 11 = \"Charging\";\ - indicator 12 = \"Shift Lock\";\ - indicator 13 = \"Group 2\";\ - indicator 14 = \"Mouse Keys\";\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ - alias = ;\ -};\ -\ -xkb_types \"(unnamed)\" {\ - virtual_modifiers NumLock,Alt,LevelThree,LAlt,RAlt,RControl,LControl,ScrollLock,LevelFive,AltGr,Meta,Super,Hyper;\ -\ - type \"ONE_LEVEL\" {\ - modifiers= none;\ - level_name[Level1]= \"Any\";\ - };\ - type \"TWO_LEVEL\" {\ - modifiers= Shift;\ - map[Shift]= Level2;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift\";\ - };\ - type \"ALPHABETIC\" {\ - modifiers= Shift+Lock;\ - map[Shift]= Level2;\ - map[Lock]= Level2;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Caps\";\ - };\ - type \"SHIFT+ALT\" {\ - modifiers= Shift+Alt;\ - map[Shift+Alt]= Level2;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift+Alt\";\ - };\ - type \"PC_SUPER_LEVEL2\" {\ - modifiers= Mod4;\ - map[Mod4]= Level2;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Super\";\ - };\ - type \"PC_CONTROL_LEVEL2\" {\ - modifiers= Control;\ - map[Control]= Level2;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Control\";\ - };\ - type \"PC_LCONTROL_LEVEL2\" {\ - modifiers= LControl;\ - map[LControl]= Level2;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"LControl\";\ - };\ - type \"PC_RCONTROL_LEVEL2\" {\ - modifiers= RControl;\ - map[RControl]= Level2;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"RControl\";\ - };\ - type \"PC_ALT_LEVEL2\" {\ - modifiers= Alt;\ - map[Alt]= Level2;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Alt\";\ - };\ - type \"PC_LALT_LEVEL2\" {\ - modifiers= LAlt;\ - map[LAlt]= Level2;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"LAlt\";\ - };\ - type \"PC_RALT_LEVEL2\" {\ - modifiers= RAlt;\ - map[RAlt]= Level2;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"RAlt\";\ - };\ - type \"CTRL+ALT\" {\ - modifiers= Shift+Control+Alt+LevelThree;\ - map[Shift]= Level2;\ - preserve[Shift]= Shift;\ - map[LevelThree]= Level3;\ - map[Shift+LevelThree]= Level4;\ - preserve[Shift+LevelThree]= Shift;\ - map[Control+Alt]= Level5;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift\";\ - level_name[Level3]= \"Alt Base\";\ - level_name[Level4]= \"Shift Alt\";\ - level_name[Level5]= \"Ctrl+Alt\";\ - };\ - type \"LOCAL_EIGHT_LEVEL\" {\ - modifiers= Shift+Lock+Control+LevelThree;\ - map[Shift]= Level2;\ - map[Lock]= Level2;\ - map[LevelThree]= Level3;\ - map[Shift+Lock+LevelThree]= Level3;\ - map[Shift+LevelThree]= Level4;\ - map[Lock+LevelThree]= Level4;\ - map[Control]= Level5;\ - map[Shift+Lock+Control]= Level5;\ - map[Shift+Control]= Level6;\ - map[Lock+Control]= Level6;\ - map[Control+LevelThree]= Level7;\ - map[Shift+Lock+Control+LevelThree]= Level7;\ - map[Shift+Control+LevelThree]= Level8;\ - map[Lock+Control+LevelThree]= Level8;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift\";\ - level_name[Level3]= \"Level3\";\ - level_name[Level4]= \"Shift Level3\";\ - level_name[Level5]= \"Ctrl\";\ - level_name[Level6]= \"Shift Ctrl\";\ - level_name[Level7]= \"Level3 Ctrl\";\ - level_name[Level8]= \"Shift Level3 Ctrl\";\ - };\ - type \"THREE_LEVEL\" {\ - modifiers= Shift+LevelThree;\ - map[Shift]= Level2;\ - map[LevelThree]= Level3;\ - map[Shift+LevelThree]= Level3;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift\";\ - level_name[Level3]= \"Level3\";\ - };\ - type \"EIGHT_LEVEL\" {\ - modifiers= Shift+LevelThree+LevelFive;\ - map[Shift]= Level2;\ - map[LevelThree]= Level3;\ - map[Shift+LevelThree]= Level4;\ - map[LevelFive]= Level5;\ - map[Shift+LevelFive]= Level6;\ - map[LevelThree+LevelFive]= Level7;\ - map[Shift+LevelThree+LevelFive]= Level8;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift\";\ - level_name[Level3]= \"Alt Base\";\ - level_name[Level4]= \"Shift Alt\";\ - level_name[Level5]= \"X\";\ - level_name[Level6]= \"X Shift\";\ - level_name[Level7]= \"X Alt Base\";\ - level_name[Level8]= \"X Shift Alt\";\ - };\ - type \"EIGHT_LEVEL_ALPHABETIC\" {\ - modifiers= Shift+Lock+LevelThree+LevelFive;\ - map[Shift]= Level2;\ - map[Lock]= Level2;\ - map[LevelThree]= Level3;\ - map[Shift+LevelThree]= Level4;\ - map[Lock+LevelThree]= Level4;\ - map[Shift+Lock+LevelThree]= Level3;\ - map[LevelFive]= Level5;\ - map[Shift+LevelFive]= Level6;\ - map[Lock+LevelFive]= Level6;\ - map[LevelThree+LevelFive]= Level7;\ - map[Shift+LevelThree+LevelFive]= Level8;\ - map[Lock+LevelThree+LevelFive]= Level8;\ - map[Shift+Lock+LevelThree+LevelFive]= Level7;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift\";\ - level_name[Level3]= \"Alt Base\";\ - level_name[Level4]= \"Shift Alt\";\ - level_name[Level5]= \"X\";\ - level_name[Level6]= \"X Shift\";\ - level_name[Level7]= \"X Alt Base\";\ - level_name[Level8]= \"X Shift Alt\";\ - };\ - type \"EIGHT_LEVEL_LEVEL_FIVE_LOCK\" {\ - modifiers= Shift+Lock+NumLock+LevelThree+LevelFive;\ - map[Shift]= Level2;\ - map[LevelThree]= Level3;\ - map[Shift+LevelThree]= Level4;\ - map[LevelFive]= Level5;\ - map[Shift+LevelFive]= Level6;\ - preserve[Shift+LevelFive]= Shift;\ - map[LevelThree+LevelFive]= Level7;\ - map[Shift+LevelThree+LevelFive]= Level8;\ - map[NumLock]= Level5;\ - map[Shift+NumLock]= Level6;\ - preserve[Shift+NumLock]= Shift;\ - map[NumLock+LevelThree]= Level7;\ - map[Shift+NumLock+LevelThree]= Level8;\ - map[Shift+NumLock+LevelFive]= Level2;\ - map[NumLock+LevelThree+LevelFive]= Level3;\ - map[Shift+NumLock+LevelThree+LevelFive]= Level4;\ - map[Shift+Lock]= Level2;\ - map[Lock+LevelThree]= Level3;\ - map[Shift+Lock+LevelThree]= Level4;\ - map[Lock+LevelFive]= Level5;\ - map[Shift+Lock+LevelFive]= Level6;\ - preserve[Shift+Lock+LevelFive]= Shift;\ - map[Lock+LevelThree+LevelFive]= Level7;\ - map[Shift+Lock+LevelThree+LevelFive]= Level8;\ - map[Lock+NumLock]= Level5;\ - map[Shift+Lock+NumLock]= Level6;\ - preserve[Shift+Lock+NumLock]= Shift;\ - map[Lock+NumLock+LevelThree]= Level7;\ - map[Shift+Lock+NumLock+LevelThree]= Level8;\ - map[Shift+Lock+NumLock+LevelFive]= Level2;\ - map[Lock+NumLock+LevelThree+LevelFive]= Level3;\ - map[Shift+Lock+NumLock+LevelThree+LevelFive]= Level4;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift\";\ - level_name[Level3]= \"Alt Base\";\ - level_name[Level4]= \"Shift Alt\";\ - level_name[Level5]= \"X\";\ - level_name[Level6]= \"X Shift\";\ - level_name[Level7]= \"X Alt Base\";\ - level_name[Level8]= \"X Shift Alt\";\ - };\ - type \"EIGHT_LEVEL_ALPHABETIC_LEVEL_FIVE_LOCK\" {\ - modifiers= Shift+Lock+NumLock+LevelThree+LevelFive;\ - map[Shift]= Level2;\ - map[LevelThree]= Level3;\ - map[Shift+LevelThree]= Level4;\ - map[LevelFive]= Level5;\ - map[Shift+LevelFive]= Level6;\ - preserve[Shift+LevelFive]= Shift;\ - map[LevelThree+LevelFive]= Level7;\ - map[Shift+LevelThree+LevelFive]= Level8;\ - map[NumLock]= Level5;\ - map[Shift+NumLock]= Level6;\ - preserve[Shift+NumLock]= Shift;\ - map[NumLock+LevelThree]= Level7;\ - map[Shift+NumLock+LevelThree]= Level8;\ - map[Shift+NumLock+LevelFive]= Level2;\ - map[NumLock+LevelThree+LevelFive]= Level3;\ - map[Shift+NumLock+LevelThree+LevelFive]= Level4;\ - map[Lock]= Level2;\ - map[Lock+LevelThree]= Level3;\ - map[Shift+Lock+LevelThree]= Level4;\ - map[Lock+LevelFive]= Level5;\ - map[Shift+Lock+LevelFive]= Level6;\ - map[Lock+LevelThree+LevelFive]= Level7;\ - map[Shift+Lock+LevelThree+LevelFive]= Level8;\ - map[Lock+NumLock]= Level5;\ - map[Shift+Lock+NumLock]= Level6;\ - map[Lock+NumLock+LevelThree]= Level7;\ - map[Shift+Lock+NumLock+LevelThree]= Level8;\ - map[Lock+NumLock+LevelFive]= Level2;\ - map[Lock+NumLock+LevelThree+LevelFive]= Level4;\ - map[Shift+Lock+NumLock+LevelThree+LevelFive]= Level3;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift\";\ - level_name[Level3]= \"Alt Base\";\ - level_name[Level4]= \"Shift Alt\";\ - level_name[Level5]= \"X\";\ - level_name[Level6]= \"X Shift\";\ - level_name[Level7]= \"X Alt Base\";\ - level_name[Level8]= \"X Shift Alt\";\ - };\ - type \"EIGHT_LEVEL_SEMIALPHABETIC\" {\ - modifiers= Shift+Lock+LevelThree+LevelFive;\ - map[Shift]= Level2;\ - map[Lock]= Level2;\ - map[LevelThree]= Level3;\ - map[Shift+LevelThree]= Level4;\ - map[Lock+LevelThree]= Level3;\ - preserve[Lock+LevelThree]= Lock;\ - map[Shift+Lock+LevelThree]= Level4;\ - preserve[Shift+Lock+LevelThree]= Lock;\ - map[LevelFive]= Level5;\ - map[Shift+LevelFive]= Level6;\ - map[Lock+LevelFive]= Level6;\ - preserve[Lock+LevelFive]= Lock;\ - map[Shift+Lock+LevelFive]= Level6;\ - preserve[Shift+Lock+LevelFive]= Lock;\ - map[LevelThree+LevelFive]= Level7;\ - map[Shift+LevelThree+LevelFive]= Level8;\ - map[Lock+LevelThree+LevelFive]= Level7;\ - preserve[Lock+LevelThree+LevelFive]= Lock;\ - map[Shift+Lock+LevelThree+LevelFive]= Level8;\ - preserve[Shift+Lock+LevelThree+LevelFive]= Lock;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift\";\ - level_name[Level3]= \"Alt Base\";\ - level_name[Level4]= \"Shift Alt\";\ - level_name[Level5]= \"X\";\ - level_name[Level6]= \"X Shift\";\ - level_name[Level7]= \"X Alt Base\";\ - level_name[Level8]= \"X Shift Alt\";\ - };\ - type \"FOUR_LEVEL\" {\ - modifiers= Shift+LevelThree;\ - map[Shift]= Level2;\ - map[LevelThree]= Level3;\ - map[Shift+LevelThree]= Level4;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift\";\ - level_name[Level3]= \"Alt Base\";\ - level_name[Level4]= \"Shift Alt\";\ - };\ - type \"FOUR_LEVEL_ALPHABETIC\" {\ - modifiers= Shift+Lock+LevelThree;\ - map[Shift]= Level2;\ - map[Lock]= Level2;\ - map[LevelThree]= Level3;\ - map[Shift+LevelThree]= Level4;\ - map[Lock+LevelThree]= Level4;\ - map[Shift+Lock+LevelThree]= Level3;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift\";\ - level_name[Level3]= \"Alt Base\";\ - level_name[Level4]= \"Shift Alt\";\ - };\ - type \"FOUR_LEVEL_SEMIALPHABETIC\" {\ - modifiers= Shift+Lock+LevelThree;\ - map[Shift]= Level2;\ - map[Lock]= Level2;\ - map[LevelThree]= Level3;\ - map[Shift+LevelThree]= Level4;\ - map[Lock+LevelThree]= Level3;\ - preserve[Lock+LevelThree]= Lock;\ - map[Shift+Lock+LevelThree]= Level4;\ - preserve[Shift+Lock+LevelThree]= Lock;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift\";\ - level_name[Level3]= \"Alt Base\";\ - level_name[Level4]= \"Shift Alt\";\ - };\ - type \"FOUR_LEVEL_MIXED_KEYPAD\" {\ - modifiers= Shift+NumLock+LevelThree;\ - map[NumLock]= Level2;\ - map[Shift]= Level2;\ - map[LevelThree]= Level3;\ - map[NumLock+LevelThree]= Level3;\ - map[Shift+LevelThree]= Level4;\ - map[Shift+NumLock+LevelThree]= Level4;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Number\";\ - level_name[Level3]= \"Alt Base\";\ - level_name[Level4]= \"Shift Alt\";\ - };\ - type \"FOUR_LEVEL_X\" {\ - modifiers= Shift+Control+Alt+LevelThree;\ - map[LevelThree]= Level2;\ - map[Shift+LevelThree]= Level3;\ - map[Control+Alt]= Level4;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Alt Base\";\ - level_name[Level3]= \"Shift Alt\";\ - level_name[Level4]= \"Ctrl+Alt\";\ - };\ - type \"SEPARATE_CAPS_AND_SHIFT_ALPHABETIC\" {\ - modifiers= Shift+Lock+LevelThree;\ - map[Shift]= Level2;\ - map[Lock]= Level4;\ - preserve[Lock]= Lock;\ - map[LevelThree]= Level3;\ - map[Shift+LevelThree]= Level4;\ - map[Lock+LevelThree]= Level3;\ - preserve[Lock+LevelThree]= Lock;\ - map[Shift+Lock+LevelThree]= Level3;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift\";\ - level_name[Level3]= \"AltGr Base\";\ - level_name[Level4]= \"Shift AltGr\";\ - };\ - type \"FOUR_LEVEL_PLUS_LOCK\" {\ - modifiers= Shift+Lock+LevelThree;\ - map[Shift]= Level2;\ - map[LevelThree]= Level3;\ - map[Shift+LevelThree]= Level4;\ - map[Lock]= Level5;\ - map[Shift+Lock]= Level2;\ - map[Lock+LevelThree]= Level3;\ - map[Shift+Lock+LevelThree]= Level4;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Shift\";\ - level_name[Level3]= \"Alt Base\";\ - level_name[Level4]= \"Shift Alt\";\ - level_name[Level5]= \"Lock\";\ - };\ - type \"KEYPAD\" {\ - modifiers= Shift+NumLock;\ - map[Shift]= Level2;\ - map[NumLock]= Level2;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Number\";\ - };\ - type \"FOUR_LEVEL_KEYPAD\" {\ - modifiers= Shift+NumLock+LevelThree;\ - map[Shift]= Level2;\ - map[NumLock]= Level2;\ - map[LevelThree]= Level3;\ - map[Shift+LevelThree]= Level4;\ - map[NumLock+LevelThree]= Level4;\ - map[Shift+NumLock+LevelThree]= Level3;\ - level_name[Level1]= \"Base\";\ - level_name[Level2]= \"Number\";\ - level_name[Level3]= \"Alt Base\";\ - level_name[Level4]= \"Alt Number\";\ - };\ -};\ -\ -xkb_compatibility \"(unnamed)\" {\ - virtual_modifiers NumLock,Alt,LevelThree,LAlt,RAlt,RControl,LControl,ScrollLock,LevelFive,AltGr,Meta,Super,Hyper;\ -\ - interpret.useModMapMods= AnyLevel;\ - interpret.repeat= False;\ - interpret ISO_Level2_Latch+Exactly(Shift) {\ - useModMapMods=level1;\ - action= LatchMods(modifiers=Shift,clearLocks,latchToLock);\ - };\ - interpret Shift_Lock+AnyOf(Shift+Lock) {\ - action= LockMods(modifiers=Shift);\ - };\ - interpret Num_Lock+AnyOf(all) {\ - virtualModifier= NumLock;\ - action= LockMods(modifiers=NumLock);\ - };\ - interpret ISO_Level3_Shift+AnyOf(all) {\ - virtualModifier= LevelThree;\ - useModMapMods=level1;\ - action= SetMods(modifiers=LevelThree,clearLocks);\ - };\ - interpret ISO_Level3_Latch+AnyOf(all) {\ - virtualModifier= LevelThree;\ - useModMapMods=level1;\ - action= LatchMods(modifiers=LevelThree,clearLocks,latchToLock);\ - };\ - interpret ISO_Level3_Lock+AnyOf(all) {\ - virtualModifier= LevelThree;\ - useModMapMods=level1;\ - action= LockMods(modifiers=LevelThree);\ - };\ - interpret Alt_L+AnyOf(all) {\ - virtualModifier= Alt;\ - action= SetMods(modifiers=modMapMods,clearLocks);\ - };\ - interpret Alt_R+AnyOf(all) {\ - virtualModifier= Alt;\ - action= SetMods(modifiers=modMapMods,clearLocks);\ - };\ - interpret Meta_L+AnyOf(all) {\ - virtualModifier= Meta;\ - action= SetMods(modifiers=modMapMods,clearLocks);\ - };\ - interpret Meta_R+AnyOf(all) {\ - virtualModifier= Meta;\ - action= SetMods(modifiers=modMapMods,clearLocks);\ - };\ - interpret Super_L+AnyOf(all) {\ - virtualModifier= Super;\ - action= SetMods(modifiers=modMapMods,clearLocks);\ - };\ - interpret Super_R+AnyOf(all) {\ - virtualModifier= Super;\ - action= SetMods(modifiers=modMapMods,clearLocks);\ - };\ - interpret Hyper_L+AnyOf(all) {\ - virtualModifier= Hyper;\ - action= SetMods(modifiers=modMapMods,clearLocks);\ - };\ - interpret Hyper_R+AnyOf(all) {\ - virtualModifier= Hyper;\ - action= SetMods(modifiers=modMapMods,clearLocks);\ - };\ - interpret Scroll_Lock+AnyOf(all) {\ - virtualModifier= ScrollLock;\ - action= LockMods(modifiers=modMapMods);\ - };\ - interpret ISO_Level5_Shift+AnyOf(all) {\ - virtualModifier= LevelFive;\ - useModMapMods=level1;\ - action= SetMods(modifiers=LevelFive,clearLocks);\ - };\ - interpret ISO_Level5_Latch+AnyOf(all) {\ - virtualModifier= LevelFive;\ - useModMapMods=level1;\ - action= LatchMods(modifiers=LevelFive,clearLocks,latchToLock);\ - };\ - interpret ISO_Level5_Lock+AnyOf(all) {\ - virtualModifier= LevelFive;\ - useModMapMods=level1;\ - action= LockMods(modifiers=LevelFive);\ - };\ - interpret Mode_switch+AnyOfOrNone(all) {\ - virtualModifier= AltGr;\ - useModMapMods=level1;\ - action= SetGroup(group=+1);\ - };\ - interpret ISO_Level3_Shift+AnyOfOrNone(all) {\ - action= SetMods(modifiers=LevelThree,clearLocks);\ - };\ - interpret ISO_Level3_Latch+AnyOfOrNone(all) {\ - action= LatchMods(modifiers=LevelThree,clearLocks,latchToLock);\ - };\ - interpret ISO_Level3_Lock+AnyOfOrNone(all) {\ - action= LockMods(modifiers=LevelThree);\ - };\ - interpret ISO_Group_Latch+AnyOfOrNone(all) {\ - virtualModifier= AltGr;\ - useModMapMods=level1;\ - action= LatchGroup(group=2);\ - };\ - interpret ISO_Next_Group+AnyOfOrNone(all) {\ - virtualModifier= AltGr;\ - useModMapMods=level1;\ - action= LockGroup(group=+1);\ - };\ - interpret ISO_Prev_Group+AnyOfOrNone(all) {\ - virtualModifier= AltGr;\ - useModMapMods=level1;\ - action= LockGroup(group=-1);\ - };\ - interpret ISO_First_Group+AnyOfOrNone(all) {\ - action= LockGroup(group=1);\ - };\ - interpret ISO_Last_Group+AnyOfOrNone(all) {\ - action= LockGroup(group=2);\ - };\ - interpret KP_1+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=-1,y=+1);\ - };\ - interpret KP_End+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=-1,y=+1);\ - };\ - interpret KP_2+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=+0,y=+1);\ - };\ - interpret KP_Down+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=+0,y=+1);\ - };\ - interpret KP_3+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=+1,y=+1);\ - };\ - interpret KP_Next+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=+1,y=+1);\ - };\ - interpret KP_4+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=-1,y=+0);\ - };\ - interpret KP_Left+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=-1,y=+0);\ - };\ - interpret KP_6+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=+1,y=+0);\ - };\ - interpret KP_Right+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=+1,y=+0);\ - };\ - interpret KP_7+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=-1,y=-1);\ - };\ - interpret KP_Home+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=-1,y=-1);\ - };\ - interpret KP_8+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=+0,y=-1);\ - };\ - interpret KP_Up+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=+0,y=-1);\ - };\ - interpret KP_9+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=+1,y=-1);\ - };\ - interpret KP_Prior+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=+1,y=-1);\ - };\ - interpret KP_5+AnyOfOrNone(all) {\ - repeat= True;\ - action= PtrBtn(button=default);\ - };\ - interpret KP_Begin+AnyOfOrNone(all) {\ - repeat= True;\ - action= PtrBtn(button=default);\ - };\ - interpret KP_F2+AnyOfOrNone(all) {\ - repeat= True;\ - action= SetPtrDflt(affect=button,button=1);\ - };\ - interpret KP_Divide+AnyOfOrNone(all) {\ - repeat= True;\ - action= SetPtrDflt(affect=button,button=1);\ - };\ - interpret KP_F3+AnyOfOrNone(all) {\ - repeat= True;\ - action= SetPtrDflt(affect=button,button=2);\ - };\ - interpret KP_Multiply+AnyOfOrNone(all) {\ - repeat= True;\ - action= SetPtrDflt(affect=button,button=2);\ - };\ - interpret KP_F4+AnyOfOrNone(all) {\ - repeat= True;\ - action= SetPtrDflt(affect=button,button=3);\ - };\ - interpret KP_Subtract+AnyOfOrNone(all) {\ - repeat= True;\ - action= SetPtrDflt(affect=button,button=3);\ - };\ - interpret KP_Separator+AnyOfOrNone(all) {\ - repeat= True;\ - action= PtrBtn(button=default,count=2);\ - };\ - interpret KP_Add+AnyOfOrNone(all) {\ - repeat= True;\ - action= PtrBtn(button=default,count=2);\ - };\ - interpret KP_0+AnyOfOrNone(all) {\ - repeat= True;\ - action= LockPtrBtn(button=default,affect=lock);\ - };\ - interpret KP_Insert+AnyOfOrNone(all) {\ - repeat= True;\ - action= LockPtrBtn(button=default,affect=lock);\ - };\ - interpret KP_Decimal+AnyOfOrNone(all) {\ - repeat= True;\ - action= LockPtrBtn(button=default,affect=unlock);\ - };\ - interpret KP_Delete+AnyOfOrNone(all) {\ - repeat= True;\ - action= LockPtrBtn(button=default,affect=unlock);\ - };\ - interpret F25+AnyOfOrNone(all) {\ - repeat= True;\ - action= SetPtrDflt(affect=button,button=1);\ - };\ - interpret F26+AnyOfOrNone(all) {\ - repeat= True;\ - action= SetPtrDflt(affect=button,button=2);\ - };\ - interpret F27+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=-1,y=-1);\ - };\ - interpret F29+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=+1,y=-1);\ - };\ - interpret F31+AnyOfOrNone(all) {\ - repeat= True;\ - action= PtrBtn(button=default);\ - };\ - interpret F33+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=-1,y=+1);\ - };\ - interpret F35+AnyOfOrNone(all) {\ - repeat= True;\ - action= MovePtr(x=+1,y=+1);\ - };\ - interpret Pointer_Button_Dflt+AnyOfOrNone(all) {\ - action= PtrBtn(button=default);\ - };\ - interpret Pointer_Button1+AnyOfOrNone(all) {\ - action= PtrBtn(button=1);\ - };\ - interpret Pointer_Button2+AnyOfOrNone(all) {\ - action= PtrBtn(button=2);\ - };\ - interpret Pointer_Button3+AnyOfOrNone(all) {\ - action= PtrBtn(button=3);\ - };\ - interpret Pointer_DblClick_Dflt+AnyOfOrNone(all) {\ - action= PtrBtn(button=default,count=2);\ - };\ - interpret Pointer_DblClick1+AnyOfOrNone(all) {\ - action= PtrBtn(button=1,count=2);\ - };\ - interpret Pointer_DblClick2+AnyOfOrNone(all) {\ - action= PtrBtn(button=2,count=2);\ - };\ - interpret Pointer_DblClick3+AnyOfOrNone(all) {\ - action= PtrBtn(button=3,count=2);\ - };\ - interpret Pointer_Drag_Dflt+AnyOfOrNone(all) {\ - action= LockPtrBtn(button=default);\ - };\ - interpret Pointer_Drag1+AnyOfOrNone(all) {\ - action= LockPtrBtn(button=1);\ - };\ - interpret Pointer_Drag2+AnyOfOrNone(all) {\ - action= LockPtrBtn(button=2);\ - };\ - interpret Pointer_Drag3+AnyOfOrNone(all) {\ - action= LockPtrBtn(button=3);\ - };\ - interpret Pointer_EnableKeys+AnyOfOrNone(all) {\ - action= LockControls(controls=MouseKeys);\ - };\ - interpret Pointer_Accelerate+AnyOfOrNone(all) {\ - action= LockControls(controls=MouseKeysAccel);\ - };\ - interpret Pointer_DfltBtnNext+AnyOfOrNone(all) {\ - action= SetPtrDflt(affect=button,button=+1);\ - };\ - interpret Pointer_DfltBtnPrev+AnyOfOrNone(all) {\ - action= SetPtrDflt(affect=button,button=-1);\ - };\ - interpret AccessX_Enable+AnyOfOrNone(all) {\ - action= LockControls(controls=AccessXKeys);\ - };\ - interpret AccessX_Feedback_Enable+AnyOfOrNone(all) {\ - action= LockControls(controls=AccessXFeedback);\ - };\ - interpret RepeatKeys_Enable+AnyOfOrNone(all) {\ - action= LockControls(controls=RepeatKeys);\ - };\ - interpret SlowKeys_Enable+AnyOfOrNone(all) {\ - action= LockControls(controls=SlowKeys);\ - };\ - interpret BounceKeys_Enable+AnyOfOrNone(all) {\ - action= LockControls(controls=BounceKeys);\ - };\ - interpret StickyKeys_Enable+AnyOfOrNone(all) {\ - action= LockControls(controls=StickyKeys);\ - };\ - interpret MouseKeys_Enable+AnyOfOrNone(all) {\ - action= LockControls(controls=MouseKeys);\ - };\ - interpret MouseKeys_Accel_Enable+AnyOfOrNone(all) {\ - action= LockControls(controls=MouseKeysAccel);\ - };\ - interpret Overlay1_Enable+AnyOfOrNone(all) {\ - action= LockControls(controls=none);\ - };\ - interpret Overlay2_Enable+AnyOfOrNone(all) {\ - action= LockControls(controls=none);\ - };\ - interpret AudibleBell_Enable+AnyOfOrNone(all) {\ - action= LockControls(controls=AudibleBell);\ - };\ - interpret Terminate_Server+AnyOfOrNone(all) {\ - action= Terminate();\ - };\ - interpret Alt_L+AnyOfOrNone(all) {\ - action= SetMods(modifiers=Alt,clearLocks);\ - };\ - interpret Alt_R+AnyOfOrNone(all) {\ - action= SetMods(modifiers=Alt,clearLocks);\ - };\ - interpret Meta_L+AnyOfOrNone(all) {\ - action= SetMods(modifiers=Meta,clearLocks);\ - };\ - interpret Meta_R+AnyOfOrNone(all) {\ - action= SetMods(modifiers=Meta,clearLocks);\ - };\ - interpret Super_L+AnyOfOrNone(all) {\ - action= SetMods(modifiers=Super,clearLocks);\ - };\ - interpret Super_R+AnyOfOrNone(all) {\ - action= SetMods(modifiers=Super,clearLocks);\ - };\ - interpret Hyper_L+AnyOfOrNone(all) {\ - action= SetMods(modifiers=Hyper,clearLocks);\ - };\ - interpret Hyper_R+AnyOfOrNone(all) {\ - action= SetMods(modifiers=Hyper,clearLocks);\ - };\ - interpret Shift_L+AnyOfOrNone(all) {\ - action= SetMods(modifiers=Shift,clearLocks);\ - };\ - interpret XF86Switch_VT_1+AnyOfOrNone(all) {\ - repeat= True;\ - action= SwitchScreen(screen=1,!same);\ - };\ - interpret XF86Switch_VT_2+AnyOfOrNone(all) {\ - repeat= True;\ - action= SwitchScreen(screen=2,!same);\ - };\ - interpret XF86Switch_VT_3+AnyOfOrNone(all) {\ - repeat= True;\ - action= SwitchScreen(screen=3,!same);\ - };\ - interpret XF86Switch_VT_4+AnyOfOrNone(all) {\ - repeat= True;\ - action= SwitchScreen(screen=4,!same);\ - };\ - interpret XF86Switch_VT_5+AnyOfOrNone(all) {\ - repeat= True;\ - action= SwitchScreen(screen=5,!same);\ - };\ - interpret XF86Switch_VT_6+AnyOfOrNone(all) {\ - repeat= True;\ - action= SwitchScreen(screen=6,!same);\ - };\ - interpret XF86Switch_VT_7+AnyOfOrNone(all) {\ - repeat= True;\ - action= SwitchScreen(screen=7,!same);\ - };\ - interpret XF86Switch_VT_8+AnyOfOrNone(all) {\ - repeat= True;\ - action= SwitchScreen(screen=8,!same);\ - };\ - interpret XF86Switch_VT_9+AnyOfOrNone(all) {\ - repeat= True;\ - action= SwitchScreen(screen=9,!same);\ - };\ - interpret XF86Switch_VT_10+AnyOfOrNone(all) {\ - repeat= True;\ - action= SwitchScreen(screen=10,!same);\ - };\ - interpret XF86Switch_VT_11+AnyOfOrNone(all) {\ - repeat= True;\ - action= SwitchScreen(screen=11,!same);\ - };\ - interpret XF86Switch_VT_12+AnyOfOrNone(all) {\ - repeat= True;\ - action= SwitchScreen(screen=12,!same);\ - };\ - interpret XF86LogGrabInfo+AnyOfOrNone(all) {\ - repeat= True;\ - action= Private(type=0x86,data[0]=0x50,data[1]=0x72,data[2]=0x47,data[3]=0x72,data[4]=0x62,data[5]=0x73,data[6]=0x00);\ - };\ - interpret XF86LogWindowTree+AnyOfOrNone(all) {\ - repeat= True;\ - action= Private(type=0x86,data[0]=0x50,data[1]=0x72,data[2]=0x57,data[3]=0x69,data[4]=0x6e,data[5]=0x73,data[6]=0x00);\ - };\ - interpret XF86Next_VMode+AnyOfOrNone(all) {\ - repeat= True;\ - action= Private(type=0x86,data[0]=0x2b,data[1]=0x56,data[2]=0x4d,data[3]=0x6f,data[4]=0x64,data[5]=0x65,data[6]=0x00);\ - };\ - interpret XF86Prev_VMode+AnyOfOrNone(all) {\ - repeat= True;\ - action= Private(type=0x86,data[0]=0x2d,data[1]=0x56,data[2]=0x4d,data[3]=0x6f,data[4]=0x64,data[5]=0x65,data[6]=0x00);\ - };\ - interpret ISO_Level5_Shift+AnyOfOrNone(all) {\ - action= SetMods(modifiers=LevelFive,clearLocks);\ - };\ - interpret ISO_Level5_Latch+AnyOfOrNone(all) {\ - action= LatchMods(modifiers=LevelFive,clearLocks,latchToLock);\ - };\ - interpret ISO_Level5_Lock+AnyOfOrNone(all) {\ - action= LockMods(modifiers=LevelFive);\ - };\ - interpret Caps_Lock+AnyOfOrNone(all) {\ - action= LockMods(modifiers=Lock);\ - };\ - interpret Any+Exactly(Lock) {\ - action= LockMods(modifiers=Lock);\ - };\ - interpret Any+AnyOf(all) {\ - action= SetMods(modifiers=modMapMods,clearLocks);\ - };\ - indicator \"Caps Lock\" {\ - whichModState= locked;\ - modifiers= Lock;\ - };\ - indicator \"Num Lock\" {\ - whichModState= locked;\ - modifiers= NumLock;\ - };\ - indicator \"Scroll Lock\" {\ - whichModState= locked;\ - modifiers= ScrollLock;\ - };\ - indicator \"Shift Lock\" {\ - whichModState= locked;\ - modifiers= Shift;\ - };\ - indicator \"Group 2\" {\ - groups= 0xfe;\ - };\ - indicator \"Mouse Keys\" {\ - controls= MouseKeys;\ - };\ -};\ -\ -xkb_symbols \"(unnamed)\" {\ - name[group1]=\"English (US)\";\ -\ - key { [ Escape ] };\ - key { [ 1, exclam ] };\ - key { [ 2, at ] };\ - key { [ 3, numbersign ] };\ - key { [ 4, dollar ] };\ - key { [ 5, percent ] };\ - key { [ 6, asciicircum ] };\ - key { [ 7, ampersand ] };\ - key { [ 8, asterisk ] };\ - key { [ 9, parenleft ] };\ - key { [ 0, parenright ] };\ - key { [ minus, underscore ] };\ - key { [ equal, plus ] };\ - key { [ BackSpace, BackSpace ] };\ - key { [ Tab, ISO_Left_Tab ] };\ - key { [ q, Q, 1 ] };\ - key { [ w, W, 2 ] };\ - key { [ e, E, 3 ] };\ - key { [ r, R, 4 ] };\ - key { [ t, T, 5 ] };\ - key { [ y, Y, 6 ] };\ - key { [ u, U, 7 ] };\ - key { [ i, I, 8 ] };\ - key { [ o, O, 9 ] };\ - key { [ p, P, 0 ] };\ - key { [ bracketleft, braceleft ] };\ - key { [ bracketright, braceright ] };\ - key { [ Return ] };\ - key { [ Control_L ] };\ - key { [ a, A, minus ] };\ - key { [ s, S, at ] };\ - key { [ d, D, asterisk ] };\ - key { [ f, F, asciicircum ] };\ - key { [ g, G, colon ] };\ - key { [ h, H, semicolon ] };\ - key { [ j, J, parenleft ] };\ - key { [ k, K, parenright ] };\ - key { [ l, L, asciitilde ] };\ - key { [ semicolon, colon ] };\ - key { [ apostrophe, quotedbl ] };\ - key { [ grave, asciitilde ] };\ - key { [ Shift_L ] };\ - key { [ backslash, bar ] };\ - key { [ z, Z, slash ] };\ - key { [ x, X, apostrophe ] };\ - key { [ c, C, quotedbl ] };\ - key { [ v, V, plus ] };\ - key { [ b, B, equal ] };\ - key { [ n, N, question ] };\ - key { [ m, M, exclam ] };\ - key { [ comma, less, backslash] };\ - key { [ period, greater, bar ] };\ - key { [ slash, question ] };\ - key { [ Shift_R ] };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ KP_Multiply, KP_Multiply, KP_Multiply, KP_Multiply, XF86ClearGrab ]\ - };\ - key { [ Alt_L, Meta_L ] };\ - key { [ space ] };\ - key { [ Caps_Lock ] };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ F1, F1, F1, F1, XF86Switch_VT_1 ]\ - };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ F2, F2, F2, F2, XF86Switch_VT_2 ]\ - };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ F3, F3, F3, F3, XF86Switch_VT_3 ]\ - };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ F4, F4, F4, F4, XF86Switch_VT_4 ]\ - };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ F5, F5, F5, F5, XF86Switch_VT_5 ]\ - };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ F6, F6, F6, F6, XF86Switch_VT_6 ]\ - };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ F7, F7, F7, F7, XF86Switch_VT_7 ]\ - };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ F8, F8, F8, F8, XF86Switch_VT_8 ]\ - };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ F9, F9, F9, F9, XF86Switch_VT_9 ]\ - };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ F10, F10, F10, F10, XF86Switch_VT_10 ]\ - };\ - key { [ Num_Lock ] };\ - key { [ Scroll_Lock ] };\ - key { [ KP_Home, KP_7 ] };\ - key { [ KP_Up, KP_8 ] };\ - key { [ KP_Prior, KP_9 ] };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ KP_Subtract, KP_Subtract, KP_Subtract, KP_Subtract, XF86Prev_VMode ]\ - };\ - key { [ KP_Left, KP_4 ] };\ - key { [ KP_Begin, KP_5 ] };\ - key { [ KP_Right, KP_6 ] };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ KP_Add, KP_Add, KP_Add, KP_Add, XF86Next_VMode ]\ - };\ - key { [ KP_End, KP_1 ] };\ - key { [ KP_Down, KP_2 ] };\ - key { [ KP_Next, KP_3 ] };\ - key { [ KP_Insert, KP_0 ] };\ - key { [ KP_Delete, KP_Decimal ] };\ - key { [ ISO_Level3_Shift ] };\ - key { [ less, greater, bar, brokenbar ] };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ F11, F11, F11, F11, XF86Switch_VT_11 ]\ - };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ F12, F12, F12, F12, XF86Switch_VT_12 ]\ - };\ - key { [ Katakana ] };\ - key { [ Hiragana ] };\ - key { [ Henkan_Mode ] };\ - key { [ Hiragana_Katakana ] };\ - key { [ Muhenkan ] };\ - key { [ KP_Enter ] };\ - key { [ Control_R ] };\ - key {\ - type= \"CTRL+ALT\",\ - symbols[Group1]= [ KP_Divide, KP_Divide, KP_Divide, KP_Divide, XF86Ungrab ]\ - };\ - key {\ - type= \"PC_ALT_LEVEL2\",\ - symbols[Group1]= [ Print, Sys_Req ]\ - };\ - key {\ - type= \"TWO_LEVEL\",\ - symbols[Group1]= [ Alt_R, Meta_R ]\ - };\ - key { [ Linefeed ] };\ - key { [ Home ] };\ - key { [ Up ] };\ - key { [ Prior ] };\ - key { [ Left ] };\ - key { [ Right ] };\ - key { [ End ] };\ - key { [ Down ] };\ - key { [ Next ] };\ - key { [ Insert ] };\ - key { [ Delete ] };\ - key { [ XF86AudioMute ] };\ - key { [ XF86AudioLowerVolume ] };\ - key { [ XF86AudioRaiseVolume ] };\ - key { [ XF86PowerOff ] };\ - key { [ KP_Equal ] };\ - key { [ plusminus ] };\ - key {\ - type= \"PC_CONTROL_LEVEL2\",\ - symbols[Group1]= [ Pause, Break ]\ - };\ - key { [ XF86LaunchA ] };\ - key { [ KP_Decimal, KP_Decimal ] };\ - key { [ Hangul ] };\ - key { [ Hangul_Hanja ] };\ - key { [ Super_L ] };\ - key { [ Super_R ] };\ - key { [ Menu ] };\ - key { [ Cancel ] };\ - key { [ Redo ] };\ - key { [ SunProps ] };\ - key { [ Undo ] };\ - key { [ SunFront ] };\ - key { [ XF86Copy ] };\ - key { [ XF86Open ] };\ - key { [ XF86Paste ] };\ - key { [ Find ] };\ - key { [ XF86Cut ] };\ - key { [ Help ] };\ - key { [ XF86MenuKB ] };\ - key { [ XF86Calculator ] };\ - key { [ XF86Sleep ] };\ - key { [ XF86WakeUp ] };\ - key { [ XF86Explorer ] };\ - key { [ XF86Send ] };\ - key { [ XF86Xfer ] };\ - key { [ XF86Launch1 ] };\ - key { [ XF86Launch2 ] };\ - key { [ XF86WWW ] };\ - key { [ XF86DOS ] };\ - key { [ XF86ScreenSaver ] };\ - key { [ XF86RotateWindows ] };\ - key { [ XF86TaskPane ] };\ - key { [ XF86Mail ] };\ - key { [ XF86Favorites ] };\ - key { [ XF86MyComputer ] };\ - key { [ XF86Back ] };\ - key { [ XF86Forward ] };\ - key { [ XF86Eject ] };\ - key { [ XF86Eject, XF86Eject ] };\ - key { [ XF86AudioNext ] };\ - key { [ XF86AudioPlay, XF86AudioPause ] };\ - key { [ XF86AudioPrev ] };\ - key { [ XF86AudioStop, XF86Eject ] };\ - key { [ XF86AudioRecord ] };\ - key { [ XF86AudioRewind ] };\ - key { [ XF86Phone ] };\ - key { [ XF86Tools ] };\ - key { [ XF86HomePage ] };\ - key { [ XF86Reload ] };\ - key { [ XF86Close ] };\ - key { [ XF86ScrollUp ] };\ - key { [ XF86ScrollDown ] };\ - key { [ parenleft ] };\ - key { [ parenright ] };\ - key { [ XF86New ] };\ - key { [ Redo ] };\ - key { [ XF86Tools ] };\ - key { [ XF86Launch5 ] };\ - key { [ XF86Launch6 ] };\ - key { [ XF86Launch7 ] };\ - key { [ XF86Launch8 ] };\ - key { [ XF86Launch9 ] };\ - key { [ XF86AudioMicMute ] };\ - key { [ XF86TouchpadToggle ] };\ - key { [ XF86TouchpadOn ] };\ - key { [ XF86TouchpadOff ] };\ - key { [ Mode_switch ] };\ - key { [ NoSymbol, Alt_L ] };\ - key { [ NoSymbol, Meta_L ] };\ - key { [ NoSymbol, Super_L ] };\ - key { [ NoSymbol, Hyper_L ] };\ - key { [ XF86AudioPlay ] };\ - key { [ XF86AudioPause ] };\ - key { [ XF86Launch3 ] };\ - key { [ XF86Launch4 ] };\ - key { [ XF86LaunchB ] };\ - key { [ XF86Suspend ] };\ - key { [ XF86Close ] };\ - key { [ XF86AudioPlay ] };\ - key { [ XF86AudioForward ] };\ - key { [ Print ] };\ - key { [ XF86WebCam ] };\ - key { [ XF86AudioPreset ] };\ - key { [ XF86Mail ] };\ - key { [ XF86Messenger ] };\ - key { [ XF86Search ] };\ - key { [ XF86Go ] };\ - key { [ XF86Finance ] };\ - key { [ XF86Game ] };\ - key { [ XF86Shop ] };\ - key { [ Cancel ] };\ - key { [ XF86MonBrightnessDown ] };\ - key { [ XF86MonBrightnessUp ] };\ - key { [ XF86AudioMedia ] };\ - key { [ XF86Display ] };\ - key { [ XF86KbdLightOnOff ] };\ - key { [ XF86KbdBrightnessDown ] };\ - key { [ XF86KbdBrightnessUp ] };\ - key { [ XF86Send ] };\ - key { [ XF86Reply ] };\ - key { [ XF86MailForward ] };\ - key { [ XF86Save ] };\ - key { [ XF86Documents ] };\ - key { [ XF86Battery ] };\ - key { [ XF86Bluetooth ] };\ - key { [ XF86WLAN ] };\ - key { [ XF86UWB ] };\ - key { [ XF86WWAN ] };\ - key { [ XF86RFKill ] };\ - modifier_map Shift { , };\ - modifier_map Lock { };\ - modifier_map Control { , };\ - modifier_map Mod1 { , , };\ - modifier_map Mod2 { };\ - modifier_map Mod4 { , , , };\ - modifier_map Mod5 { , };\ -};\ -\ -};\ -"; diff --git a/crates/cursor-move-webapp/src/utils/mod.rs b/crates/cursor-move-webapp/src/utils/mod.rs new file mode 100644 index 0000000..cd13774 --- /dev/null +++ b/crates/cursor-move-webapp/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod mouse_filter_buffer; diff --git a/crates/cursor-move-webapp/src/utils/mouse_filter_buffer.rs b/crates/cursor-move-webapp/src/utils/mouse_filter_buffer.rs new file mode 100644 index 0000000..da39fc6 --- /dev/null +++ b/crates/cursor-move-webapp/src/utils/mouse_filter_buffer.rs @@ -0,0 +1,80 @@ +use std::collections::VecDeque; + +use dioxus_html::geometry::{ + ElementSpace, + euclid::{Point2D, Vector2D}, +}; +use wasmtimer::std::SystemTime; + +pub struct MouseFilterBufferEntry { + pub position: Point2D, + pub time: SystemTime, +} + +pub struct MouseFilterBuffer { + buffer: VecDeque, +} + +impl MouseFilterBuffer { + pub fn new( + size: usize, + initial: Point2D, + initial_timestamp: SystemTime, + ) -> Self { + let mut buffer = VecDeque::with_capacity(size); + buffer.push_back(MouseFilterBufferEntry { + position: initial, + time: initial_timestamp, + }); + Self { buffer } + } + + pub fn push( + &mut self, + point: Point2D, + time: SystemTime, + ) { + if self.buffer.len() == self.buffer.capacity() { + self.buffer.pop_front(); + } + self.buffer.push_back(MouseFilterBufferEntry { + position: point, + time, + }); + } + + pub fn back(&self) -> &MouseFilterBufferEntry { + self.buffer + .back() + .expect("Mouse filter buffer may never have less than one element") + } + + pub fn average_velocity_since( + &self, + start_time: SystemTime, + ) -> Vector2D { + let mut total_distance = Vector2D::zero(); + + let mut i = self.buffer.iter(); + + let mut last = if let Some(it) = i.find(|it| it.time >= start_time) { + it + } else { + return Vector2D::zero(); + }; + let start_time = last.time; + let mut last_time = last.time; + + for point in i { + total_distance += (point.position - last.position); + last = point; + last_time = point.time; + } + + if total_distance == Vector2D::zero() { + return Vector2D::zero(); + } + + total_distance / (last_time.duration_since(start_time).unwrap().as_secs_f64()) + } +} diff --git a/crates/cursor-move-webapp/src/views/home.rs b/crates/cursor-move-webapp/src/views/home.rs index 51edcaa..07651f7 100644 --- a/crates/cursor-move-webapp/src/views/home.rs +++ b/crates/cursor-move-webapp/src/views/home.rs @@ -1,4 +1,4 @@ -use crate::components::MouseArea; +use crate::components::{Controls, MouseArea}; use dioxus::prelude::*; /// The Home page component that will be rendered when the current route is `[Route::Home]` @@ -10,7 +10,7 @@ pub fn Home() -> Element { rsx! { div { class: Styles::container, - MouseArea { } + Controls { } } } }