diff --git a/docs/README/FT_POINTER.md b/docs/README/FT_POINTER.md new file mode 100644 index 0000000..0951d0d --- /dev/null +++ b/docs/README/FT_POINTER.md @@ -0,0 +1,23 @@ +# FT_POINTER + +Script / module: `pointer/helper/ft-pointer.cpp` (user service via `pointer/helper/run.sh`) + +## Purpose + +3D pointer helper for SteamVR overlays: laser hit-testing, drag lock, SteamVR Settings workaround, `POINTER_IGNORE`, and placement helpers used by layout. + +## Floating panels + +`FramePanel()` treats `frametop.screen.N`, `frametop.float.N`, and `frametop.float.N.sub.K` as desktop panels the laser can retarget across while a press is held and the pressed overlay has not moved. Left release sends `up` to `@ft_screens` as a backstop for the catcher. `POINTER_IGNORE` still cannot drop any `frametop.*` key (Phase 2 hard guard). + +## Related + +[FT_FLOATD.md](FT_FLOATD.md), [INPUT-RELAY.md](INPUT-RELAY.md), `docs/floating-windows.md`. + +## Tests + +``` +python3 test/test_pointer_ignore.py +python3 test/test_float_phase3.py +bash test/test_steamvr_client_init.sh +``` diff --git a/docs/README/INPUT-RELAY.md b/docs/README/INPUT-RELAY.md index ffeacc2..d1918f6 100644 --- a/docs/README/INPUT-RELAY.md +++ b/docs/README/INPUT-RELAY.md @@ -28,11 +28,16 @@ The desktop's input method ([FT_TEXTINPUT.md](FT_TEXTINPUT.md)) sends `textfield `keyboard_toggle` ("Open/close keyboard") is a new action, before `key` in `ACTIONS`, for mouse buttons and Frame controller buttons. Both paths go through `do_action`, which sends `vrkeyboard toggle` on a press (unless the mode is `never`) and hands every other action to `Pointer.action`. A keyboard made by a program through uinput (frame-voice's, say) doesn't count as "connected": `probe` marks a node `uinput` when its sysfs path is under `/sys/devices/virtual/input/`, `Node.describe()` reports it, and the `no_keyboard` check skips it (as it does keyboards set to Ignore or Pointer). +## Floating windows + +`float_toggle` and `dock_all` send `float pointer` / `dock all` to ft-floatd on `@frametop_float` (they work even when pointer mode is off). A rules file without `key_bindings` gets `DEFAULT_KEY_BINDINGS`: Meta+Shift+F (`42+125+33`) → `float_toggle`. A file that defines its own `key_bindings` object, even `{}`, does not get that default. Combinations are taken on passthrough keyboards before the key is typed; Meta is swallowed on the desktop for the combo so Plasma's launcher does not open. This fork does not ship gaze key bindings. + ## Tests ``` python3 test/test_input_relay_control.py # needs Linux/WSL abstract AF_UNIX python3 test/test_vr_keyboard_relay.py # modes, persist, uinput detection, keyboard_toggle +python3 test/test_float_phase3.py # float wiring, Meta+Shift+F, crop math bash test/test_boot_safety.sh bash test/test_steamvr_client_init.sh ``` diff --git a/docs/README/OVERVIEW.md b/docs/README/OVERVIEW.md index 2455429..414377c 100644 --- a/docs/README/OVERVIEW.md +++ b/docs/README/OVERVIEW.md @@ -16,7 +16,12 @@ Frametop tools and docs for the Steam Frame nested desktop. | `layout/ft_layout.py` | [FT_LAYOUT.md](FT_LAYOUT.md) | | `session/ft-launch.py` | [FT-LAUNCH.md](FT-LAUNCH.md) | | `layout/ft_desktop.py` | [FT_DESKTOP.md](FT_DESKTOP.md) | +| `input/input-relay.py` | [INPUT-RELAY.md](INPUT-RELAY.md) | | `input/ft-textinput` | [FT_TEXTINPUT.md](FT_TEXTINPUT.md) | +| `pointer/helper/ft-pointer.cpp` | [FT_POINTER.md](FT_POINTER.md) | | `screens/keyboard.cpp` | [SCREENS_KEYBOARD.md](SCREENS_KEYBOARD.md) | +| `screens/test/headless.sh` | [SCREENS_TEST_HEADLESS.md](SCREENS_TEST_HEADLESS.md) | +| `float/ft_floatd.py` | [FT_FLOATD.md](FT_FLOATD.md) | +| `float/ft_apps.py` | [FT_APPS.md](FT_APPS.md) | -Layout / Spatial Instruments CLI and profile format live in `docs/reference.md` (and `docs/design.md`). `ft-layout apply` still pushes visibility, KWin scales, and instruments when the HMD pose is not ready yet (see [FT_LAYOUT.md](FT_LAYOUT.md)). Display Settings → **Background** uses `frame-background`; recover-vr also clears a broken empty `steamvr-pending.path` that can black-screen SteamVR after the boot logo. +Layout / Spatial Instruments CLI and profile format live in `docs/reference.md` (and `docs/design.md`). `ft-layout apply` still pushes visibility, KWin scales, and instruments when the HMD pose is not ready yet (see [FT_LAYOUT.md](FT_LAYOUT.md)). Display Settings → **Background** uses `frame-background`; recover-vr also clears a broken empty `steamvr-pending.path` that can black-screen SteamVR after the boot logo. Launcher Configure writes/removes apps in-process in Display Settings (then host-syncs VR) so remove and the “application not available” warning stay reliable inside distrobox — see [FT_DISPLAY_SETTINGS.md](FT_DISPLAY_SETTINGS.md). SteamVR overlay clients (ft-pointer, ft-screens, ft-gaze) probe as Background before Overlay and use `Requisite=steamvr.service` so they cannot bootstrap a rogue vrserver; see `docs/design.md`. Floating windows use spare KWin outputs (`FLOAT_SLOTS`), `ft-floatd`, and `frametop.float.N` panels — see [FT_FLOATD.md](FT_FLOATD.md) and `docs/floating-windows.md`. diff --git a/input-settings/ft_input_settings.py b/input-settings/ft_input_settings.py index 676dfa5..9108f62 100644 --- a/input-settings/ft_input_settings.py +++ b/input-settings/ft_input_settings.py @@ -63,6 +63,7 @@ ACTION_LABELS = { "sens_up": "Faster pointer", "sens_down": "Slower pointer", "layout_reset": "Reset desktop screen layout", "screens_toggle": "Hide/show desktop screens", "keyboard_toggle": "Open/close keyboard", + "float_toggle": "Float/dock window", "dock_all": "Dock all floating windows", "profile_slot_1": "Apply profile slot 1", "profile_slot_2": "Apply profile slot 2", "profile_slot_3": "Apply profile slot 3", "profile_slot_4": "Apply profile slot 4", "profile_slot_5": "Apply profile slot 5", "profile_slot_6": "Apply profile slot 6", diff --git a/input/input-relay.py b/input/input-relay.py index 839bc62..cff0153 100755 --- a/input/input-relay.py +++ b/input/input-relay.py @@ -23,7 +23,9 @@ pointer_toggle, follow_toggle = head follow on or off, gaze_toggle = gaze mode o (the pointer goes where you look; see pointer/helper/ft-pointer.cpp), sens_up, sens_down, layout_reset = put the desktop screens back in their saved layout, screens_toggle = hide or show the desktop screens, profile_slot_1..6 / profile_next / profile_previous = apply named profile -slots via ft-layout, keyboard_toggle = open or close Frametop's keyboard, key = pass through as a +slots via ft-layout, keyboard_toggle = open or close Frametop's keyboard, float_toggle = float the +desktop window under the pointer (else the active one) in VR or dock it if it floats, dock_all = +put every floating window back (both go to ft-floatd on @frametop_float), key = pass through as a key, none). Frame controller buttons can be mapped too ("controller_buttons": {"right/a": action} in the @@ -173,7 +175,8 @@ RULES_PATH = os.path.expanduser("~/.config/frametop-input.json") ACTIONS = ("left", "right", "middle", "back", "scroll_up", "scroll_down", "dashboard", "recenter", "pointer_toggle", "follow_toggle", "gaze_toggle", "sens_up", "sens_down", "layout_reset", "screens_toggle", "profile_slot_1", "profile_slot_2", "profile_slot_3", "profile_slot_4", "profile_slot_5", - "profile_slot_6", "profile_next", "profile_previous", "keyboard_toggle", "key", "none") + "profile_slot_6", "profile_next", "profile_previous", "keyboard_toggle", "float_toggle", "dock_all", + "key", "none") VR_KEYBOARD_MODES = ("always", "no_keyboard", "button", "never") # when Frametop's keyboard opens HELPER = "\0ft_pointer_helper" # Frame controller buttons the pointer helper can read (pointer/helper/vrbuttons.h). @@ -182,6 +185,24 @@ VR_BUTTONS = ("left/view", "left/dpad_up", "left/dpad_down", "left/dpad_left", " "right/bumper", "right/trigger", "right/grip", "right/thumbstick") VR_DEVICE = "frame_controller" # the id controller buttons have in watch events SCREENS = "\0ft_screens" +FLOAT = "\0frametop_float" # ft-floatd; floating windows in the Frametop desktop +# Actions for ft-floatd: work even when pointer mode is off. +FLOAT_ACTIONS = {"float_toggle": b"float pointer", "dock_all": b"dock all"} +# Key combinations a rules file without "key_bindings" gets. Meta+Shift+F floats/docks +# a window (free on the Frametop desktop; apps rarely use Meta+Shift+F). Gaze shortcuts +# are not included — this fork keeps attention opacity without gaze mode. +DEFAULT_KEY_BINDINGS = {"42+125+33": "float_toggle"} # Shift+Meta+F +KEY_F24 = 194 # sent to the desktop with a Meta combination (see key_binding) +# Key combinations ("key_bindings"): modifiers, each side's code folded into the left one's. +MODIFIERS = {29: 29, 97: 29, 42: 42, 54: 42, 56: 56, 100: 56, 125: 125, 126: 125} + + +def known_action(a): + return a in ACTIONS + + +def needs_pointer(a): + return a not in FLOAT_ACTIONS KEYS = "\0frametop_keys" # keys of keyboards grabbed for the desktop, for other readers FT_LAYOUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "layout", "ft-layout") DEFAULT_BUTTONS = {BTN_LEFT: "left", BTN_RIGHT: "right", BTN_MIDDLE: "middle", @@ -292,7 +313,12 @@ def read_config(path=os.path.expanduser("~/.config/frametop.conf")): def read_rules(path=RULES_PATH): """{"devices": {id: {"role", "name"}}, "buttons": {id: {"": action}}, "controller_buttons": {"/