diff --git a/dash-frontend/assets/lang/en.json b/dash-frontend/assets/lang/en.json index ca0b1d27..4c5f5c89 100644 --- a/dash-frontend/assets/lang/en.json +++ b/dash-frontend/assets/lang/en.json @@ -115,6 +115,8 @@ "HANDSFREE_POINTER_HELP": "Input to use when motion\ncontrollers are unavailable.\nLeft pinch is grab, right is click.", "HIDE_GRAB_HELP": "Hide grab help", "HIDE_USERNAME": "Hide username", + "INPUT_EMULATION_METHOD": "Input emulation method", + "INPUT_EMULATION_METHOD_HELP": "Try change this in case mouse or\nkeyboard input does not register.", "INPUT_PROFILES": "Change Input Bindings", "INPUT_PROFILES_HELP": "OpenXR controller input bindings", "INVERT_SCROLL_DIRECTION_X": "Invert horizontal scroll direction", @@ -141,10 +143,15 @@ "HMD_ONLY": "HMD only", "HMD_PINCH": "HMD + pinch", "NONE": "None", + "NONE_INPUT_HELP": "Do not emulate mouse and keyboard.\nWill not be able to interact with screens.", "PIPEWIRE_HELP": "Fast GPU capture,\nstandard on all desktops.", "PW_FALLBACK_HELP": "Slow method with high CPU usage.\nTry in case PipeWire GPU doesn't work", "SCREENCOPY_GPU_HELP": "Fast, no screen share popups.\nWorks on: Hyprland, Niri, River, Sway", - "SCREENCOPY_HELP": "Slow, no screen share popups.\nWorks on: Hyprland, Niri, River, Sway" + "SCREENCOPY_HELP": "Slow, no screen share popups.\nWorks on: Hyprland, Niri, River, Sway", + "UINPUT": "Device emulation", + "UINPUT_HELP": "Uses the uinput module to emulate a device.\nYour user must be in the input group.\nKnown to work well on most desktops.", + "WL_VIRTUAL": "Wayland virtual input", + "WL_VIRTUAL_HELP": "Send events to the Wayland compositor using\nzwlr_virtual_pointer and zwp_virtual_keyboard.\nOnly works reliably on some desktops.\nDoes NOT work on KDE, GNOME or COSMIC." }, "POINTER_LERP_FACTOR": "Pointer smoothing", "REQUIRES_RESTART": "Requires restart", diff --git a/dash-frontend/src/tab/settings/mod.rs b/dash-frontend/src/tab/settings/mod.rs index 3360e10a..afebc9db 100644 --- a/dash-frontend/src/tab/settings/mod.rs +++ b/dash-frontend/src/tab/settings/mod.rs @@ -284,6 +284,7 @@ enum SettingType { HandsfreePointer, HideGrabHelp, HideUsername, + InputEmulationMethod, InvertScrollDirectionX, InvertScrollDirectionY, KeyboardMiddleClick, @@ -392,6 +393,10 @@ impl SettingType { Self::CaptureMethod => { config.capture_method = wlx_common::config::CaptureMethod::from_str(value).expect("Invalid enum value!") } + Self::InputEmulationMethod => { + config.input_emulation_method = + wlx_common::config::InputEmulationMethod::from_str(value).expect("Invalid enum value!") + } Self::KeyboardMiddleClick => { config.keyboard_middle_click_mode = wlx_common::config::AltModifier::from_str(value).expect("Invalid enum value!") @@ -409,6 +414,7 @@ impl SettingType { fn get_enum_title(self, config: &mut GeneralConfig) -> Translation { match self { Self::CaptureMethod => Self::get_enum_title_inner(config.capture_method), + Self::InputEmulationMethod => Self::get_enum_title_inner(config.input_emulation_method), Self::KeyboardMiddleClick => Self::get_enum_title_inner(config.keyboard_middle_click_mode), Self::HandsfreePointer => Self::get_enum_title_inner(config.handsfree_pointer), Self::Language => match &config.language { @@ -454,6 +460,7 @@ impl SettingType { Self::HandsfreePointer => Ok("APP_SETTINGS.HANDSFREE_POINTER"), Self::HideGrabHelp => Ok("APP_SETTINGS.HIDE_GRAB_HELP"), Self::HideUsername => Ok("APP_SETTINGS.HIDE_USERNAME"), + Self::InputEmulationMethod => Ok("APP_SETTINGS.INPUT_EMULATION_METHOD"), Self::InvertScrollDirectionX => Ok("APP_SETTINGS.INVERT_SCROLL_DIRECTION_X"), Self::InvertScrollDirectionY => Ok("APP_SETTINGS.INVERT_SCROLL_DIRECTION_Y"), Self::KeyboardMiddleClick => Ok("APP_SETTINGS.KEYBOARD_MIDDLE_CLICK"), @@ -500,6 +507,7 @@ impl SettingType { Self::DoubleCursorFix => Some("APP_SETTINGS.DOUBLE_CURSOR_FIX_HELP"), Self::GridOpacity => Some("APP_SETTINGS.GRID_OPACITY_HELP"), Self::HandsfreePointer => Some("APP_SETTINGS.HANDSFREE_POINTER_HELP"), + Self::InputEmulationMethod => Some("APP_SETTINGS.INPUT_EMULATION_METHOD_HELP"), Self::KeyboardMiddleClick => Some("APP_SETTINGS.KEYBOARD_MIDDLE_CLICK_HELP"), Self::LeftHandedMouse => Some("APP_SETTINGS.LEFT_HANDED_MOUSE_HELP"), Self::ScreenRenderDown => Some("APP_SETTINGS.SCREEN_RENDER_DOWN_HELP"), @@ -527,6 +535,7 @@ impl SettingType { | Self::DoubleCursorFix | Self::Language | Self::CaptureMethod + | Self::InputEmulationMethod ) } diff --git a/dash-frontend/src/tab/settings/tab_misc.rs b/dash-frontend/src/tab/settings/tab_misc.rs index 29b57522..3d883887 100644 --- a/dash-frontend/src/tab/settings/tab_misc.rs +++ b/dash-frontend/src/tab/settings/tab_misc.rs @@ -10,6 +10,7 @@ impl SettingsTab for State {} impl State { pub fn mount(par: SettingsMountParams) -> anyhow::Result { let c = options_category(par.mp, par.id_parent, "APP_SETTINGS.MISC", "dashboard/blocks.svg")?; + options_dropdown::(par.mp, c, &SettingType::InputEmulationMethod)?; options_dropdown::(par.mp, c, &SettingType::CaptureMethod)?; options_checkbox(par.mp, c, SettingType::XwaylandByDefault)?; options_checkbox(par.mp, c, SettingType::UprightScreenFix)?; diff --git a/dash-frontend/src/views/bindings.rs b/dash-frontend/src/views/bindings.rs index 13a1eac8..a3724a1c 100644 --- a/dash-frontend/src/views/bindings.rs +++ b/dash-frontend/src/views/bindings.rs @@ -469,7 +469,9 @@ fn input_controls_for_hand( clicks_dropdown(mp, parent, action.clone(), click_type)?; if let Some(component) = current.as_ref().map(|x| x.component) - && component.is_analog() && &*action != "scroll" // hax + && component.is_analog() + && &*action != "scroll" + // hax { threshold_slider(mp, parent, action, side, threshold)?; } diff --git a/wayvr/src/state.rs b/wayvr/src/state.rs index ae4323f6..de36c007 100644 --- a/wayvr/src/state.rs +++ b/wayvr/src/state.rs @@ -92,7 +92,7 @@ impl AppState { .log_err("Could not initialize WayVR Server") .ok(); - let (hid_provider, mut hid_error) = HidWrapper::new(); + let (hid_provider, mut hid_error) = HidWrapper::new(session.config.input_emulation_method); #[cfg(feature = "osc")] let osc_sender = crate::subsystem::osc::OscSender::new(session.config.osc_out_port).ok(); diff --git a/wayvr/src/subsystem/hid/provider/dummy.rs b/wayvr/src/subsystem/hid/provider/dummy.rs index ecc9b4e2..b05afdc1 100644 --- a/wayvr/src/subsystem/hid/provider/dummy.rs +++ b/wayvr/src/subsystem/hid/provider/dummy.rs @@ -1,3 +1,4 @@ +use crate::overlays::toast::Toast; use crate::subsystem::hid::provider::HidProvider; use crate::subsystem::hid::{VirtualKey, WheelDelta, XkbKeymap}; use glam::Vec2; @@ -17,3 +18,7 @@ impl HidProvider for DummyProvider { fn commit(&mut self) {} } + +pub fn initialize_dummy() -> anyhow::Result, Toast> { + Ok(Box::new(DummyProvider {})) +} diff --git a/wayvr/src/subsystem/input.rs b/wayvr/src/subsystem/input.rs index 9c60c179..3b8d82e8 100644 --- a/wayvr/src/subsystem/input.rs +++ b/wayvr/src/subsystem/input.rs @@ -1,3 +1,5 @@ +use wlx_common::config::InputEmulationMethod; + use super::hid::{self, VirtualKey}; use crate::subsystem::hid::provider::HidProvider; @@ -17,9 +19,14 @@ pub struct HidWrapper { } impl HidWrapper { - pub fn new() -> (Self, Option) { - let (provider, toast) = hid::provider::wl_virtual::initialize_wl_virtual() - .or_else(|_| hid::provider::uinput::initialize_uinput()) + pub fn new(method: InputEmulationMethod) -> (Self, Option) { + let maybe_provider = match method { + InputEmulationMethod::Uinput => hid::provider::uinput::initialize_uinput(), + InputEmulationMethod::WlVirtual => hid::provider::wl_virtual::initialize_wl_virtual(), + InputEmulationMethod::None => hid::provider::dummy::initialize_dummy(), + }; + + let (provider, toast) = maybe_provider .map(|provider| (provider, None)) .unwrap_or_else(|toast| (Box::new(DummyProvider {}), Some(toast))); diff --git a/wlx-common/src/config.rs b/wlx-common/src/config.rs index 48871771..229168a5 100644 --- a/wlx-common/src/config.rs +++ b/wlx-common/src/config.rs @@ -40,6 +40,28 @@ pub enum CaptureMethod { ScreenCopyCpu, } +#[derive(Default, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumString, EnumProperty, VariantArray)] +pub enum InputEmulationMethod { + #[default] + #[strum(props( + Translation = "APP_SETTINGS.OPTION.UINPUT", + Tooltip = "APP_SETTINGS.OPTION.UINPUT_HELP" + ))] + Uinput, + + #[strum(props( + Translation = "APP_SETTINGS.OPTION.WL_VIRTUAL", + Tooltip = "APP_SETTINGS.OPTION.WL_VIRTUAL_HELP" + ))] + WlVirtual, + + #[strum(props( + Translation = "APP_SETTINGS.OPTION.NONE", + Tooltip = "APP_SETTINGS.OPTION.NONE_INPUT_HELP" + ))] + None, +} + #[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumString, EnumProperty, VariantArray)] pub enum AltModifier { #[default] @@ -292,6 +314,9 @@ pub struct GeneralConfig { #[serde(default)] pub capture_method: CaptureMethod, + #[serde(default)] + pub input_emulation_method: InputEmulationMethod, + #[serde(default = "def_true")] pub allow_sliding: bool,