mirror of https://github.com/wayvr-org/wayvr.git
handsfree alt-tab
This commit is contained in:
parent
0b8040b9ae
commit
4cd238e487
|
|
@ -74,8 +74,6 @@
|
|||
"NONE": "Keine",
|
||||
"HMD_PINCH": "HMD + Kneifen",
|
||||
"EYE_PINCH": "Auge + Kneifen",
|
||||
"EYE_ONLY": "Nur Auge",
|
||||
"HMD_ONLY": "Nur HMD",
|
||||
"NONE_INPUT_HELP": "Maus und Tastatur nicht emulieren.\nEs wird nicht möglich sein, mit Displays zu interagieren.",
|
||||
"UINPUT": "Gerätesimulation",
|
||||
"UINPUT_HELP": "Verwendet das uinput-Modul, um ein Gerät zu emulieren.\nIhr Benutzer muss in der Gruppe „input“ sein.\nBekannt dafür, auf den meisten Desktops gut zu funktionieren.",
|
||||
|
|
@ -315,4 +313,4 @@
|
|||
"REMOVE_FROM_FAVOURITES": "Aus Favoriten entfernen",
|
||||
"EMPTY": "Leer",
|
||||
"PINNED_APPS": "Angepinnte Anwendungen"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,6 +123,8 @@
|
|||
"FOCUS_FOLLOWS_MOUSE_MODE": "Mouse move on trigger touch",
|
||||
"HANDSFREE_POINTER": "Handsfree mode",
|
||||
"HANDSFREE_POINTER_HELP": "Input to use when motion\ncontrollers are unavailable.\nLeft pinch is grab, right is click.",
|
||||
"HANDSFREE_ALT_TAB": "Handsfree alt-tab aim",
|
||||
"HANDSFREE_ALT_TAB_HELP": "Hold alt-tab, aim at the desired window, then release to switch focus.",
|
||||
"HIDE_GRAB_HELP": "Hide grab help",
|
||||
"HIDE_USERNAME": "Hide username",
|
||||
"INPUT_EMULATION_METHOD": "Input emulation method",
|
||||
|
|
@ -148,9 +150,9 @@
|
|||
"OPTION": {
|
||||
"AUTO": "Automatic",
|
||||
"AUTO_HELP": "ScreenCopy GPU if supported,\notherwise PipeWire GPU.",
|
||||
"EYE_ONLY": "Eye only",
|
||||
"EYE_ONLY": "Eye laser",
|
||||
"EYE_PINCH": "Eye + pinch",
|
||||
"HMD_ONLY": "HMD only",
|
||||
"HMD_ONLY": "HMD laser",
|
||||
"HMD_PINCH": "HMD + pinch",
|
||||
"NONE": "None",
|
||||
"NONE_INPUT_HELP": "Do not emulate mouse and keyboard.\nWill not be able to interact with screens.",
|
||||
|
|
|
|||
|
|
@ -74,8 +74,6 @@
|
|||
"NONE": "Ninguno",
|
||||
"HMD_PINCH": "HMD + pellizco",
|
||||
"EYE_PINCH": "Ojo + pellizco",
|
||||
"EYE_ONLY": "Solo ojo",
|
||||
"HMD_ONLY": "Solo HMD",
|
||||
"NONE_INPUT_HELP": "No emular ratón y teclado.\nNo podrá interactuar con las pantallas.",
|
||||
"UINPUT": "Emulación de dispositivo",
|
||||
"UINPUT_HELP": "Utiliza el módulo uinput para emular un dispositivo.\nSu usuario debe estar en el grupo input.\nSe sabe que funciona bien en la mayoría de los escritorios.",
|
||||
|
|
@ -315,4 +313,4 @@
|
|||
"REMOVE_FROM_FAVOURITES": "Eliminar de favoritos",
|
||||
"EMPTY": "Vacío",
|
||||
"PINNED_APPS": "Aplicaciones ancladas"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,8 +76,6 @@
|
|||
"NONE": "Nessuno",
|
||||
"HMD_PINCH": "HMD + pizzico",
|
||||
"EYE_PINCH": "Occhio + pizzico",
|
||||
"EYE_ONLY": "Solo occhio",
|
||||
"HMD_ONLY": "Solo HMD",
|
||||
"NONE_INPUT_HELP": "Non emulare mouse e tastiera.\nNon sarà possibile interagire con gli schermi.",
|
||||
"UINPUT": "Emulazione dispositivo",
|
||||
"UINPUT_HELP": "Utilizza il modulo uinput per emulare un dispositivo.\nL'utente deve far parte del gruppo input.\nRisultato ottimale su quasi tutti i desktop.",
|
||||
|
|
@ -315,4 +313,4 @@
|
|||
"REMOVE_FROM_FAVOURITES": "Rimuovi dai preferiti",
|
||||
"EMPTY": "Vuoto",
|
||||
"PINNED_APPS": "Applicazioni fissate"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,8 +74,6 @@
|
|||
"NONE": "なし",
|
||||
"HMD_PINCH": "HMD + ピンチ",
|
||||
"EYE_PINCH": "つまんで目を合わせる",
|
||||
"EYE_ONLY": "視野のみ",
|
||||
"HMD_ONLY": "HMDのみ",
|
||||
"NONE_INPUT_HELP": "マウスとキーボードをエミュレートしません。\nディスプレイを操作できなくなります。",
|
||||
"UINPUT": "デバイス・エミュレーション",
|
||||
"UINPUT_HELP": "uinput モジュールを使用してデバイスをエミュレートします。\nユーザーが input グループに属している必要があります。\nほとんどのデスクトップ環境で正常に動作することが確認されています。",
|
||||
|
|
@ -315,4 +313,4 @@
|
|||
"REMOVE_FROM_FAVOURITES": "お気に入りから削除",
|
||||
"EMPTY": "空",
|
||||
"PINNED_APPS": "ピン留めされたアプリケーション"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,8 +69,6 @@
|
|||
"NONE": "Brak",
|
||||
"HMD_PINCH": "HMD + ściśnięcie placami",
|
||||
"EYE_PINCH": "Ściśnięcie palcami + oko",
|
||||
"EYE_ONLY": "Tylko oko",
|
||||
"HMD_ONLY": "Tylko HMD",
|
||||
"NONE_INPUT_HELP": "Nie emuluj myszy ani klawiatury.\nBrak możliwości interakcji z ekranami.",
|
||||
"UINPUT": "Emulacja urządzenia",
|
||||
"UINPUT_HELP": "Używa modułu uinput do emulowania urządzenia.\nTwoje konto użytkownika musi należeć do grupy input.\nWiadomo, że działa dobrze na większości komputerów stacjonarnych.",
|
||||
|
|
@ -315,4 +313,4 @@
|
|||
"REMOVE_FROM_FAVOURITES": "Usuń z ulubionych",
|
||||
"EMPTY": "Puste",
|
||||
"PINNED_APPS": "Przypięte aplikacje"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,8 +76,6 @@
|
|||
"NONE": "无",
|
||||
"HMD_PINCH": "HMD + 捏合",
|
||||
"EYE_PINCH": "眼睛 + 捏合",
|
||||
"EYE_ONLY": "仅眼球",
|
||||
"HMD_ONLY": "仅限头显",
|
||||
"NONE_INPUT_HELP": "不模拟鼠标和键盘。\n将无法与屏幕进行交互。",
|
||||
"UINPUT": "设备模拟",
|
||||
"UINPUT_HELP": "使用 uinput 模块来模拟设备。\n您的用户必须处于 input 用户组中。\n已知在大多数桌面上运行良好。",
|
||||
|
|
@ -315,4 +313,4 @@
|
|||
"REMOVE_FROM_FAVOURITES": "从收藏中移除",
|
||||
"EMPTY": "空",
|
||||
"PINNED_APPS": "已固定应用程序"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,6 +303,7 @@ pub(crate) enum SettingType {
|
|||
EnableWatch,
|
||||
FocusFollowsMouseMode,
|
||||
GridOpacity,
|
||||
HandsfreeAltTab,
|
||||
HandsfreePointer,
|
||||
HideGrabHelp,
|
||||
HideUsername,
|
||||
|
|
@ -431,6 +432,9 @@ impl SettingType {
|
|||
config.keyboard_middle_click_mode =
|
||||
wlx_common::config::AltModifier::from_str(value).expect("Invalid enum value!")
|
||||
}
|
||||
Self::HandsfreeAltTab => {
|
||||
config.handsfree_alt_tab = wlx_common::config::HandsfreeAltTab::from_str(value).expect("Invalid enum value!")
|
||||
}
|
||||
Self::HandsfreePointer => {
|
||||
config.handsfree_pointer = wlx_common::config::HandsfreePointer::from_str(value).expect("Invalid enum value!")
|
||||
}
|
||||
|
|
@ -447,6 +451,7 @@ impl SettingType {
|
|||
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::HandsfreeAltTab => Self::get_enum_title_inner(config.handsfree_alt_tab),
|
||||
Self::Language => match &config.language {
|
||||
Some(lang) => Self::get_enum_title_inner(*lang),
|
||||
None => Translation::from_translation_key("APP_SETTINGS.OPTION.AUTO"),
|
||||
|
|
@ -488,6 +493,7 @@ impl SettingType {
|
|||
Self::DoubleCursorFix => Ok("APP_SETTINGS.DOUBLE_CURSOR_FIX"),
|
||||
Self::FocusFollowsMouseMode => Ok("APP_SETTINGS.FOCUS_FOLLOWS_MOUSE_MODE"),
|
||||
Self::GridOpacity => Ok("APP_SETTINGS.GRID_OPACITY"),
|
||||
Self::HandsfreeAltTab => Ok("APP_SETTINGS.HANDSFREE_ALT_TAB"),
|
||||
Self::HandsfreePointer => Ok("APP_SETTINGS.HANDSFREE_POINTER"),
|
||||
Self::HideGrabHelp => Ok("APP_SETTINGS.HIDE_GRAB_HELP"),
|
||||
Self::HideUsername => Ok("APP_SETTINGS.HIDE_USERNAME"),
|
||||
|
|
@ -541,6 +547,7 @@ impl SettingType {
|
|||
Self::DefaultOverlayScale => Some("APP_SETTINGS.DEFAULT_OVERLAY_SCALE_HELP"),
|
||||
Self::DoubleCursorFix => Some("APP_SETTINGS.DOUBLE_CURSOR_FIX_HELP"),
|
||||
Self::GridOpacity => Some("APP_SETTINGS.GRID_OPACITY_HELP"),
|
||||
Self::HandsfreeAltTab => Some("APP_SETTINGS.HANDSFREE_ALT_TAB_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"),
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ impl State {
|
|||
}
|
||||
options_dropdown::<wlx_common::config::AltModifier>(par.mp, c, &SettingType::KeyboardMiddleClick)?;
|
||||
options_dropdown::<wlx_common::config::HandsfreePointer>(par.mp, c, &SettingType::HandsfreePointer)?;
|
||||
options_dropdown::<wlx_common::config::HandsfreeAltTab>(par.mp, c, &SettingType::HandsfreeAltTab)?;
|
||||
options_checkbox(par.mp, c, SettingType::FocusFollowsMouseMode)?;
|
||||
options_checkbox(par.mp, c, SettingType::LeftHandedMouse)?;
|
||||
options_checkbox(par.mp, c, SettingType::AllowSliding)?;
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@
|
|||
"TITLE": "Freihändig-Modus",
|
||||
"NONE": "Aus",
|
||||
"HMD": "HMD + Kneifen",
|
||||
"EYE_TRACKING": "Auge + Kneifen",
|
||||
"HMD_ONLY": "Nur HMD",
|
||||
"EYE_ONLY": "Nur Augen"
|
||||
"EYE_TRACKING": "Auge + Kneifen"
|
||||
}
|
||||
},
|
||||
"WATCH": {
|
||||
|
|
@ -136,4 +134,4 @@
|
|||
"WAITING_FOR_USER": "Überprüfen Sie Ihren Desktop auf ein Pop-up zur Bildschirmübertragung.",
|
||||
"FAIL": "Bildschirmübertragungsquelle konnte nicht initialisiert werden."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@
|
|||
"EDIT_MODE_TOGGLE": "Toggle edit mode",
|
||||
"FORCE_CLOSE_APP": "Force close app",
|
||||
"HANDSFREE": {
|
||||
"EYE_ONLY": "Eye only",
|
||||
"EYE_ONLY": "Eye laser",
|
||||
"EYE_TRACKING": "Eye + pinch",
|
||||
"HMD": "HMD + pinch",
|
||||
"HMD_ONLY": "HMD only",
|
||||
"HMD_ONLY": "HMD laser",
|
||||
"NONE": "Off",
|
||||
"TITLE": "Handsfree mode"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@
|
|||
"TITLE": "Modo manos libres",
|
||||
"NONE": "Desactivado",
|
||||
"HMD": "HMD + pellizco",
|
||||
"EYE_TRACKING": "Ojo + pellizco",
|
||||
"HMD_ONLY": "Solo HMD",
|
||||
"EYE_ONLY": "Solo ojos"
|
||||
"EYE_TRACKING": "Ojo + pellizco"
|
||||
}
|
||||
},
|
||||
"WATCH": {
|
||||
|
|
@ -136,4 +134,4 @@
|
|||
"WAITING_FOR_USER": "Revisa tu escritorio para ver la ventana emergente de transmisión de pantalla.",
|
||||
"FAIL": "No se pudo inicializar la fuente de transmisión de pantalla."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@
|
|||
"TITLE": "Modalità a mani libere",
|
||||
"NONE": "Disattivato",
|
||||
"HMD": "HMD + pizzico",
|
||||
"EYE_TRACKING": "Occhio + pizzico",
|
||||
"HMD_ONLY": "Solo HMD",
|
||||
"EYE_ONLY": "Solo occhi"
|
||||
"EYE_TRACKING": "Occhio + pizzico"
|
||||
}
|
||||
},
|
||||
"DEFAULT": "Predefinito",
|
||||
|
|
@ -134,4 +132,4 @@
|
|||
"WAITING_FOR_USER": "Controlla il desktop per un pop-up di condivisione schermo.",
|
||||
"FAIL": "Impossibile inizializzare la sorgente di trasmissione dello schermo."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@
|
|||
"TITLE": "ハンズフリーモード",
|
||||
"NONE": "オフ",
|
||||
"HMD": "HMD + ピンチ",
|
||||
"EYE_TRACKING": "視線 + ピンチ",
|
||||
"HMD_ONLY": "HMDのみ",
|
||||
"EYE_ONLY": "目のみ"
|
||||
"EYE_TRACKING": "視線 + ピンチ"
|
||||
}
|
||||
},
|
||||
"WATCH": {
|
||||
|
|
@ -134,4 +132,4 @@
|
|||
"WAITING_FOR_USER": "デスクトップにスクリーンキャストのポップアップが表示されていないか確認してください。",
|
||||
"FAIL": "スクリーンキャストのソースを初期化できませんでした。"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@
|
|||
"TITLE": "Tryb wolnych rąk",
|
||||
"NONE": "Wyłączone",
|
||||
"HMD": "HMD + uszczypnięcie",
|
||||
"EYE_TRACKING": "Oko + uszczypnięcie",
|
||||
"HMD_ONLY": "Tylko HMD",
|
||||
"EYE_ONLY": "Tylko oczy"
|
||||
"EYE_TRACKING": "Oko + uszczypnięcie"
|
||||
}
|
||||
},
|
||||
"WATCH": {
|
||||
|
|
@ -134,4 +132,4 @@
|
|||
"WAITING_FOR_USER": "Sprawdź na pulpicie powiadomienie o przesyłaniu ekranu.",
|
||||
"FAIL": "Nie udało się zainicjować źródła przesyłania obrazu z ekranu."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@
|
|||
"TITLE": "免提模式",
|
||||
"NONE": "关闭",
|
||||
"HMD": "HMD + 捏合",
|
||||
"EYE_TRACKING": "眼动 + 捏合",
|
||||
"HMD_ONLY": "仅 HMD",
|
||||
"EYE_ONLY": "仅限眼睛"
|
||||
"EYE_TRACKING": "眼动 + 捏合"
|
||||
}
|
||||
},
|
||||
"DEFAULT": "默认",
|
||||
|
|
@ -134,4 +132,4 @@
|
|||
"WAITING_FOR_USER": "请检查桌面上的屏幕投射弹出窗口。",
|
||||
"FAIL": "无法初始化屏幕镜像源。"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ pub struct InputState {
|
|||
pub pointers: [Pointer; 2],
|
||||
pub devices: Vec<TrackedDevice>,
|
||||
pub handsfree_state: PointerState,
|
||||
pub picking_focus: bool,
|
||||
processes: Vec<Child>,
|
||||
}
|
||||
|
||||
|
|
@ -76,6 +77,7 @@ impl InputState {
|
|||
devices: Vec::new(),
|
||||
processes: Vec::new(),
|
||||
handsfree_state: PointerState::default(),
|
||||
picking_focus: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ impl OpenXrInputSource {
|
|||
);
|
||||
}
|
||||
|
||||
pub fn update(&mut self, xr: &XrState, state: &mut AppState) -> anyhow::Result<()> {
|
||||
pub fn update(&mut self, xr: &XrState, app: &mut AppState) -> anyhow::Result<()> {
|
||||
xr.session.sync_actions(&[(&self.action_set).into()])?;
|
||||
|
||||
let loc = xr.view.locate(&xr.stage, xr.predicted_display_time)?;
|
||||
|
|
@ -221,7 +221,7 @@ impl OpenXrInputSource {
|
|||
.location_flags
|
||||
.contains(xr::SpaceLocationFlags::ORIENTATION_VALID)
|
||||
{
|
||||
state.input_state.hmd.matrix3 = hmd.matrix3;
|
||||
app.input_state.hmd.matrix3 = hmd.matrix3;
|
||||
} else {
|
||||
hmd_tracked = false;
|
||||
}
|
||||
|
|
@ -230,26 +230,39 @@ impl OpenXrInputSource {
|
|||
.location_flags
|
||||
.contains(xr::SpaceLocationFlags::POSITION_VALID)
|
||||
{
|
||||
state.input_state.hmd.translation = hmd.translation;
|
||||
app.input_state.hmd.translation = hmd.translation;
|
||||
} else {
|
||||
hmd_tracked = false;
|
||||
}
|
||||
|
||||
let mut any_tracked = false;
|
||||
for i in 0..2 {
|
||||
let pointer = &mut state.input_state.pointers[i];
|
||||
self.pointers[i].update(pointer, xr, &state.session)?;
|
||||
any_tracked |= pointer.tracked;
|
||||
let old_handsfree = app.session.config.handsfree_pointer;
|
||||
|
||||
if app.input_state.picking_focus {
|
||||
app.session.config.handsfree_pointer = app.session.config.handsfree_alt_tab.into();
|
||||
|
||||
let ptr1 = &mut app.input_state.pointers[1];
|
||||
ptr1.before = ptr1.now;
|
||||
ptr1.now = PointerState::default();
|
||||
ptr1.tracked = false
|
||||
} else {
|
||||
for i in 0..2 {
|
||||
let pointer = &mut app.input_state.pointers[i];
|
||||
self.pointers[i].update(pointer, xr, &app.session)?;
|
||||
any_tracked |= pointer.tracked;
|
||||
}
|
||||
}
|
||||
if !any_tracked {
|
||||
self.handsfree_pointer.update_handsfree(
|
||||
&mut state.input_state.pointers[0],
|
||||
&mut app.input_state.pointers[0],
|
||||
xr,
|
||||
&state.session,
|
||||
&app.session,
|
||||
hmd,
|
||||
hmd_tracked,
|
||||
&state.input_state.handsfree_state,
|
||||
&app.input_state.handsfree_state,
|
||||
)?;
|
||||
|
||||
app.session.config.handsfree_pointer = old_handsfree;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -30,8 +30,13 @@ const POLL_TIMEOUT_MS: i32 = 20;
|
|||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum KeyCombo {
|
||||
Super1,
|
||||
Super2,
|
||||
Super3,
|
||||
Super4,
|
||||
AltF4,
|
||||
AltTab,
|
||||
AltShiftTab,
|
||||
/// Always consumed by InputCapture internally
|
||||
CtrlAltDel,
|
||||
}
|
||||
|
|
@ -123,19 +128,10 @@ impl InputCapture {
|
|||
/// Exclusively grabs every currently detected keyboard and mouse.
|
||||
/// Newly connected matching devices are grabbed automatically.
|
||||
pub fn set_grabbed(&self, grabbed: bool) -> anyhow::Result<()> {
|
||||
let (response_tx, response_rx) = mpsc::sync_channel(1);
|
||||
|
||||
self.command_tx
|
||||
.send(Command::SetGrabbed {
|
||||
grabbed,
|
||||
response_tx,
|
||||
})
|
||||
.try_send(Command::SetGrabbed(grabbed))
|
||||
.map_err(|error| anyhow::anyhow!("worker thread unreachable: {error}"))?;
|
||||
|
||||
response_rx
|
||||
.recv()
|
||||
.map_err(|error| anyhow::anyhow!("worker thread unreachable: {error}"))??;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -146,7 +142,7 @@ impl InputCapture {
|
|||
}
|
||||
|
||||
self.command_tx
|
||||
.send(Command::SetPointerAccel { accel, speed })
|
||||
.try_send(Command::SetPointerAccel { accel, speed })
|
||||
.map_err(|error| anyhow::anyhow!("worker thread unreachable: {error}"))?;
|
||||
|
||||
Ok(())
|
||||
|
|
@ -164,14 +160,8 @@ impl Drop for InputCapture {
|
|||
|
||||
enum Command {
|
||||
ResetWatchdog,
|
||||
SetGrabbed {
|
||||
grabbed: bool,
|
||||
response_tx: SyncSender<io::Result<()>>,
|
||||
},
|
||||
SetPointerAccel {
|
||||
accel: bool,
|
||||
speed: f32,
|
||||
},
|
||||
SetGrabbed(bool),
|
||||
SetPointerAccel { accel: bool, speed: f32 },
|
||||
Shutdown,
|
||||
}
|
||||
|
||||
|
|
@ -345,11 +335,8 @@ fn worker_main(
|
|||
'worker: loop {
|
||||
loop {
|
||||
match command_rx.try_recv() {
|
||||
Ok(Command::SetGrabbed {
|
||||
grabbed: requested,
|
||||
response_tx,
|
||||
}) => {
|
||||
let result = if requested {
|
||||
Ok(Command::SetGrabbed(requested)) => {
|
||||
let _ = if requested {
|
||||
match restricted_state.borrow_mut().set_grabbed(true) {
|
||||
Ok(()) => {
|
||||
grabbed = true;
|
||||
|
|
@ -391,8 +378,6 @@ fn worker_main(
|
|||
pointer_accel,
|
||||
&event_tx,
|
||||
);
|
||||
|
||||
let _ = response_tx.send(result);
|
||||
}
|
||||
Ok(Command::SetPointerAccel { accel, speed }) => {
|
||||
pointer_accel = PointerAccelConfig { accel, speed };
|
||||
|
|
@ -542,7 +527,15 @@ fn process_libinput_event(
|
|||
}
|
||||
|
||||
// emit press/release whenever a combo's complete state changes.
|
||||
for combo in [KeyCombo::AltF4, KeyCombo::AltTab] {
|
||||
for combo in [
|
||||
KeyCombo::AltF4,
|
||||
KeyCombo::AltShiftTab,
|
||||
KeyCombo::AltTab,
|
||||
KeyCombo::Super1,
|
||||
KeyCombo::Super2,
|
||||
KeyCombo::Super3,
|
||||
KeyCombo::Super4,
|
||||
] {
|
||||
let combo_pressed = key_combo_is_pressed(combo, &state.pressed_keys);
|
||||
let was_pressed = state.active_combos.contains(&combo);
|
||||
|
||||
|
|
@ -840,10 +833,21 @@ fn key_combo_is_pressed(combo: KeyCombo, pressed: &HashSet<u16>) -> bool {
|
|||
let ctrl =
|
||||
pressed.contains(&KeyCode::KEY_LEFTCTRL.0) || pressed.contains(&KeyCode::KEY_RIGHTCTRL.0);
|
||||
|
||||
let meta =
|
||||
pressed.contains(&KeyCode::KEY_LEFTMETA.0) || pressed.contains(&KeyCode::KEY_RIGHTMETA.0);
|
||||
|
||||
let shift =
|
||||
pressed.contains(&KeyCode::KEY_LEFTSHIFT.0) || pressed.contains(&KeyCode::KEY_RIGHTSHIFT.0);
|
||||
|
||||
match combo {
|
||||
KeyCombo::AltF4 => alt && pressed.contains(&KeyCode::KEY_F4.0),
|
||||
KeyCombo::AltShiftTab => alt && shift && pressed.contains(&KeyCode::KEY_TAB.0),
|
||||
KeyCombo::AltTab => alt && pressed.contains(&KeyCode::KEY_TAB.0),
|
||||
KeyCombo::CtrlAltDel => ctrl && alt && pressed.contains(&KeyCode::KEY_DELETE.0),
|
||||
KeyCombo::Super1 => meta && pressed.contains(&KeyCode::KEY_1.0),
|
||||
KeyCombo::Super2 => meta && pressed.contains(&KeyCode::KEY_2.0),
|
||||
KeyCombo::Super3 => meta && pressed.contains(&KeyCode::KEY_3.0),
|
||||
KeyCombo::Super4 => meta && pressed.contains(&KeyCode::KEY_4.0),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ use xkbcommon::xkb;
|
|||
|
||||
use crate::{
|
||||
backend::{
|
||||
input::InputState,
|
||||
task::{OverlayTask, SpawnPos, TaskContainer, TaskType, ToggleMode},
|
||||
wayvr::{
|
||||
image_importer::ImageImporter,
|
||||
|
|
@ -636,7 +637,7 @@ impl WvrServerState {
|
|||
wvr_server.manager.cleanup_handles();
|
||||
}
|
||||
|
||||
wvr_server.process_input_capture();
|
||||
wvr_server.process_input_capture(&mut app.input_state, &mut app.tasks);
|
||||
|
||||
wvr_server.ticks += 1;
|
||||
|
||||
|
|
@ -747,7 +748,11 @@ impl WvrServerState {
|
|||
self.manager.seat_pointer.is_grabbed()
|
||||
}
|
||||
|
||||
pub fn process_input_capture(&mut self) {
|
||||
pub fn process_input_capture(
|
||||
&mut self,
|
||||
input_state: &mut InputState,
|
||||
tasks: &mut TaskContainer,
|
||||
) {
|
||||
if !self.has_input_focus {
|
||||
return;
|
||||
}
|
||||
|
|
@ -803,7 +808,22 @@ impl WvrServerState {
|
|||
self.close_window(window_handle);
|
||||
}
|
||||
}
|
||||
input_capture::KeyCombo::AltTab => self.alt_tab(pressed),
|
||||
input_capture::KeyCombo::AltTab => input_state.picking_focus = pressed,
|
||||
input_capture::KeyCombo::AltShiftTab => {
|
||||
input_state.handsfree_state.grab = pressed
|
||||
}
|
||||
input_capture::KeyCombo::Super1 => {
|
||||
tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleSet(0)))
|
||||
}
|
||||
input_capture::KeyCombo::Super2 => {
|
||||
tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleSet(1)))
|
||||
}
|
||||
input_capture::KeyCombo::Super3 => {
|
||||
tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleSet(2)))
|
||||
}
|
||||
input_capture::KeyCombo::Super4 => {
|
||||
tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleSet(3)))
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
|
|
@ -852,15 +872,6 @@ impl WvrServerState {
|
|||
}
|
||||
}
|
||||
|
||||
fn alt_tab(&mut self, pressed: bool) {
|
||||
let mut windows: Vec<_> = self.wm.windows.iter().collect();
|
||||
if windows.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO
|
||||
}
|
||||
|
||||
fn button_to_mouse_index(button: u32) -> Option<MouseIndex> {
|
||||
match button {
|
||||
272 => Some(MouseIndex::Left),
|
||||
|
|
@ -877,7 +888,7 @@ impl WvrServerState {
|
|||
|
||||
let res = input_capture
|
||||
.set_grabbed(has_focus)
|
||||
.log_err("Could not grab input.");
|
||||
.log_err("Could not set input grab");
|
||||
|
||||
if res.is_ok() && !self.grab_toast_sent {
|
||||
self.grab_toast_sent = true;
|
||||
|
|
@ -971,6 +982,7 @@ impl WvrServerState {
|
|||
target: PointerFocusTarget,
|
||||
global_pos: Vec2,
|
||||
hover_window: window::WindowHandle,
|
||||
force_focus: bool,
|
||||
) {
|
||||
if self.mouse_freeze > Instant::now() {
|
||||
return;
|
||||
|
|
@ -978,7 +990,17 @@ impl WvrServerState {
|
|||
|
||||
let global_pos = DVec2::from(global_pos);
|
||||
|
||||
let (focus, _) = self.get_mouse_focus(target, hover_window, false);
|
||||
let (focus, focus_keyboard) = self.get_mouse_focus(target, hover_window, force_focus);
|
||||
if focus_keyboard.is_some() {
|
||||
self.manager.seat_keyboard.set_focus(
|
||||
&mut self.manager.state,
|
||||
focus_keyboard,
|
||||
self.manager.serial_counter.next_serial(),
|
||||
);
|
||||
|
||||
self.wm.keyboard_focus = Some(hover_window);
|
||||
}
|
||||
|
||||
let linear_delta = self.get_mouse_relative(global_pos, hover_window);
|
||||
self.manager
|
||||
.send_mouse_move(focus, global_pos, linear_delta, linear_delta);
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ use wayvr_ipc::packet_client::WvrProcessLaunchParams;
|
|||
use wlx_common::{
|
||||
astr_containers::AStrMap,
|
||||
config::{
|
||||
AltModifier, CaptureMethod, ChromaKeyParams, GeneralConfig, HandsfreePointer,
|
||||
InputEmulationMethod, SerializedWindowSet, SerializedWindowStates,
|
||||
AltModifier, CaptureMethod, ChromaKeyParams, GeneralConfig, HandsfreeAltTab,
|
||||
HandsfreePointer, InputEmulationMethod, SerializedWindowSet, SerializedWindowStates,
|
||||
},
|
||||
config_io,
|
||||
locale::Language,
|
||||
|
|
@ -180,6 +180,7 @@ pub struct AutoSettings {
|
|||
pub keyboard_middle_click_mode: AltModifier,
|
||||
pub autostart_apps: Vec<WvrProcessLaunchParams>,
|
||||
pub handsfree_pointer: HandsfreePointer,
|
||||
pub handsfree_alt_tab: HandsfreeAltTab,
|
||||
pub language: Option<Language>,
|
||||
pub chroma_key_params: ChromaKeyParams,
|
||||
pub input_emulation_method: InputEmulationMethod,
|
||||
|
|
@ -248,6 +249,7 @@ pub fn save_settings(config: &GeneralConfig) -> anyhow::Result<()> {
|
|||
keyboard_middle_click_mode: config.keyboard_middle_click_mode,
|
||||
autostart_apps: config.autostart_apps.clone(),
|
||||
handsfree_pointer: config.handsfree_pointer,
|
||||
handsfree_alt_tab: config.handsfree_alt_tab,
|
||||
language: config.language,
|
||||
chroma_key_params: config.chroma_key_params.clone(),
|
||||
input_emulation_method: config.input_emulation_method,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ use crate::{
|
|||
},
|
||||
overlays::screen::capture::MyFirstDmaExporter,
|
||||
state::AppState,
|
||||
subsystem::hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT, WheelDelta},
|
||||
subsystem::{
|
||||
hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT, WheelDelta},
|
||||
input::InputFocus,
|
||||
},
|
||||
windowing::backend::{
|
||||
FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender, ui_transform,
|
||||
},
|
||||
|
|
@ -298,6 +301,12 @@ impl OverlayBackend for ScreenBackend {
|
|||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> HoverResult {
|
||||
#[cfg(debug_assertions)]
|
||||
log::trace!("Hover: {:?}", hit.uv);
|
||||
|
||||
if app.input_state.picking_focus {
|
||||
app.hid_provider
|
||||
.set_input_focus(app.wvr_server.as_mut(), InputFocus::PhysicalScreen);
|
||||
}
|
||||
|
||||
if can_move()
|
||||
&& (!app.session.config.focus_follows_mouse_mode
|
||||
|| app.input_state.pointers[hit.pointer].now.move_mouse)
|
||||
|
|
|
|||
|
|
@ -845,11 +845,17 @@ impl OverlayBackend for WvrWindowBackend {
|
|||
self.panel_hovered = false;
|
||||
}
|
||||
|
||||
if app.input_state.picking_focus {
|
||||
app.hid_provider
|
||||
.set_input_focus(app.wvr_server.as_mut(), InputFocus::WayVR);
|
||||
}
|
||||
|
||||
let wvr_server = app.wvr_server.as_mut().unwrap();
|
||||
wvr_server.send_mouse_move(
|
||||
PointerFocusTarget::Surface { surface, origin },
|
||||
global_pos,
|
||||
self.window,
|
||||
app.input_state.picking_focus,
|
||||
);
|
||||
|
||||
HoverResult::consume()
|
||||
|
|
@ -860,8 +866,18 @@ impl OverlayBackend for WvrWindowBackend {
|
|||
self.panel_hovered = false;
|
||||
}
|
||||
|
||||
if app.input_state.picking_focus {
|
||||
app.hid_provider
|
||||
.set_input_focus(app.wvr_server.as_mut(), InputFocus::WayVR);
|
||||
}
|
||||
|
||||
let wvr_server = app.wvr_server.as_mut().unwrap();
|
||||
wvr_server.send_mouse_move(PointerFocusTarget::Toplevel, pos, self.window);
|
||||
wvr_server.send_mouse_move(
|
||||
PointerFocusTarget::Toplevel,
|
||||
pos,
|
||||
self.window,
|
||||
app.input_state.picking_focus,
|
||||
);
|
||||
|
||||
HoverResult::consume()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,24 @@ pub enum HandsfreePointer {
|
|||
EyeTrackingOnly,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumString, EnumProperty, VariantArray)]
|
||||
pub enum HandsfreeAltTab {
|
||||
#[strum(props(Translation = "APP_SETTINGS.OPTION.HMD_ONLY"))]
|
||||
#[default]
|
||||
Hmd,
|
||||
#[strum(props(Translation = "APP_SETTINGS.OPTION.EYE_ONLY"))]
|
||||
EyeTracking,
|
||||
}
|
||||
|
||||
impl From<HandsfreeAltTab> for HandsfreePointer {
|
||||
fn from(value: HandsfreeAltTab) -> Self {
|
||||
match value {
|
||||
HandsfreeAltTab::Hmd => HandsfreePointer::HmdOnly,
|
||||
HandsfreeAltTab::EyeTracking => HandsfreePointer::EyeTrackingOnly,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct ChromaKeyParams {
|
||||
pub hsv_min: [f32; 3],
|
||||
|
|
@ -449,6 +467,9 @@ pub struct GeneralConfig {
|
|||
#[serde(default)]
|
||||
pub handsfree_pointer: HandsfreePointer,
|
||||
|
||||
#[serde(default)]
|
||||
pub handsfree_alt_tab: HandsfreeAltTab,
|
||||
|
||||
#[serde(default = "def_one")]
|
||||
pub grid_opacity: f32,
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue