diff --git a/Cargo.lock b/Cargo.lock index 530e1a55..679b115c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5047,13 +5047,16 @@ name = "openlogi-cli" version = "0.6.22" dependencies = [ "anyhow", + "async-hid", "clap", + "futures-lite", "openlogi-assets", "openlogi-core", "openlogi-hid", "tokio", "tracing", "tracing-subscriber", + "windows-sys 0.61.2", ] [[package]] @@ -5095,6 +5098,7 @@ dependencies = [ "openlogi-core", "openlogi-hid", "openlogi-hook", + "raw-window-handle", "rust-i18n", "serde", "serde_json", @@ -5108,6 +5112,7 @@ dependencies = [ "ureq", "url", "walkdir", + "windows-sys 0.61.2", ] [[package]] diff --git a/HANDOFF-WINDOWS-ACTION-RING.md b/HANDOFF-WINDOWS-ACTION-RING.md new file mode 100644 index 00000000..62616dfd --- /dev/null +++ b/HANDOFF-WINDOWS-ACTION-RING.md @@ -0,0 +1,290 @@ +# Handoff — OpenLogi with MX Master 4 Action Ring (Windows) + +**Read this first if you are an agent setting this up on a second Windows PC.** +Everything needed is here: what this fork is, how to build it, how to install it +so it stays installed, how to configure the Action Ring, and the specific traps +that cost the first machine several hours. Follow it top to bottom. + +--- + +## 1. What this is + +Upstream [OpenLogi](https://github.com/AprilNEA/OpenLogi) is a native, local-first +replacement for Logitech Options+ (Rust; no account, no telemetry, plain-TOML +config). It did **not** support the MX Master 4's **Action Ring** — the haptic +force-pad on the thumb rest, marked with eight dots. + +This fork adds that, Windows-first: + +| Capability | Detail | +|---|---| +| Pad capture | The pad speaks only HID++ and emits no native HID events. The agent arms it (`0x19c0` force threshold `0x15a3` + `0x1b04` analytics reporting) and decodes its press events. | +| On-screen ring | Tap the pad → a ring of eight circles appears at the cursor. Aim and tap again (or click) to fire. Centre ✕ / `Esc` / click-outside cancels. | +| Ring folders | A slot can hold a sub-ring; firing it swaps the ring in place, centre becomes ← to go back. One level deep. | +| Full editor | In-app page: the ring drawn large with labelled slots, a live action panel, folder drill-in. | +| Rich actions | `Run` (URL / file / program, `||` for args, `%VAR%` expansion), `PasteText` (typed as Unicode, no clipboard clobber), `CustomShortcut` (record by pressing the keys), `Named` (your own label for any action). | +| Side buttons | Back/Forward on the MX Master 4 emit **no** native HID either — this fork diverts and dispatches them, so browser back/forward finally work. | + +Everything is also available on the gesture button and plain buttons (e.g. the +DPI toggle), not just the ring. + +**Licensing:** upstream is dual MIT/Apache-2.0 — fine to use and modify. The +`design/` brand assets are **proprietary**; keep this mirror private and do not +redistribute those publicly. + +**Upstream status:** this work is proposed upstream as +[PR #436](https://github.com/AprilNEA/OpenLogi/pull/436). Until/unless it merges, +this fork is the only build with the ring. + +--- + +## 2. Prerequisites (target machine) + +- **Windows 10/11**, MX Master 4 paired via a **Logi Bolt receiver** (this is the + verified path; Bluetooth-direct is untested for the ring). +- **Rust** with the **GNU** toolchain. MSVC also works *if* Visual Studio Build + Tools are installed; the source machine had no VS, so it used GNU: + ```bash + rustup toolchain install stable-x86_64-pc-windows-gnu + ``` +- **Git**. +- **`fxc.exe`** (DirectX shader compiler) — **only for release builds**. GPUI + precompiles HLSL in release. If the Windows SDK is not installed, extract it + from the `Microsoft.Windows.SDK.CPP` NuGet package (it lives at + `c\bin\\x64\fxc.exe`) and set `GPUI_FXC_PATH` to it. Debug builds compile + shaders at runtime and do not need it. + +> **Toolchain trap.** The repo's `rust-toolchain.toml` says `channel = "stable"`, +> which resolves to the host default (often MSVC). On a machine without VS this +> fails with `linker link.exe not found` — and confusingly, plain `cargo build` +> may work while `cargo clippy` fails, because one is a direct binary and the +> other goes through the rustup shim. **Pin every cargo command explicitly:** +> ```bash +> rustup run stable-x86_64-pc-windows-gnu cargo ... +> ``` + +--- + +## 3. Get the code + +Private Forgejo (same LAN / Tailscale): + +| Route | URL | +|---|---| +| LAN | `http://10.0.0.140:3000/ultradaoto/openlogi.git` | +| Tailscale | `http://forgejo-lxc.tailb56dd.ts.net:3000/ultradaoto/openlogi.git` | + +```bash +git clone http://10.0.0.140:3000/ultradaoto/openlogi.git +cd openlogi +git checkout feat/haptic-sense-panel # <-- the ring lives here, NOT on master +``` + +Authenticate with a **Forgejo personal access token** (Settings → Applications → +Generate Token, scope `read:repository` is enough to clone). Use the token as the +password: + +```bash +git clone http://:@10.0.0.140:3000/ultradaoto/openlogi.git +``` + +`master` on this mirror tracks upstream; **`feat/haptic-sense-panel` is the branch +you want.** + +--- + +## 4. Build + +```bash +# from the repo root +$env:GPUI_FXC_PATH = 'C:\path\to\fxc.exe' # release builds only +rustup run stable-x86_64-pc-windows-gnu cargo build --release -p openlogi-agent -p openlogi-gui +``` + +Two binaries land in `target\release\`: + +- `openlogi-agent.exe` — background service: owns the input hook and **all** + device I/O. +- `openlogi-gui.exe` — the app window; a pure IPC client. It **spawns the agent + itself**, so you normally launch only the GUI. + +Optional sanity gate (matches CI): + +```bash +rustup run stable-x86_64-pc-windows-gnu cargo clippy --workspace --all-targets -- -D warnings +rustup run stable-x86_64-pc-windows-gnu cargo test --workspace +``` + +--- + +## 5. Install — and why it matters + +> ### ⚠️ The single worst trap: two OpenLogis on one machine +> If an official OpenLogi is already installed (MSI / winget), you now have two +> builds. Launching the **old** one from the Start menu starts an old agent that +> cannot parse the ring bindings, **falls back to defaults, and saves those +> defaults over `config.toml` — wiping every binding.** On the source machine +> this silently destroyed a fully configured ring. +> +> This fork now guards against it (config `schema_version` 4, and a build that +> cannot read the config refuses to save over it), but an *older* binary predates +> that guard. **Have exactly one OpenLogi on the machine.** + +**Do this:** if an official OpenLogi is installed, either uninstall it, or +overwrite its binaries so every launch path runs this build: + +```powershell +$dst = "$env:LOCALAPPDATA\Programs\OpenLogi" # default install location +Stop-Process -Name OpenLogi, openlogi-gui, openlogi-agent -Force -ErrorAction SilentlyContinue +Copy-Item .\target\release\openlogi-gui.exe "$dst\OpenLogi.exe" -Force +Copy-Item .\target\release\openlogi-agent.exe "$dst\openlogi-agent.exe" -Force +``` + +If OpenLogi was never installed, create that folder and copy both binaries in +(rename the GUI to `OpenLogi.exe`), then make a Start-menu shortcut to it. + +**Autostart** (one entry, GUI only — it starts the agent): + +```powershell +Set-ItemProperty -Path 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run' ` + -Name 'OpenLogi' -Value "`"$env:LOCALAPPDATA\Programs\OpenLogi\OpenLogi.exe`" --background" +``` + +`--background` starts it resident without opening a window. Do **not** add a +second Run entry for the agent — two agents means two input hooks. + +**Also uninstall Logi Options+ if present.** It re-arms the same pad and fights +for the device. Its updater service resurrects the app, so disabling is not +enough — uninstall it: +`"C:\Program Files\LogiOptionsPlus\logioptionsplus_updater.exe" --uninstall --full --shadow` +(elevated). G HUB is a separate stack and can stay. + +--- + +## 6. Configure the Action Ring + +Config lives at **`%USERPROFILE%\.config\openlogi\config.toml`** (plain TOML; +edit it with the app closed, or use the in-app editor). + +### 6a. Find the device key — do not copy the source machine's + +Every device is keyed by its **physical** identity, e.g. +`receiver:97b76948a846c55a:slot:2`. That receiver UID is unique to the source +machine's Bolt receiver. **Yours will differ.** + +Run the app once (it writes an identity block for every device it sees), then: + +```powershell +Select-String -Path "$env:USERPROFILE\.config\openlogi\config.toml" -Pattern '^\[devices\.' | + ForEach-Object { $_.Line } +``` + +Use the key whose `identity.display_name` is `MX Master 4`. Substitute it +everywhere `receiver:97b76948a846c55a:slot:2` appears below. + +### 6b. The ring layout + +A ready-to-adapt example is in **[`docs/action-ring-example.toml`](docs/action-ring-example.toml)** — +copy the `ActionRing` sections into your config under your own device key. + +Slots are compass-named clockwise from the top: `North`, `NorthEast`, `East`, +`SouthEast`, `South`, `SouthWest`, `West`, `NorthWest`. + +Shape of each action: + +```toml +North = "PlayPause" # built-in action +East = { Run = "https://chatgpt.com/" } # URL, file, or program +South = { Run = 'C:\Tools\app.exe||--flag value' } # || separates arguments +West = { PasteText = "text typed at the cursor" } + +[devices."".bindings.ActionRing.NorthWest.CustomShortcut] +modifiers = 4 # bitmask: 1=Cmd 2=Shift 4=Ctrl 8=Alt 16=Win +key_code = 49 # macOS kVK code (49 = Space) — see below +display = "Ctrl+Space" + +# A folder = a nested ring (one level deep) +[devices."".bindings.ActionRing.NorthEast.Folder.North] +PasteText = "first item in the sub-ring" +``` + +**Don't hand-write `CustomShortcut`.** Use the app: ring editor → slot → +**Keyboard Shortcut…** → **Press Keys**, then physically press the chord and +release. It records and saves in one motion, including chords another app has +claimed globally. (`key_code` is a macOS virtual-key code because that is the +cross-platform storage format; the recorder handles the translation.) + +**Naming:** any action takes an optional label shown on the ring instead of the +raw payload (`{ Named = { name = "Dictation", action = { ... } } }`). The dialog's +**Name** field writes this. + +### 6c. Using it + +- **Tap the pad** → ring opens at the cursor. +- **Move toward a slot, tap again** (or click it) → fires. +- **Folder slot** → ring swaps to its contents; centre becomes ← . +- **Cancel** → centre ✕, `Esc`, or click outside. +- **Edit** → open the app → device → Buttons → click the ring hotspot or its + "8 actions" card → full editor page. + +--- + +## 7. Traps and troubleshooting + +| Symptom | Cause / fix | +|---|---| +| **Ring bindings reverted to defaults on their own** | An older OpenLogi build ran and overwrote the config. See §5 — remove the second install. Restore from a backup (`config.toml.bak-*`). | +| **Pad stops responding entirely** | The pad's analytics reporting can wedge in device RAM after repeated arm/kill cycles (dev churn). **Power-cycle the mouse** (switch off, on). This is device-side; restarting software will not clear it. | +| **Ring doesn't open, but the app runs** | Check the agent armed it. Launch with `OPENLOGI_LOG='warn,openlogi_hid=info'` and look for `control capture active ... action_ring=true`. | +| **Every mouse click opens the ring** | Only CID `0x01a0` may be armed. CIDs `0x0050`/`0x0051` are **left/right click telemetry** — arming those makes every click a pad press. (Fixed here; noted in case anyone edits the arming code.) | +| **Mouse pointer jerky / skipping after hours** | Was caused by a caching bug: devices whose pairing register reports an all-zero `unit_id` were re-probed *every tick* — a full 46-feature HID++ walk every ~2 s over the mouse's own radio link. Fixed on this branch. If it recurs, power-cycle the mouse and report it. | +| **Huge log file** | Don't run with bare `OPENLOGI_LOG=info` long-term — tarpc logs every IPC call (~200 MB in days). Use `OPENLOGI_LOG='warn,openlogi_hid=info'`. | +| **Device takes minutes to appear** | First feature walk on the Windows BLE stack takes 1–3 s; the probe budget is 3 s. Should be fine now; if a device never appears, that budget is the place to look. | +| **`cargo clippy` fails with `link.exe not found`** | Toolchain trap — see §2, pin to `stable-x86_64-pc-windows-gnu`. | +| **Release build panics "Failed to find fxc.exe"** | Set `GPUI_FXC_PATH` — see §2. | + +--- + +## 8. Architecture orientation (for the agent) + +Three tiers, one install. The **GUI is a pure IPC client**; the **agent** owns the +input hook and all device I/O. + +| Crate | Role in this feature | +|---|---| +| `openlogi-hid` | `gesture.rs` arms the pad and decodes its events; `inventory/` enumerates devices and caches probes. | +| `openlogi-core` | `binding.rs` — the `Action` catalog, `RingSlot`, `Binding::Ring`; `config.rs` — TOML schema (**v4**). | +| `openlogi-agent-core` | tarpc IPC contract (`ipc.rs`, **PROTOCOL_VERSION 14**) — append-only wire format. | +| `openlogi-gui` | `ring.rs` = the overlay window; `mouse_model/ring_editor.rs` = the editor page; `windows/ring_action_editor.rs` = the payload dialog; `chord_recorder.rs` = key recording. | +| `openlogi-inject` | Synthesizes actions (`SendInput`, `ShellExecuteW`). | + +**Two rules that will bite you:** + +1. **The IPC wire format is append-only.** bincode encodes variant *indices* and + tarpc encodes *method order*. Never reorder or insert — only append — and bump + `PROTOCOL_VERSION` plus the golden tests in + `crates/openlogi-agent-core/tests/wire_format.rs`. +2. **Bump `SCHEMA_VERSION` whenever you write config an older build can't + represent.** That gate is the only thing standing between a downgrade and a + wiped config. + +Also worth knowing: synthesized keyboard chords **must dwell** (~120 ms held). +Apps that detect a global hotkey by *polling* key state — common for chords like +`Ctrl+Space` — never see an instantaneous press. `openlogi-inject` holds chords +for this reason; don't "optimize" it away. + +Repo conventions live in `AGENTS.md` (+ `.claude/rules/`): conventional commits, +no AI attribution, i18n strings added to **all 20 locales** at the same position. + +--- + +## 9. Quick checklist + +1. [ ] Rust GNU toolchain installed; `fxc.exe` available; `GPUI_FXC_PATH` set. +2. [ ] Cloned from Forgejo, **on branch `feat/haptic-sense-panel`**. +3. [ ] `cargo build --release -p openlogi-agent -p openlogi-gui` (pinned toolchain). +4. [ ] Logi Options+ uninstalled; only **one** OpenLogi on the machine. +5. [ ] Binaries copied to `%LOCALAPPDATA%\Programs\OpenLogi\`; single Run key with `--background`. +6. [ ] App launched once; **device key** read out of `config.toml`. +7. [ ] Ring slots configured (in-app editor, or adapt `docs/action-ring-example.toml`). +8. [ ] Verified: log shows `action_ring=true`; tapping the pad opens the ring. diff --git a/crates/openlogi-agent-core/Cargo.toml b/crates/openlogi-agent-core/Cargo.toml index 1a0f341f..448fbcb0 100644 --- a/crates/openlogi-agent-core/Cargo.toml +++ b/crates/openlogi-agent-core/Cargo.toml @@ -29,3 +29,5 @@ workspace = true bincode = "1.3" # Only to construct an `InventoryError::Hid` in the watcher's classify tests. async-hid = { workspace = true } +# `start_paused` virtual time for the ring long-poll timeout tests. +tokio = { workspace = true, features = ["test-util", "macros", "rt"] } diff --git a/crates/openlogi-agent-core/src/bindings.rs b/crates/openlogi-agent-core/src/bindings.rs index a416709c..ceba82cd 100644 --- a/crates/openlogi-agent-core/src/bindings.rs +++ b/crates/openlogi-agent-core/src/bindings.rs @@ -77,6 +77,25 @@ pub fn gesture_bindings_for( bindings } +/// Whether the Action Ring pad's effective binding opens the on-screen ring +/// (a [`Binding::Ring`]) rather than firing a single action. +/// +/// A device with no stored `ActionRing` binding gets the canonical default — +/// which *is* a ring — so a fresh MX Master 4 opens the ring out of the box. +/// A per-app overlay that demotes the pad to a single action disarms the ring +/// for that app, mirroring how a gesture owner is demoted per app. +#[must_use] +pub fn ring_armed_for(config: &Config, config_key: Option<&str>, app_bundle: Option<&str>) -> bool { + let Some(key) = config_key else { + // No config key yet (no device selected) — the default binding rules. + return true; + }; + config + .effective_bindings(key, app_bundle) + .remove(&ButtonId::ActionRing) + .is_none_or(|binding| binding.is_ring()) +} + /// Per-direction maps for the OS-hook gesture buttons (Middle/Back/Forward in /// gesture mode) on `config_key`, with `app_bundle`'s per-app overlay applied, /// for the OS hook to resolve a hold+swipe. @@ -160,6 +179,48 @@ mod tests { ); } + #[test] + fn ring_stays_armed_by_default_and_disarms_on_a_single_binding() { + let mut cfg = Config::default(); + // No stored binding: the canonical Ring default arms the overlay. + assert!(ring_armed_for(&cfg, Some("2b042"), None)); + assert!( + ring_armed_for(&cfg, None, None), + "no selected device still means the default ring binding" + ); + + // The user demotes the pad to a plain action — taps dispatch instead. + cfg.set_binding("2b042", ButtonId::ActionRing, Action::Copy.into()); + assert!(!ring_armed_for(&cfg, Some("2b042"), None)); + + // An explicit ring binding re-arms it. + cfg.set_binding( + "2b042", + ButtonId::ActionRing, + openlogi_core::binding::default_binding_for(ButtonId::ActionRing), + ); + assert!(ring_armed_for(&cfg, Some("2b042"), None)); + } + + #[test] + fn per_app_single_override_disarms_the_ring_for_that_app_only() { + let mut cfg = Config::default(); + cfg.set_per_app_binding( + "2b042", + "com.microsoft.VSCode", + ButtonId::ActionRing, + Some(Action::Paste), + ); + assert!( + !ring_armed_for(&cfg, Some("2b042"), Some("com.microsoft.VSCode")), + "the overlay must not open where the pad is a plain action" + ); + assert!( + ring_armed_for(&cfg, Some("2b042"), Some("com.other.App")), + "other apps keep the ring" + ); + } + #[test] fn oshook_gestures_collects_only_os_hook_gesture_buttons() { let mut cfg = Config::default(); diff --git a/crates/openlogi-agent-core/src/ipc.rs b/crates/openlogi-agent-core/src/ipc.rs index 9acdc281..f561b14c 100644 --- a/crates/openlogi-agent-core/src/ipc.rs +++ b/crates/openlogi-agent-core/src/ipc.rs @@ -6,6 +6,7 @@ //! flow long-polls [`Agent::next_pairing`], which the agent holds open until a //! pairing event arrives or the request deadline elapses. +use openlogi_core::binding::Action; use openlogi_core::config::Lighting; use openlogi_core::device::DeviceInventory; use openlogi_hid::{ @@ -28,7 +29,37 @@ use serde::{Deserialize, Serialize}; /// v8: [`WriteError`] carries typed HID++ operation failures. /// v9: `poll_event_monitor` appended + [`MonitorEvent`] (live event monitor). /// v10: `Capabilities::hires_wheel` appended. -pub const PROTOCOL_VERSION: u32 = 10; +/// v11: `next_ring_press` + `execute_action` appended (Action Ring overlay). +/// v12: [`Action`] gains the appended `Run` / `PasteText` variants (they ride +/// inside `execute_action` and config snapshots). +/// v13: [`Action`] gains the appended `Folder` variant (ring sub-menus). +/// v14: [`Action`] gains the appended `Named` variant (user action labels). +/// v15: [`RingPress`] gains the appended `device_key` field, so the overlay +/// resolves slots against the pad's own device. +pub const PROTOCOL_VERSION: u32 = 15; + +/// One Action Ring pad press, streamed to the GUI via +/// [`Agent::next_ring_press`] so the on-screen ring opens (or confirms a +/// selection) the moment the pad is tapped. +/// +/// bincode encodes struct fields positionally — fields are append-only, like +/// the [`Agent`] trait methods. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct RingPress { + /// Monotonic press counter within one agent run. Lets the GUI drop + /// stale presses that queued while it had no poll outstanding (e.g. + /// while reconnecting) instead of replaying a burst. + pub seq: u64, + /// Config key of the device whose pad fired, so the overlay renders that + /// device's ring. + /// + /// Without it the GUI would resolve slots against its carousel selection, + /// which is a different device whenever the pad's mouse isn't the one on + /// screen — and a device with no ring binding falls back to the canonical + /// default ring, i.e. a ring the user never configured. Empty when the + /// agent has no active device key. + pub device_key: String, +} /// Where the agent's device enumeration stands. The distinction matters /// because an empty inventory list is ambiguous on its own: the GUI must keep @@ -272,7 +303,19 @@ pub trait Agent { /// Drain the events the hook has observed since the last poll, for the GUI's /// live event monitor. The first poll enables monitoring; the agent /// auto-disables it once polls stop (the GUI closed the panel or died), so - /// there is no explicit stop. Appended last — see the method-order note on - /// [`Agent::protocol_version`]. + /// there is no explicit stop. async fn poll_event_monitor() -> Vec; + /// Long-poll the next Action Ring pad press. The agent answers immediately + /// when a press is queued, otherwise holds the request until one arrives or + /// its hold window elapses (`None` — the GUI simply re-polls). Only presses + /// while the pad's effective binding is ring-shaped arrive here; a + /// single-action binding dispatches in the agent instead. Appended for + /// v11 — method order is wire-sensitive (see [`Self::protocol_version`]). + async fn next_ring_press() -> Option; + /// Execute one bound action through the agent's dispatch path — how the + /// ring overlay fires the sector the user selected. Runs in the agent so + /// synthesis works exactly like any button binding (and is not tied to the + /// GUI's window focus). Appended for v11 — see the method-order note on + /// [`Self::protocol_version`]. + async fn execute_action(action: Action); } diff --git a/crates/openlogi-agent-core/src/lib.rs b/crates/openlogi-agent-core/src/lib.rs index 435d848c..0638585b 100644 --- a/crates/openlogi-agent-core/src/lib.rs +++ b/crates/openlogi-agent-core/src/lib.rs @@ -15,6 +15,7 @@ pub mod hook_runtime; pub mod ipc; pub mod orchestrator; pub mod receiver_access; +pub mod ring; pub mod transport; pub mod watchers; diff --git a/crates/openlogi-agent-core/src/orchestrator.rs b/crates/openlogi-agent-core/src/orchestrator.rs index a3c26fdd..25757314 100644 --- a/crates/openlogi-agent-core/src/orchestrator.rs +++ b/crates/openlogi-agent-core/src/orchestrator.rs @@ -20,11 +20,12 @@ use openlogi_hid::{CaptureChannel, DeviceRoute}; use tracing::warn; use crate::DpiCycleState; -use crate::bindings::{bindings_for, gesture_bindings_for, oshook_gestures_for}; +use crate::bindings::{bindings_for, gesture_bindings_for, oshook_gestures_for, ring_armed_for}; use crate::device_order::DeviceStableId; use crate::hook_runtime::{HookMaps, SharedHookMaps}; use crate::ipc::InventoryHealth; use crate::receiver_access::ReceiverAccess; +use crate::ring::RingChannel; use crate::watchers::gesture::GestureBindings; /// The minimal per-device facts the agent needs: the config key (binding / @@ -61,6 +62,10 @@ pub struct SharedRuntime { /// Exclusive receiver access shared by HID++ capture and pairing. Capture /// and pairing must never open the same receiver HID node concurrently. pub receiver_access: ReceiverAccess, + /// Action Ring press channel: the gesture watcher pushes pad presses here + /// while the pad's effective binding is ring-shaped, and the IPC server's + /// `next_ring_press` long-poll drains them for the GUI overlay. + pub ring: RingChannel, } /// Owns the config + device selection and keeps [`SharedRuntime`] in sync. @@ -112,6 +117,7 @@ impl Orchestrator { )), capture_channel: Arc::new(RwLock::new(None)), receiver_access: ReceiverAccess::default(), + ring: RingChannel::default(), }; let orch = Self { config, @@ -183,6 +189,10 @@ impl Orchestrator { self.config.app_settings.thumbwheel_sensitivity, Ordering::Relaxed, ); + self.shared.ring.set_armed( + ring_armed_for(&self.config, key, self.current_app.as_deref()), + key, + ); } /// Apply a fresh inventory snapshot. Always refreshes the snapshot the IPC diff --git a/crates/openlogi-agent-core/src/ring.rs b/crates/openlogi-agent-core/src/ring.rs new file mode 100644 index 00000000..e9fb0bd4 --- /dev/null +++ b/crates/openlogi-agent-core/src/ring.rs @@ -0,0 +1,217 @@ +//! Shared Action Ring press channel between the gesture watcher (producer) +//! and the IPC server's long-poll (consumer). +//! +//! When the pad's effective binding is ring-shaped, a tap must reach the GUI — +//! the process that draws the on-screen ring — instantly. The GUI keeps one +//! `next_ring_press` long-poll outstanding; the watcher pushes each press here +//! and the poll answers immediately, so open latency is one IPC round trip +//! rather than a poll interval. + +use std::collections::VecDeque; +use std::sync::{Arc, Mutex, PoisonError}; +use std::time::Duration; + +use tokio::sync::Notify; + +use crate::ipc::RingPress; + +/// How long an empty `next_ring_press` poll is held before answering `None`. +/// Mirrors the pairing long-poll: long enough that an idle GUI re-polls rarely, +/// short enough that the client's request deadline (25 s) never fires first. +const HOLD: Duration = Duration::from_secs(20); + +/// Presses buffered while the GUI has no poll outstanding. Deliberately small: +/// a backlog older than this is stale input (the user tapping at a dead +/// overlay), and replaying it would fire ghost open/select transitions. +const QUEUE_CAP: usize = 4; + +#[derive(Default)] +struct RingChannelState { + /// Whether the active device's effective Action Ring binding is + /// ring-shaped. Published by the orchestrator on every rebuild; the + /// gesture watcher routes a pad press here only while set, and to the + /// ordinary single-action dispatch otherwise. + armed: bool, + /// Config key of the device whose pad is armed, published alongside + /// [`Self::armed`] and stamped onto every press. + /// + /// The GUI must resolve a press against *this* device, not whichever one + /// its carousel happens to show: the ring belongs to the mouse with the + /// pad, and asking a keyboard for ring slots yields the canonical + /// defaults — a second, phantom ring the user never configured. + device_key: Option, + /// Monotonic press counter for [`RingPress::seq`]. + seq: u64, + pending: VecDeque, +} + +/// Shared press channel; cheap to clone (two `Arc`s). +#[derive(Clone, Default)] +pub struct RingChannel { + state: Arc>, + notify: Arc, +} + +impl RingChannel { + fn lock(&self) -> std::sync::MutexGuard<'_, RingChannelState> { + // Recover the guard even if a prior holder panicked — every critical + // section below is panic-free, so the data stays consistent. + self.state.lock().unwrap_or_else(PoisonError::into_inner) + } + + /// Publish whether the pad's effective binding opens the ring, and which + /// device that binding belongs to. + pub fn set_armed(&self, armed: bool, device_key: Option<&str>) { + let mut st = self.lock(); + st.armed = armed; + st.device_key = device_key.map(str::to_owned); + } + + /// Whether a pad press should be routed to the ring overlay. + #[must_use] + pub fn is_armed(&self) -> bool { + self.lock().armed + } + + /// Queue one pad press and wake the long-poll. Oldest press is dropped + /// when the queue is full — see [`QUEUE_CAP`]. + pub fn push_press(&self) { + { + let mut st = self.lock(); + st.seq += 1; + let seq = st.seq; + let device_key = st.device_key.clone().unwrap_or_default(); + if st.pending.len() == QUEUE_CAP { + st.pending.pop_front(); + } + st.pending.push_back(RingPress { seq, device_key }); + } + // notify_one stores a permit when no poll is waiting, so a press that + // lands between a poll's queue check and its await is never lost. + self.notify.notify_one(); + } + + /// Long-poll: the oldest queued press, or `None` once [`HOLD`] elapses. + pub async fn next_press(&self) -> Option { + let deadline = tokio::time::Instant::now() + HOLD; + loop { + // Register interest before checking, so a push between the check + // and the await wakes the `notified` future instead of racing it. + let notified = self.notify.notified(); + if let Some(press) = self.lock().pending.pop_front() { + return Some(press); + } + tokio::select! { + () = notified => {} + () = tokio::time::sleep_until(deadline) => return None, + } + } + } +} + +#[cfg(test)] +#[allow(clippy::expect_used, reason = "expect/unwrap are idiomatic in tests")] +mod tests { + use super::*; + + /// A press carrying `seq`, from the device the tests arm below. + fn press(seq: u64) -> RingPress { + RingPress { + seq, + device_key: "mouse".into(), + } + } + + /// An armed channel, as the orchestrator publishes it. + fn armed() -> RingChannel { + let chan = RingChannel::default(); + chan.set_armed(true, Some("mouse")); + chan + } + + #[tokio::test] + async fn queued_press_answers_immediately() { + let chan = armed(); + chan.push_press(); + assert_eq!(chan.next_press().await, Some(press(1))); + } + + #[tokio::test] + async fn presses_deliver_in_order_with_monotonic_seq() { + let chan = armed(); + chan.push_press(); + chan.push_press(); + assert_eq!(chan.next_press().await, Some(press(1))); + assert_eq!(chan.next_press().await, Some(press(2))); + } + + #[tokio::test] + async fn overflow_drops_the_oldest_press_not_the_newest() { + let chan = armed(); + for _ in 0..QUEUE_CAP + 2 { + chan.push_press(); + } + // Seqs 1 and 2 were evicted; the survivors are the most recent CAP. + assert_eq!(chan.next_press().await, Some(press(3))); + } + + /// Every press names the device whose pad fired, so the overlay renders + /// that device's ring instead of falling back to defaults for whatever + /// the GUI's carousel happens to show. + #[tokio::test] + async fn a_press_carries_the_armed_device_key() { + let chan = RingChannel::default(); + chan.set_armed(true, Some("receiver:abc:slot:2")); + chan.push_press(); + assert_eq!( + chan.next_press().await.map(|p| p.device_key), + Some("receiver:abc:slot:2".to_string()) + ); + + // Re-arming for another device restamps subsequent presses. + chan.set_armed(true, Some("receiver:abc:slot:3")); + chan.push_press(); + assert_eq!( + chan.next_press().await.map(|p| p.device_key), + Some("receiver:abc:slot:3".to_string()) + ); + + // No active device: an empty key, which the GUI treats as "unknown". + chan.set_armed(true, None); + chan.push_press(); + assert_eq!( + chan.next_press().await.map(|p| p.device_key), + Some(String::new()) + ); + } + + #[tokio::test(start_paused = true)] + async fn empty_poll_times_out_with_none() { + let chan = RingChannel::default(); + // Paused time: the sleep_until elapses instantly once polled. + assert_eq!(chan.next_press().await, None); + } + + #[tokio::test(start_paused = true)] + async fn press_during_a_held_poll_wakes_it() { + let chan = armed(); + let waiter = tokio::spawn({ + let chan = chan.clone(); + async move { chan.next_press().await } + }); + // Let the poll reach its await before pushing. + tokio::task::yield_now().await; + chan.push_press(); + assert_eq!(waiter.await.expect("join"), Some(press(1))); + } + + #[tokio::test] + async fn armed_flag_round_trips() { + let chan = RingChannel::default(); + assert!(!chan.is_armed(), "unarmed until the orchestrator publishes"); + chan.set_armed(true, Some("mouse")); + assert!(chan.is_armed()); + chan.set_armed(false, None); + assert!(!chan.is_armed()); + } +} diff --git a/crates/openlogi-agent-core/src/watchers/gesture.rs b/crates/openlogi-agent-core/src/watchers/gesture.rs index 80659682..e966c66b 100644 --- a/crates/openlogi-agent-core/src/watchers/gesture.rs +++ b/crates/openlogi-agent-core/src/watchers/gesture.rs @@ -33,6 +33,7 @@ use tracing::{debug, warn}; use crate::DpiCycleState; use crate::hook_runtime::{self, SharedHookMaps}; use crate::receiver_access::ReceiverAccess; +use crate::ring::RingChannel; /// Shared gesture-direction binding map, mirrored from `AppState` (keyed by /// direction). The watcher reads it to map a captured swipe to a bound action. @@ -81,6 +82,7 @@ pub fn spawn( capture_channel: CaptureChannel, thumbwheel_sensitivity: ThumbwheelSensitivity, receiver_access: ReceiverAccess, + ring: RingChannel, ) { thread::spawn(move || { let runtime = match tokio::runtime::Builder::new_current_thread() @@ -100,6 +102,7 @@ pub fn spawn( capture_channel, thumbwheel_sensitivity, receiver_access, + ring, )); }); } @@ -151,6 +154,7 @@ async fn manage( capture_channel: CaptureChannel, thumbwheel_sensitivity: ThumbwheelSensitivity, receiver_access: ReceiverAccess, + ring: RingChannel, ) { let (tx, mut rx) = mpsc::unbounded_channel::(); // (route, capture_thumbwheel, divert_gesture_button) @@ -180,6 +184,7 @@ async fn manage( &dpi_cycle, &capture_channel, &thumbwheel_sensitivity, + &ring, ); } _ = ticker.tick() => { @@ -308,6 +313,10 @@ enum WheelOutput { } /// Route one captured input to its bound action (or re-synthesised scroll). +#[expect( + clippy::too_many_arguments, + reason = "the watcher's full shared-state set; bundling it would just relocate the list" +)] fn dispatch( input: CapturedInput, accumulators: &mut WheelAccumulators, @@ -316,6 +325,7 @@ fn dispatch( dpi_cycle: &Arc>, capture: &CaptureChannel, thumbwheel_sensitivity: &ThumbwheelSensitivity, + ring: &RingChannel, ) { match input { CapturedInput::Gesture(direction) => { @@ -330,6 +340,13 @@ fn dispatch( debug!(?direction, "gesture with no binding — ignored"); } } + // A ring-shaped Action Ring binding routes the press to the GUI + // overlay instead of the single-action path (whose projection for a + // ring binding is deliberately `Action::None`). + CapturedInput::ButtonPressed(ButtonId::ActionRing) if ring.is_armed() => { + debug!("action ring press → overlay long-poll"); + ring.push_press(); + } CapturedInput::ButtonPressed(button) => { let action = hook_maps .read() diff --git a/crates/openlogi-agent-core/tests/wire_format.rs b/crates/openlogi-agent-core/tests/wire_format.rs index c5b14e4c..5291b00f 100644 --- a/crates/openlogi-agent-core/tests/wire_format.rs +++ b/crates/openlogi-agent-core/tests/wire_format.rs @@ -24,8 +24,9 @@ use std::fmt::Write; use bincode::Options; use openlogi_agent_core::ipc::{ AgentRequest, AgentSnapshot, AgentStatus, FoundDevice, InventoryHealth, MonitorEvent, - PROTOCOL_VERSION, PairingCommandError, PairingFailure, PairingUpdate, + PROTOCOL_VERSION, PairingCommandError, PairingFailure, PairingUpdate, RingPress, }; +use openlogi_core::binding::Action; use openlogi_core::config::Lighting; use openlogi_core::device::{ BatteryInfo, BatteryLevel, BatteryStatus, Capabilities, DeviceInventory, DeviceKind, @@ -61,7 +62,7 @@ fn assert_wire(value: &T, golden: &str) { /// that makes that visible in the same diff. #[test] fn protocol_version_is_pinned() { - assert_eq!(PROTOCOL_VERSION, 10); + assert_eq!(PROTOCOL_VERSION, 15); } /// tarpc encodes the request enum's variant index, so trait *method order* is @@ -83,6 +84,65 @@ fn request_variant_order() { assert_wire(&AgentRequest::NextPairing {}, "0d"); assert_wire(&AgentRequest::Snapshot {}, "0e"); assert_wire(&AgentRequest::PollEventMonitor {}, "0f"); + assert_wire(&AgentRequest::NextRingPress {}, "10"); + assert_wire( + &AgentRequest::ExecuteAction { + action: Action::Copy, + }, + "1106", + ); + // The appended v12 payload variants: variant index as a varint, then the + // usual length-prefixed UTF-8 payload. + assert_wire( + &AgentRequest::ExecuteAction { + action: Action::Run("a".into()), + }, + "112d0161", + ); + assert_wire( + &AgentRequest::ExecuteAction { + action: Action::PasteText("Hi".into()), + }, + "112e024869", + ); + // v13's Folder: variant index, then the BTreeMap as varint length + + // (RingSlot variant, Action variant) pairs. + assert_wire( + &AgentRequest::ExecuteAction { + action: Action::Folder(std::collections::BTreeMap::from([( + openlogi_core::binding::RingSlot::North, + Action::Copy, + )])), + }, + "112f010006", + ); + // v14's Named: variant index, the label, then the wrapped action. + assert_wire( + &AgentRequest::ExecuteAction { + action: Action::Copy.with_name("N"), + }, + "1130014e06", + ); +} + +#[test] +fn ring_press() { + // Varint seq: single byte below 251, 0xfb + u16 LE above; then the + // appended device key as a length-prefixed string. + assert_wire( + &RingPress { + seq: 3, + device_key: String::new(), + }, + "0300", + ); + assert_wire( + &RingPress { + seq: 300, + device_key: "ab".into(), + }, + "fb2c01026162", + ); } #[test] diff --git a/crates/openlogi-agent/src/main.rs b/crates/openlogi-agent/src/main.rs index b5e98729..42256008 100644 --- a/crates/openlogi-agent/src/main.rs +++ b/crates/openlogi-agent/src/main.rs @@ -77,8 +77,12 @@ fn main() { self_restart::spawn(); let config = Config::load_or_default().unwrap_or_else(|e| { - warn!(error = %e, "could not load config.toml; using defaults"); - Config::default() + warn!( + error = %e, + "could not load config.toml; running on defaults WITHOUT persisting, \ + so the unreadable file is left intact" + ); + Config::defaults_for_unreadable() }); let runtime = match tokio::runtime::Builder::new_multi_thread() @@ -162,6 +166,7 @@ async fn run(config: Config) { shared.capture_channel.clone(), shared.thumbwheel_sensitivity.clone(), shared.receiver_access.clone(), + shared.ring.clone(), ); let mut inventory_rx = watchers::inventory::spawn(Duration::from_secs(2)); diff --git a/crates/openlogi-agent/src/pairing.rs b/crates/openlogi-agent/src/pairing.rs index ef365590..fd5a047e 100644 --- a/crates/openlogi-agent/src/pairing.rs +++ b/crates/openlogi-agent/src/pairing.rs @@ -271,6 +271,7 @@ mod tests { thumbwheel_sensitivity: Arc::new(0.into()), capture_channel: Arc::new(RwLock::new(None)), receiver_access: ReceiverAccess::default(), + ring: openlogi_agent_core::ring::RingChannel::default(), } } diff --git a/crates/openlogi-agent/src/server.rs b/crates/openlogi-agent/src/server.rs index 4e69d75b..40720c70 100644 --- a/crates/openlogi-agent/src/server.rs +++ b/crates/openlogi-agent/src/server.rs @@ -10,12 +10,14 @@ use std::sync::atomic::{AtomicBool, Ordering}; use futures::StreamExt as _; use openlogi_agent_core::event_monitor::SharedEventMonitor; +use openlogi_agent_core::hook_runtime; use openlogi_agent_core::ipc::{ Agent, AgentSnapshot, AgentStatus, MonitorEvent, PROTOCOL_VERSION, PairingCommandError, - PairingUpdate, + PairingUpdate, RingPress, }; use openlogi_agent_core::orchestrator::{Orchestrator, SharedRuntime}; use openlogi_agent_core::{hardware, transport}; +use openlogi_core::binding::Action; use openlogi_core::config::{Config, Lighting}; use openlogi_core::device::DeviceInventory; use openlogi_hid::{ @@ -171,6 +173,19 @@ impl Agent for AgentServer { async fn poll_event_monitor(self, _: Context) -> Vec { self.event_monitor.poll() } + + async fn next_ring_press(self, _: Context) -> Option { + self.shared.ring.next_press().await + } + + async fn execute_action(self, _: Context, action: Action) { + info!(action = %action.label(), "ring overlay → action"); + hook_runtime::dispatch_action( + &action, + &self.shared.dpi_cycle, + &self.shared.capture_channel, + ); + } } /// Bind the agent's IPC socket and serve [`Agent`] requests until the process diff --git a/crates/openlogi-cli/Cargo.toml b/crates/openlogi-cli/Cargo.toml index f8f498d6..b1f67e87 100644 --- a/crates/openlogi-cli/Cargo.toml +++ b/crates/openlogi-cli/Cargo.toml @@ -16,9 +16,24 @@ openlogi-hid = { path = "../openlogi-hid", version = "0.6.22" } openlogi-assets = { path = "../openlogi-assets", version = "0.6.22" } clap = { workspace = true } anyhow = { workspace = true } +async-hid = { workspace = true } +futures-lite = { workspace = true } tokio = { workspace = true, features = ["rt", "macros", "sync", "time"] } tracing = { workspace = true } tracing-subscriber = { workspace = true } +# RawInput tap for `diag rawinput` — the only user-mode way to observe HID +# collections the OS input stack holds exclusively (see diag/rawinput.rs). +[target.'cfg(target_os = "windows")'.dependencies] +windows-sys = { workspace = true, features = [ + "Win32_Foundation", + # WNDCLASSW references HBRUSH, so the window-class APIs are only exposed + # when Win32_Graphics_Gdi is also enabled. + "Win32_Graphics_Gdi", + "Win32_System_LibraryLoader", + "Win32_UI_Input", + "Win32_UI_WindowsAndMessaging", +] } + [lints] workspace = true diff --git a/crates/openlogi-cli/src/cmd/diag.rs b/crates/openlogi-cli/src/cmd/diag.rs index 3a9e0a74..11bdcd6b 100644 --- a/crates/openlogi-cli/src/cmd/diag.rs +++ b/crates/openlogi-cli/src/cmd/diag.rs @@ -10,10 +10,18 @@ use anyhow::{Result, anyhow}; use clap::Subcommand; use openlogi_hid::{DeviceRoute, dump_features}; +use std::fmt::Write as _; + +pub mod call; pub mod controls; pub mod dpi; pub mod features; +pub mod fsb; +pub mod hidden; +pub mod hidsniff; pub mod lighting; +pub mod panel; +pub mod rawinput; pub mod smartshift; pub mod wheel; @@ -31,6 +39,18 @@ pub enum DiagCmd { Lighting(lighting::LightingArgs), /// Read or set the HID++ 0x2121 wheel reporting resolution. Wheel(wheel::WheelArgs), + /// Passively hex-dump raw input reports from every Logitech HID interface. + Hidsniff(hidsniff::HidSniffArgs), + /// Read or set the 0x1e00 EnableHiddenFeatures gate. + Hidden(hidden::HiddenArgs), + /// Raw-probe the 0x19c0 ForceSensingButton feature (Action Ring panel). + Fsb(fsb::FsbArgs), + /// OS-level RawInput tap: dump reports even from OS-owned HID collections. + Rawinput(rawinput::RawInputArgs), + /// Send one raw call to any HID++ 2.0 feature by ID (reverse-engineering). + Call(call::CallArgs), + /// Arm the Action Ring panel (Options+ recipe) and print its press events. + Panel(panel::PanelArgs), } impl DiagCmd { @@ -42,10 +62,24 @@ impl DiagCmd { Self::Smartshift(args) => smartshift::run(args).await, Self::Lighting(args) => lighting::run(args).await, Self::Wheel(args) => wheel::run(args).await, + Self::Hidsniff(args) => hidsniff::run(args).await, + Self::Hidden(args) => hidden::run(args).await, + Self::Fsb(args) => fsb::run(args).await, + Self::Rawinput(args) => rawinput::run(args).await, + Self::Call(args) => call::run(args).await, + Self::Panel(args) => panel::run(args).await, } } } +/// Space-separated lowercase hex (`"0a 1b "` style) for diag report dumps. +pub(crate) fn hex_dump(bytes: &[u8]) -> String { + bytes.iter().fold(String::new(), |mut s, b| { + let _ = write!(s, "{b:02x} "); + s + }) +} + /// One online, paired device discovered during enumeration, already resolved to /// the [`DeviceRoute`] needed to talk to it. Builds a Bolt route when the device /// is behind a receiver, a direct route otherwise (USB cable / Bluetooth). diff --git a/crates/openlogi-cli/src/cmd/diag/call.rs b/crates/openlogi-cli/src/cmd/diag/call.rs new file mode 100644 index 00000000..4006a963 --- /dev/null +++ b/crates/openlogi-cli/src/cmd/diag/call.rs @@ -0,0 +1,59 @@ +//! `openlogi diag call` — send one raw call to ANY HID++ 2.0 feature by ID. +//! +//! Generic reverse-engineering probe: resolves the feature at runtime and +//! hex-dumps the 16-byte response. `InvalidFunctionId` marks the end of a +//! feature's function table; `InvalidArgument` means the function exists but +//! wants different arguments. + +use anyhow::{Context, Result, bail}; +use clap::Args; + +use crate::cmd::diag::select_device; + +#[derive(Debug, Args)] +pub struct CallArgs { + /// Feature ID, hex (e.g. 1e02). + #[arg(long, value_name = "HEX")] + pub feature: String, + + /// Function ID to call (0-15). + #[arg(long, default_value_t = 0)] + pub function: u8, + + /// Three comma-separated hex argument bytes, e.g. `01,00,00`. + #[arg(long, value_name = "AA,BB,CC")] + pub args: Option, + + /// Run against the device whose name contains this string + /// (case-insensitive) instead of auto-selecting. + #[arg(long, value_name = "NAME")] + pub device: Option, +} + +pub async fn run(args: CallArgs) -> Result<()> { + let feature = u16::from_str_radix(args.feature.trim_start_matches("0x"), 16) + .context("--feature must be hex, e.g. 1e02")?; + if args.function > 0x0f { + bail!("function must be 0-15 (got {})", args.function); + } + let call_args = super::fsb::parse_args(args.args.as_deref())?; + + let (route, name) = select_device(args.device.as_deref(), &[feature]).await?; + println!("device: {name} ({route})"); + println!( + "feature 0x{feature:04x} fn={} args={:02x} {:02x} {:02x}", + args.function, call_args[0], call_args[1], call_args[2] + ); + + match openlogi_hid::hidden_features::raw_feature_call(&route, feature, args.function, call_args) + .await + { + Ok(Some(payload)) => { + let hex = super::hex_dump(&payload); + println!("response: {hex}"); + } + Ok(None) => println!("feature not exposed by this device"), + Err(e) => println!("error: {e}"), + } + Ok(()) +} diff --git a/crates/openlogi-cli/src/cmd/diag/fsb.rs b/crates/openlogi-cli/src/cmd/diag/fsb.rs new file mode 100644 index 00000000..23aaa2ee --- /dev/null +++ b/crates/openlogi-cli/src/cmd/diag/fsb.rs @@ -0,0 +1,66 @@ +//! `openlogi diag fsb` — raw-probe the `0x19c0 ForceSensingButton` feature +//! (the MX Master 4's Action Ring panel). +//! +//! The feature's function map is undocumented; this sends one function call +//! with caller-chosen argument bytes and hex-dumps the response so the map +//! can be reverse-engineered on real hardware. An `InvalidFunction` HID++ +//! error is the expected "past the end of the table" response. + +use anyhow::{Context, Result, bail}; +use clap::Args; + +use crate::cmd::diag::select_device; + +#[derive(Debug, Args)] +pub struct FsbArgs { + /// Function ID to call (0-15). + #[arg(long, default_value_t = 0)] + pub function: u8, + + /// Three comma-separated hex argument bytes, e.g. `01,00,00`. + #[arg(long, value_name = "AA,BB,CC")] + pub args: Option, + + /// Run against the device whose name contains this string + /// (case-insensitive) instead of auto-selecting. + #[arg(long, value_name = "NAME")] + pub device: Option, +} + +pub async fn run(args: FsbArgs) -> Result<()> { + if args.function > 0x0f { + bail!("function must be 0-15 (got {})", args.function); + } + let call_args = parse_args(args.args.as_deref())?; + + let (route, name) = select_device(args.device.as_deref(), &[0x19c0]).await?; + println!("device: {name} ({route})"); + println!( + "0x19c0 fn={} args={:02x} {:02x} {:02x}", + args.function, call_args[0], call_args[1], call_args[2] + ); + + match openlogi_hid::hidden_features::force_button_raw_call(&route, args.function, call_args) + .await + { + Ok(payload) => { + let hex = super::hex_dump(&payload); + println!("response: {hex}"); + } + Err(e) => println!("error: {e}"), + } + Ok(()) +} + +pub(crate) fn parse_args(raw: Option<&str>) -> Result<[u8; 3]> { + let Some(raw) = raw else { return Ok([0; 3]) }; + let parts: Vec = raw + .split(',') + .map(|p| u8::from_str_radix(p.trim().trim_start_matches("0x"), 16)) + .collect::>() + .context("--args must be hex bytes like 01,00,00")?; + if parts.len() != 3 { + bail!("--args needs exactly 3 bytes (got {})", parts.len()); + } + Ok([parts[0], parts[1], parts[2]]) +} diff --git a/crates/openlogi-cli/src/cmd/diag/hidden.rs b/crates/openlogi-cli/src/cmd/diag/hidden.rs new file mode 100644 index 00000000..4fcae8ee --- /dev/null +++ b/crates/openlogi-cli/src/cmd/diag/hidden.rs @@ -0,0 +1,49 @@ +//! `openlogi diag hidden` — read or set the `0x1e00 EnableHiddenFeatures` +//! gate. Some devices keep auxiliary event sources dormant until a host +//! enables this; the setting does not survive a device power cycle. + +use anyhow::{Context, Result, bail}; +use clap::Args; + +use crate::cmd::diag::select_device; + +#[derive(Debug, Args)] +pub struct HiddenArgs { + /// Enable hidden features (write `1`). + #[arg(long, conflicts_with = "disable")] + pub enable: bool, + + /// Disable hidden features (write `0`). + #[arg(long)] + pub disable: bool, + + /// Run against the device whose name contains this string + /// (case-insensitive) instead of auto-selecting. + #[arg(long, value_name = "NAME")] + pub device: Option, +} + +pub async fn run(args: HiddenArgs) -> Result<()> { + let (route, name) = select_device(args.device.as_deref(), &[0x1e00]).await?; + println!("device: {name} ({route})"); + + let before = openlogi_hid::hidden_features::hidden_features_enabled(&route) + .await + .context("read 0x1e00 enabled state")?; + println!("hidden features enabled: {before}"); + + let target = match (args.enable, args.disable) { + (true, _) => true, + (_, true) => false, + _ => return Ok(()), + }; + + let after = openlogi_hid::hidden_features::set_hidden_features_enabled(&route, target) + .await + .context("write 0x1e00 enabled state")?; + println!("hidden features enabled (read-back): {after}"); + if after != target { + bail!("write not applied: requested {target}, device reports {after}"); + } + Ok(()) +} diff --git a/crates/openlogi-cli/src/cmd/diag/hidsniff.rs b/crates/openlogi-cli/src/cmd/diag/hidsniff.rs new file mode 100644 index 00000000..662013b0 --- /dev/null +++ b/crates/openlogi-cli/src/cmd/diag/hidsniff.rs @@ -0,0 +1,117 @@ +//! `openlogi diag hidsniff` — passively hex-dump raw input reports from every +//! Logitech HID interface for a bounded window. +//! +//! Diagnosis tool for locating input that does NOT arrive via HID++ divert — +//! e.g. the MX Master 4 Action Ring panel, whose events are invisible on +//! `0x1b04` and suspected to flow through the Bolt receiver's touch-pad +//! collection (`MI_03`) instead. Read-only: opens interfaces for input +//! reports, writes nothing, and interfaces the OS holds exclusively (mouse / +//! keyboard boot collections) simply report their open error and are skipped. + +use std::sync::Arc; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::time::{Duration, Instant}; + +use anyhow::{Context, Result}; +use async_hid::{AsyncHidRead, HidBackend}; +use clap::Args; +use futures_lite::StreamExt; + +/// Per-interface cap on individually printed reports, so an unexpectedly +/// chatty collection (sensor stream) can't drown the interesting ones; counts +/// keep accumulating after the mute. +const PRINT_CAP: u64 = 300; + +#[derive(Debug, Args)] +pub struct HidSniffArgs { + /// Vendor ID to filter on, hex (default: Logitech). + #[arg(long, default_value = "046d")] + pub vid: String, + + /// How long to listen for reports, in seconds. + #[arg(long, default_value_t = 30)] + pub seconds: u64, +} + +pub async fn run(args: HidSniffArgs) -> Result<()> { + let vid = u16::from_str_radix(args.vid.trim_start_matches("0x"), 16) + .context("--vid must be hex, e.g. 046d")?; + + let devices: Vec = HidBackend::default() + .enumerate() + .await + .context("HID enumeration failed")? + .collect() + .await; + + let started = Instant::now(); + let deadline = started + Duration::from_secs(args.seconds); + let mut tasks = Vec::new(); + + for (n, dev) in devices.iter().filter(|d| d.vendor_id == vid).enumerate() { + println!( + "iface #{n}: pid={:04x} usage={:#06x}/{:#04x} name={:?} id={:?}", + dev.product_id, dev.usage_page, dev.usage_id, dev.name, dev.id + ); + match dev.open().await { + Ok((mut reader, _writer)) => { + println!(" -> open OK, listening"); + let label = format!("#{n} pid={:04x} up={:#06x}", dev.product_id, dev.usage_page); + let task_label = label.clone(); + let count = Arc::new(AtomicU64::new(0)); + let task_count = Arc::clone(&count); + let task = tokio::spawn(async move { + let label = task_label; + // 1 KiB: Windows rejects reads whose buffer is smaller than + // the interface's max input report (seen on the Bolt + // receiver's Haptics collection, > 64 bytes). + let mut buf = [0u8; 1024]; + loop { + let remain = deadline.saturating_duration_since(Instant::now()); + if remain.is_zero() { + break; + } + match tokio::time::timeout(remain, reader.read_input_report(&mut buf)).await + { + Ok(Ok(len)) => { + let seen = task_count.fetch_add(1, Ordering::Relaxed) + 1; + if seen <= PRINT_CAP { + let ms = started.elapsed().as_millis(); + let hex = super::hex_dump(&buf[..len]); + println!("[{ms:>7}ms] {label} len={len}: {hex}"); + } else if seen == PRINT_CAP + 1 { + println!("[{label}] print cap reached — counting silently"); + } + } + Ok(Err(e)) => { + println!("[{label}] read error: {e:?}"); + break; + } + Err(_) => break, // deadline reached + } + } + }); + tasks.push((label, count, task)); + } + Err(e) => println!(" -> open failed: {e:?}"), + } + } + + if tasks.is_empty() { + anyhow::bail!("no vid={vid:04x} interface could be opened"); + } + + println!( + "\nlistening on {} interface(s) for {} s — exercise the control under test now\n", + tasks.len(), + args.seconds + ); + for (label, count, task) in tasks { + let _ = task.await; + println!( + "summary {label}: {} report(s)", + count.load(Ordering::Relaxed) + ); + } + Ok(()) +} diff --git a/crates/openlogi-cli/src/cmd/diag/panel.rs b/crates/openlogi-cli/src/cmd/diag/panel.rs new file mode 100644 index 00000000..21983ef1 --- /dev/null +++ b/crates/openlogi-cli/src/cmd/diag/panel.rs @@ -0,0 +1,53 @@ +//! `openlogi diag panel` — arm the MX Master 4 Action Ring panel with the +//! reverse-engineered Options+ recipe and print each press/release. +//! +//! Proves OpenLogi can drive the panel: it enables `0x1b04` +//! `analyticsKeyEvents` on the panel CIDs (no diversion) and decodes the +//! events the panel emits. This is the empirical basis for the production +//! ring; keep the mouse moving so the (BTLE) link is hot while arming. + +use std::sync::Arc; +use std::sync::atomic::{AtomicU32, Ordering}; + +use anyhow::{Context, Result}; +use clap::Args; + +use crate::cmd::diag::select_device; + +#[derive(Debug, Args)] +pub struct PanelArgs { + /// How long to listen, in seconds. + #[arg(long, default_value_t = 45)] + pub seconds: u64, + + /// Run against the device whose name contains this string + /// (case-insensitive) instead of auto-selecting. + #[arg(long, value_name = "NAME")] + pub device: Option, +} + +pub async fn run(args: PanelArgs) -> Result<()> { + let (route, name) = select_device(args.device.as_deref(), &[0x1b04]).await?; + println!("device: {name} ({route})"); + println!( + "arming Action Ring panel (analytics on CIDs 0x01a0/0x0050/0x0051) — press it now, {}s window\n", + args.seconds + ); + + let count = Arc::new(AtomicU32::new(0)); + let tally = Arc::clone(&count); + openlogi_hid::hidden_features::watch_panel(&route, args.seconds, move |cid, event| { + let n = tally.fetch_add(1, Ordering::Relaxed) + 1; + let state = if event != 0 { "PRESS " } else { "RELEASE" }; + println!(" [{n:>3}] panel cid=0x{cid:04x} {state} (event=0x{event:02x})"); + }) + .await + .context("watch panel")?; + + let total = count.load(Ordering::Relaxed); + println!("\n{total} panel event(s) captured."); + if total == 0 { + println!("none seen — was the mouse moving while arming? is Options+ holding the device?"); + } + Ok(()) +} diff --git a/crates/openlogi-cli/src/cmd/diag/rawinput.rs b/crates/openlogi-cli/src/cmd/diag/rawinput.rs new file mode 100644 index 00000000..52e56456 --- /dev/null +++ b/crates/openlogi-cli/src/cmd/diag/rawinput.rs @@ -0,0 +1,289 @@ +//! `openlogi diag rawinput` — OS-level input tap via the Win32 RawInput API. +//! +//! Registers whole HID usage pages (digitizer `0x0D`, haptics `0x0E`, the +//! Logitech vendor pages `0xFF00`/`0xFF43`) with `RIDEV_INPUTSINK` and +//! hex-dumps every report Windows delivers — INCLUDING reports consumed by +//! exclusive OS owners like the Precision Touchpad stack. This is the only +//! user-mode way to observe the Bolt receiver's touch-pad collection +//! (`0x000D/0x05`), whose node `CreateFile` cannot open. Windows-only; +//! read-only (registration does not steal input from its owners). + +use anyhow::Result; +use clap::Args; + +#[derive(Debug, Args)] +pub struct RawInputArgs { + /// How long to listen, in seconds. + #[arg(long, default_value_t = 45)] + pub seconds: u64, +} + +#[cfg(not(target_os = "windows"))] +pub async fn run(_args: RawInputArgs) -> Result<()> { + anyhow::bail!("`diag rawinput` is Windows-only") +} + +#[cfg(target_os = "windows")] +pub async fn run(args: RawInputArgs) -> Result<()> { + // RawInput delivery is synchronous window messaging; the pump owns a + // dedicated blocking thread rather than the async runtime. + let seconds = args.seconds; + tokio::task::spawn_blocking(move || windows_impl::listen(seconds)).await? +} + +#[cfg(target_os = "windows")] +#[expect( + unsafe_code, + reason = "raw Win32 RawInput FFI — a read-only diagnostic input tap with no safe wrapper available" +)] +mod windows_impl { + use std::collections::HashMap; + use std::mem::{size_of, zeroed}; + use std::ptr::{null, null_mut}; + use std::sync::{Mutex, OnceLock}; + use std::time::Instant; + + use anyhow::{Result, bail}; + use windows_sys::Win32::Foundation::{GetLastError, HWND, LPARAM, LRESULT, WPARAM}; + use windows_sys::Win32::System::LibraryLoader::GetModuleHandleW; + use windows_sys::Win32::UI::Input::{ + GetRawInputData, GetRawInputDeviceInfoW, HRAWINPUT, RAWINPUT, RAWINPUTDEVICE, + RAWINPUTHEADER, RID_INPUT, RIDEV_INPUTSINK, RIDEV_PAGEONLY, RIDI_DEVICENAME, RIM_TYPEHID, + RegisterRawInputDevices, + }; + use windows_sys::Win32::UI::WindowsAndMessaging::{ + CreateWindowExW, DefWindowProcW, DispatchMessageW, GetMessageW, MSG, PostQuitMessage, + RegisterClassW, SetTimer, TranslateMessage, WM_INPUT, WM_TIMER, WNDCLASSW, + }; + + /// Set once at listen start; the window proc reads it for timestamps. + static START: OnceLock = OnceLock::new(); + + fn device_names() -> &'static Mutex> { + static NAMES: OnceLock>> = OnceLock::new(); + NAMES.get_or_init(Mutex::default) + } + + pub fn listen(seconds: u64) -> Result<()> { + let _ = START.set(Instant::now()); + + let class_name: Vec = "openlogi_rawinput\0".encode_utf16().collect(); + let window_name: Vec = "openlogi rawinput tap\0".encode_utf16().collect(); + + // SAFETY: plain Win32 window bootstrap; all pointers passed are either + // valid locals or null where the API documents null as acceptable. + let hwnd = unsafe { + let hinstance = GetModuleHandleW(null()); + let mut wc: WNDCLASSW = zeroed(); + wc.lpfnWndProc = Some(wndproc); + wc.hInstance = hinstance; + wc.lpszClassName = class_name.as_ptr(); + // Re-registration in one process returns 0 with + // ERROR_CLASS_ALREADY_EXISTS — harmless for this tool's lifetime. + RegisterClassW(&raw const wc); + + CreateWindowExW( + 0, + class_name.as_ptr(), + window_name.as_ptr(), + 0, + 0, + 0, + 0, + 0, + null_mut(), + null_mut(), + hinstance, + null(), + ) + }; + if hwnd.is_null() { + // SAFETY: trivial error-code read. + bail!("CreateWindowExW failed: {}", unsafe { GetLastError() }); + } + + let flags = RIDEV_INPUTSINK | RIDEV_PAGEONLY; + let registrations = [ + // Digitizer page — the receiver's touch-pad collection lives here. + rid(0x000d, flags, hwnd), + // Haptics page — the receiver's 0x000E collection. + rid(0x000e, flags, hwnd), + // Logitech vendor pages (HID++ short/long and friends). + rid(0xff00, flags, hwnd), + rid(0xff43, flags, hwnd), + ]; + // SAFETY: registrations array outlives the call; cbSize matches. + #[expect( + clippy::cast_possible_truncation, + reason = "a four-element array length and a fixed struct size are far below u32::MAX" + )] + let ok = unsafe { + RegisterRawInputDevices( + registrations.as_ptr(), + registrations.len() as u32, + size_of::() as u32, + ) + }; + if ok == 0 { + // SAFETY: trivial error-code read. + bail!("RegisterRawInputDevices failed: {}", unsafe { + GetLastError() + }); + } + + println!( + "raw-input tap live for {seconds} s — pages 0x0D digitizer, 0x0E haptics, 0xFF00/0xFF43 vendor" + ); + + // SAFETY: standard message pump on the window created above; the + // timer id is private to this window. + unsafe { + SetTimer( + hwnd, + 1, + u32::try_from(seconds * 1000).unwrap_or(45_000), + None, + ); + let mut msg: MSG = zeroed(); + while GetMessageW(&raw mut msg, null_mut(), 0, 0) > 0 { + TranslateMessage(&raw const msg); + DispatchMessageW(&raw const msg); + } + } + println!("raw-input tap closed"); + Ok(()) + } + + fn rid(usage_page: u16, flags: u32, hwnd: HWND) -> RAWINPUTDEVICE { + RAWINPUTDEVICE { + usUsagePage: usage_page, + usUsage: 0, // RIDEV_PAGEONLY requires usage 0 + dwFlags: flags, + hwndTarget: hwnd, + } + } + + unsafe extern "system" fn wndproc( + hwnd: HWND, + msg: u32, + wparam: WPARAM, + lparam: LPARAM, + ) -> LRESULT { + match msg { + WM_INPUT => { + dump_input(lparam as HRAWINPUT); + // WM_INPUT must still reach DefWindowProc for cleanup. + // SAFETY: forwarding the untouched arguments. + unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) } + } + WM_TIMER => { + // SAFETY: ends this thread's message loop. + unsafe { PostQuitMessage(0) }; + 0 + } + // SAFETY: default handling for everything else. + _ => unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) }, + } + } + + fn dump_input(handle: HRAWINPUT) { + #[expect( + clippy::cast_possible_truncation, + reason = "a fixed struct size is far below u32::MAX" + )] + let header_size = size_of::() as u32; + let mut size = 0u32; + // SAFETY: sizing call per RawInput protocol (null buffer, then fetch). + unsafe { + GetRawInputData(handle, RID_INPUT, null_mut(), &raw mut size, header_size); + } + if size == 0 { + return; + } + // Backed by u64 words so the buffer meets RAWINPUT's 8-byte alignment + // — a Vec only guarantees 1. + let mut buf = vec![0u64; (size as usize).div_ceil(size_of::())]; + // SAFETY: buffer is at least the size Windows requested. + let got = unsafe { + GetRawInputData( + handle, + RID_INPUT, + buf.as_mut_ptr().cast(), + &raw mut size, + header_size, + ) + }; + if got == 0 || got == u32::MAX { + return; + } + // SAFETY: Windows filled the buffer with a RAWINPUT structure of at + // least `got` bytes; the u64 backing guarantees its alignment. + let raw = buf.as_ptr().cast::(); + // SAFETY: header fields are plain integers within the filled buffer. + let (dw_type, h_device) = unsafe { ((*raw).header.dwType, (*raw).header.hDevice) }; + if dw_type != RIM_TYPEHID { + return; + } + // SAFETY: dwType == RIM_TYPEHID guarantees the union holds RAWHID. + let (each, count, data_ptr) = unsafe { + let hid = &(*raw).data.hid; + ( + hid.dwSizeHid as usize, + hid.dwCount as usize, + hid.bRawData.as_ptr(), + ) + }; + let name = lookup_name(h_device as usize); + let ms = START.get().map_or(0, |start| start.elapsed().as_millis()); + for i in 0..count { + // SAFETY: bRawData holds dwCount packed reports of dwSizeHid bytes + // inside the buffer Windows sized for us. + let report = unsafe { std::slice::from_raw_parts(data_ptr.add(i * each), each) }; + let hex = crate::cmd::diag::hex_dump(report); + println!("[{ms:>7}ms] {name} len={each}: {hex}"); + } + } + + fn lookup_name(handle: usize) -> String { + if let Some(name) = device_names() + .lock() + .ok() + .and_then(|map| map.get(&handle).cloned()) + { + return name; + } + let mut len = 0u32; + // SAFETY: sizing call, then bounded fetch into a matching buffer. + let name = unsafe { + GetRawInputDeviceInfoW(handle as _, RIDI_DEVICENAME, null_mut(), &raw mut len); + let mut buf = vec![0u16; len as usize]; + let got = GetRawInputDeviceInfoW( + handle as _, + RIDI_DEVICENAME, + buf.as_mut_ptr().cast(), + &raw mut len, + ); + if got == u32::MAX || got == 0 { + format!("hdev={handle:x}") + } else { + let full = String::from_utf16_lossy(&buf[..got as usize]); + let full = full.trim_end_matches('\0'); + // Announce the full path once; per-report lines carry the + // discriminating VID/PID/interface segment. + println!("device hdev={handle:x}: {full}"); + let core: String = full + .split('#') + .nth(1) + .unwrap_or(full) + .chars() + .take(40) + .collect(); + core + } + }; + if let Ok(mut map) = device_names().lock() { + map.insert(handle, name.clone()); + } + name + } +} diff --git a/crates/openlogi-core/src/binding.rs b/crates/openlogi-core/src/binding.rs index 97ddea09..ce73cde4 100644 --- a/crates/openlogi-core/src/binding.rs +++ b/crates/openlogi-core/src/binding.rs @@ -51,13 +51,18 @@ pub enum ButtonId { /// The HID++ gesture button on MX-line devices. The press itself /// fires the bound action; swipe directions are P1.5 territory. GestureButton, + /// The MX Master 4 Action Ring pad — the force-sensitive ridged thumb pad, + /// captured over HID++ analytics events. With the default [`Binding::Ring`] + /// a tap opens the on-screen ring; bound to a [`Binding::Single`] action, a + /// tap fires that action directly instead. + ActionRing, } impl ButtonId { /// Every rebindable button in declaration (physical front-to-side) order — /// the iteration source for default-binding seeding and the popover /// trigger list. - pub const ALL: [ButtonId; 10] = [ + pub const ALL: [ButtonId; 11] = [ ButtonId::LeftClick, ButtonId::RightClick, ButtonId::MiddleClick, @@ -68,6 +73,7 @@ impl ButtonId { ButtonId::ThumbwheelScrollUp, ButtonId::ThumbwheelScrollDown, ButtonId::GestureButton, + ButtonId::ActionRing, ]; /// Whether this button is one the OS hook (macOS `CGEventTap` / Linux evdev) @@ -99,6 +105,7 @@ impl ButtonId { ButtonId::ThumbwheelScrollUp => "Thumb Wheel Up", ButtonId::ThumbwheelScrollDown => "Thumb Wheel Down", ButtonId::GestureButton => "Gesture Button", + ButtonId::ActionRing => "Action Ring", } } } @@ -174,6 +181,102 @@ impl fmt::Display for GestureDirection { } } +/// One of the eight sectors of the on-screen Action Ring, clockwise from the +/// top. The names are compass points — deliberately disjoint from every +/// [`Action`] variant name *and* every [`GestureDirection`] name, because the +/// untagged [`Binding`] routing distinguishes its arms purely by key names +/// (see the [`Binding`] serialization notes). +/// +/// Variant identifiers are TOML-stable: renames are migration events. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] +pub enum RingSlot { + /// Straight up (12 o'clock). + North, + /// Up-right (1:30). + NorthEast, + /// Right (3 o'clock). + East, + /// Down-right (4:30). + SouthEast, + /// Straight down (6 o'clock). + South, + /// Down-left (7:30). + SouthWest, + /// Left (9 o'clock). + West, + /// Up-left (10:30). + NorthWest, +} + +impl RingSlot { + /// All eight slots, clockwise from the top — the iteration source for + /// default seeding and the overlay's sector layout. + pub const ALL: [RingSlot; 8] = [ + RingSlot::North, + RingSlot::NorthEast, + RingSlot::East, + RingSlot::SouthEast, + RingSlot::South, + RingSlot::SouthWest, + RingSlot::West, + RingSlot::NorthWest, + ]; + + /// Human-readable label for tooltips and the binding UI. + #[must_use] + pub fn label(self) -> &'static str { + match self { + RingSlot::North => "Top", + RingSlot::NorthEast => "Top Right", + RingSlot::East => "Right", + RingSlot::SouthEast => "Bottom Right", + RingSlot::South => "Bottom", + RingSlot::SouthWest => "Bottom Left", + RingSlot::West => "Left", + RingSlot::NorthWest => "Top Left", + } + } + + /// Arrow glyph for compact list rendering, pointing at the slot's + /// position on the ring. + #[must_use] + pub fn glyph(self) -> &'static str { + match self { + RingSlot::North => "↑", + RingSlot::NorthEast => "↗", + RingSlot::East => "→", + RingSlot::SouthEast => "↘", + RingSlot::South => "↓", + RingSlot::SouthWest => "↙", + RingSlot::West => "←", + RingSlot::NorthWest => "↖", + } + } + + /// The slot's centre angle in degrees, measured clockwise from straight + /// up — the overlay's sector geometry (each sector spans ±22.5° around + /// this). + #[must_use] + pub fn angle_degrees(self) -> f32 { + match self { + RingSlot::North => 0.0, + RingSlot::NorthEast => 45.0, + RingSlot::East => 90.0, + RingSlot::SouthEast => 135.0, + RingSlot::South => 180.0, + RingSlot::SouthWest => 225.0, + RingSlot::West => 270.0, + RingSlot::NorthWest => 315.0, + } + } +} + +impl fmt::Display for RingSlot { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.label()) + } +} + /// Grouping for popover section headers. /// /// Used by [`Action::category`] and rendered as a small muted label above @@ -363,6 +466,197 @@ pub enum Action { /// The `display` field is used by [`Action::label`] so the popover /// shows the user-friendly chord name. CustomShortcut(KeyCombo), + + /// Open a URL, file, or program — the Options+ "Run" action. + /// + /// The payload is the target optionally followed by `||` and an argument + /// string (`"C:\tool.exe||--flag value"`), the same convention Options+ + /// documents in its Run editor; split it with [`split_run_target`]. + /// On Windows `%VAR%` environment references in either half expand at + /// fire time. + Run(String), + + /// Type a fixed text snippet wherever the caret is — the Options+ + /// "Paste Text" action. Synthesized as Unicode key events rather than a + /// clipboard round-trip, so the user's clipboard is never clobbered. + PasteText(String), + + /// A sub-ring — the Options+ ring "Folder": firing this slot swaps the + /// on-screen ring to the nested actions instead of executing anything + /// (the overlay resolves it; it never reaches the injector). Sparse maps + /// are fine — empty positions just don't render. One level deep by + /// convention: the editor only offers folders at the top level, and the + /// overlay treats a folder nested inside a folder as a plain (warned, + /// ignored) leaf. + Folder(BTreeMap), + + /// A user-labelled wrapper — the Options+ card name. `Run`/`PasteText`/ + /// `CustomShortcut` payloads are what the machine does; this is what the + /// user calls it ("Wispr Voice", not `⊞⌃Space`). Purely presentational: + /// every consumer dispatches [`Action::inner`], so a name can be added + /// or removed without changing behaviour. + Named { + /// Display label. Empty falls back to the wrapped action's own + /// label, so a blanked name is not a blank slot. + name: String, + /// What actually runs. + action: Box, + }, +} + +impl Action { + /// The action stripped of any [`Action::Named`] wrappers — what every + /// dispatcher should execute. Loops rather than recurses so an + /// accidentally double-wrapped action still resolves. + #[must_use] + pub fn inner(&self) -> &Action { + let mut current = self; + while let Action::Named { action, .. } = current { + current = action; + } + current + } + + /// The user-chosen name, if this action carries one. + #[must_use] + pub fn display_name(&self) -> Option<&str> { + match self { + Action::Named { name, .. } if !name.is_empty() => Some(name), + _ => None, + } + } + + /// Wrap in (or, with an empty `name`, strip) a [`Action::Named`] label, + /// never stacking one wrapper on another. + #[must_use] + pub fn with_name(self, name: &str) -> Action { + let inner = self.inner().clone(); + if name.is_empty() { + inner + } else { + Action::Named { + name: name.to_owned(), + action: Box::new(inner), + } + } + } +} + +/// Split an [`Action::Run`] payload into its target and optional argument +/// string at the first `||`, trimming whitespace around both halves. An +/// empty argument half (`"app||"`) collapses to `None`. +#[must_use] +pub fn split_run_target(payload: &str) -> (&str, Option<&str>) { + match payload.split_once("||") { + Some((target, args)) => { + let args = args.trim(); + ( + target.trim(), + if args.is_empty() { None } else { Some(args) }, + ) + } + None => (payload.trim(), None), + } +} + +/// Map one non-modifier chord token to its macOS virtual key code (the +/// [`KeyCombo`] storage format) plus its canonical display spelling. +fn parse_key_name(token: &str) -> Option<(u16, String)> { + let lower = token.to_ascii_lowercase(); + // Letters and digits: canonical form is the uppercase letter / digit. + if lower.len() == 1 { + let ch = lower.chars().next()?; + let code = match ch { + 'a' => 0x00, + 's' => 0x01, + 'd' => 0x02, + 'f' => 0x03, + 'h' => 0x04, + 'g' => 0x05, + 'z' => 0x06, + 'x' => 0x07, + 'c' => 0x08, + 'v' => 0x09, + 'b' => 0x0B, + 'q' => 0x0C, + 'w' => 0x0D, + 'e' => 0x0E, + 'r' => 0x0F, + 'y' => 0x10, + 't' => 0x11, + 'u' => 0x20, + 'i' => 0x22, + 'o' => 0x1F, + 'p' => 0x23, + 'j' => 0x26, + 'k' => 0x28, + 'l' => 0x25, + 'm' => 0x2E, + 'n' => 0x2D, + '0' => 0x1D, + '1' => 0x12, + '2' => 0x13, + '3' => 0x14, + '4' => 0x15, + '5' => 0x17, + '6' => 0x16, + '7' => 0x1A, + '8' => 0x1C, + '9' => 0x19, + _ => return None, + }; + return Some((code, ch.to_ascii_uppercase().to_string())); + } + let (code, canonical) = match lower.as_str() { + "space" => (0x31, "Space"), + "enter" | "return" => (0x24, "Enter"), + "tab" => (0x30, "Tab"), + "escape" | "esc" => (0x35, "Escape"), + "backspace" => (0x33, "Backspace"), + "delete" | "del" => (0x75, "Delete"), + "home" => (0x73, "Home"), + "end" => (0x77, "End"), + "pageup" => (0x74, "PageUp"), + "pagedown" => (0x79, "PageDown"), + "up" => (0x7E, "Up"), + "down" => (0x7D, "Down"), + "left" => (0x7B, "Left"), + "right" => (0x7C, "Right"), + "f1" => (0x7A, "F1"), + "f2" => (0x78, "F2"), + "f3" => (0x63, "F3"), + "f4" => (0x76, "F4"), + "f5" => (0x60, "F5"), + "f6" => (0x61, "F6"), + "f7" => (0x62, "F7"), + "f8" => (0x64, "F8"), + "f9" => (0x65, "F9"), + "f10" => (0x6D, "F10"), + "f11" => (0x67, "F11"), + "f12" => (0x6F, "F12"), + _ => return None, + }; + Some((code, canonical.to_string())) +} + +/// Short human name for a [`Action::Run`] target — the host for URLs, the +/// file stem for paths, the raw target otherwise — truncated so slot labels +/// stay readable. +fn run_target_short_name(payload: &str) -> String { + let (target, _) = split_run_target(payload); + let short = if let Some((_, rest)) = target.split_once("://") { + rest.split(['/', '?']).next().unwrap_or(rest) + } else { + std::path::Path::new(target) + .file_stem() + .and_then(|stem| stem.to_str()) + .unwrap_or(target) + }; + let mut out: String = short.chars().take(24).collect(); + if short.chars().count() > 24 { + out.push('…'); + } + out } /// A modifier + virtual-key keystroke captured by the P1.3 recorder UI or @@ -391,6 +685,60 @@ pub struct KeyCombo { } impl KeyCombo { + /// Parse a human `"Win+Ctrl+Space"`-style chord: `+`-separated modifier + /// names (`Ctrl`/`Control`, `Shift`, `Alt`/`Option`, `Win`/`Super`/ + /// `Meta`, `Cmd`/`Command`; case-insensitive) followed by exactly one + /// key — a letter, digit, `F1`–`F12`, or a named key (`Space`, `Enter`/ + /// `Return`, `Tab`, `Escape`/`Esc`, `Backspace`, `Delete`, `Home`, + /// `End`, `PageUp`, `PageDown`, `Up`, `Down`, `Left`, `Right`). The + /// stored `display` is the canonical re-rendering of what was parsed, + /// so labels stay consistent regardless of input casing or order. + #[must_use] + pub fn parse(text: &str) -> Option { + let mut modifiers = 0u8; + let mut key: Option<(u16, String)> = None; + for token in text.split('+') { + let token = token.trim(); + if token.is_empty() { + return None; + } + match token.to_ascii_lowercase().as_str() { + "ctrl" | "control" => modifiers |= Self::MOD_CTRL, + "shift" => modifiers |= Self::MOD_SHIFT, + "alt" | "option" => modifiers |= Self::MOD_OPTION, + "win" | "windows" | "super" | "meta" => modifiers |= Self::MOD_WIN, + "cmd" | "command" => modifiers |= Self::MOD_CMD, + _ => { + // Exactly one non-modifier token, and it must be last. + if key.is_some() { + return None; + } + key = Some(parse_key_name(token)?); + } + } + } + let (key_code, canonical_key) = key?; + let mut display = String::new(); + for (bit, name) in [ + (Self::MOD_WIN, "Win"), + (Self::MOD_CTRL, "Ctrl"), + (Self::MOD_OPTION, "Alt"), + (Self::MOD_SHIFT, "Shift"), + (Self::MOD_CMD, "Cmd"), + ] { + if modifiers & bit != 0 { + display.push_str(name); + display.push('+'); + } + } + display.push_str(&canonical_key); + Some(Self { + modifiers, + key_code, + display, + }) + } + /// Bit for the ⌘ Command modifier in [`Self::modifiers`]. pub const MOD_CMD: u8 = 1 << 0; /// Bit for the ⇧ Shift modifier in [`Self::modifiers`]. @@ -399,6 +747,12 @@ impl KeyCombo { pub const MOD_CTRL: u8 = 1 << 2; /// Bit for the ⌥ Option/Alt modifier in [`Self::modifiers`]. pub const MOD_OPTION: u8 = 1 << 3; + /// Bit for the ⊞ Windows / Super modifier in [`Self::modifiers`]. + /// + /// Appended for shortcuts like Win+Ctrl+Space that macOS's four + /// modifiers cannot express. Injection maps it to `VK_LWIN` on Windows + /// and Super/Meta on Linux; macOS treats it as ⌘ (the closest key). + pub const MOD_WIN: u8 = 1 << 4; /// Build the human-readable label from the modifier bitmask + key code. /// Falls back to `"⌘key 0xNN"` when the key code isn't one of the @@ -410,6 +764,9 @@ impl KeyCombo { return self.display.clone(); } let mut out = String::new(); + if self.modifiers & Self::MOD_WIN != 0 { + out.push('⊞'); + } if self.modifiers & Self::MOD_CTRL != 0 { out.push('⌃'); } @@ -466,15 +823,18 @@ impl KeyCombo { /// table keyed by [`GestureDirection`] names (`Up`/`Down`/`Left`/`Right`/ /// `Click`). /// -/// The two arms are disambiguated by the **zero overlap** between [`Action`] -/// variant names and [`GestureDirection`] variant names — untagged tries -/// `Single(Action)` first, and a table keyed by `Up` etc. cannot parse as an -/// externally-tagged `Action`, so it falls through to `Gesture`. A payload -/// action like `{ SetDpiPreset = 2 }` is a valid externally-tagged `Action`, so -/// it stays `Single` and never reaches the `Gesture` arm. This invariant is the -/// entire safety basis for untagged routing; the `binding_untagged_*` tests -/// guard it (a future `Action` named `Up`/`Down`/`Left`/`Right`/`Click` would -/// silently mis-route, and those tests would fail). +/// The arms are disambiguated by the **zero overlap** between [`Action`] +/// variant names, [`GestureDirection`] variant names, and [`RingSlot`] variant +/// names — untagged tries `Single(Action)` first; a table keyed by `Up` etc. +/// cannot parse as an externally-tagged `Action`, so it falls through to +/// `Gesture`; a table keyed by compass names (`North` etc.) fails both and +/// lands on `Ring`. A payload action like `{ SetDpiPreset = 2 }` is a valid +/// externally-tagged `Action`, so it stays `Single` and never reaches the map +/// arms. This invariant is the entire safety basis for untagged routing; the +/// `binding_*_routes_*` tests guard it (a future `Action` named after a +/// direction or compass point — or a [`RingSlot`] named like a +/// [`GestureDirection`] — would silently mis-route, and those tests would +/// fail). #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(untagged)] pub enum Binding { @@ -484,6 +844,12 @@ pub enum Binding { /// committed swipe direction, with [`GestureDirection::Click`] holding the /// plain-click (no-swipe) action. Gesture(BTreeMap), + /// Per-sector sub-bindings for the Action Ring pad: a tap opens the + /// on-screen ring and the second tap fires the hovered sector's action. + /// Appended after [`Gesture`](Binding::Gesture) — untagged tries arms in + /// order, so an **empty** table keeps routing to `Gesture` as it always + /// has (ring maps are seeded with all eight slots and are never empty). + Ring(BTreeMap), } impl Binding { @@ -493,6 +859,10 @@ impl Binding { /// when a gesture binding has no explicit `Click`. /// /// Lets the click-dispatch path stay binding-shape-agnostic. + /// + /// A [`Ring`](Binding::Ring) binding has no click action: the tap's job is + /// opening the on-screen ring (driven off the binding shape, not an + /// [`Action`]), so the single-action projection is [`Action::None`]. #[must_use] pub fn click_action(&self) -> Action { match self { @@ -501,19 +871,30 @@ impl Binding { .get(&GestureDirection::Click) .cloned() .unwrap_or(Action::None), + Binding::Ring(_) => Action::None, } } /// The action bound to `direction`, if this is a gesture binding. - /// [`Single`](Binding::Single) has no directions and returns `None`. + /// The other arms have no directions and return `None`. #[must_use] pub fn direction_action(&self, direction: GestureDirection) -> Option<&Action> { match self { - Binding::Single(_) => None, + Binding::Single(_) | Binding::Ring(_) => None, Binding::Gesture(map) => map.get(&direction), } } + /// The action bound to `slot`, if this is a ring binding. The other arms + /// have no slots and return `None`. + #[must_use] + pub fn ring_action(&self, slot: RingSlot) -> Option<&Action> { + match self { + Binding::Single(_) | Binding::Gesture(_) => None, + Binding::Ring(map) => map.get(&slot), + } + } + /// Whether this binding drives raw-XY swipe capture (the /// [`Gesture`](Binding::Gesture) arm). #[must_use] @@ -521,6 +902,13 @@ impl Binding { matches!(self, Binding::Gesture(_)) } + /// Whether a tap on this binding's button opens the on-screen ring (the + /// [`Ring`](Binding::Ring) arm). + #[must_use] + pub fn is_ring(&self) -> bool { + matches!(self, Binding::Ring(_)) + } + /// Promote a [`Single`](Binding::Single) binding in place to a /// [`Gesture`](Binding::Gesture), keeping its action as the /// [`GestureDirection::Click`] entry and leaving the swipe arms unbound. @@ -547,6 +935,19 @@ impl Binding { } } } + + /// Fill any unbound slots of a [`Ring`](Binding::Ring) binding with their + /// canonical [`default_ring_binding`], so the overlay always renders a full + /// eight-sector ring even from a hand-edited sparse config. A no-op on the + /// other arms and on slots already bound. + pub fn fill_ring_defaults(&mut self) { + if let Binding::Ring(map) = self { + for slot in RingSlot::ALL { + map.entry(slot) + .or_insert_with(|| default_ring_binding(slot)); + } + } + } } impl From for Binding { @@ -609,6 +1010,36 @@ impl Action { Action::HorizontalScrollLeft => "Scroll Left".into(), Action::HorizontalScrollRight => "Scroll Right".into(), Action::CustomShortcut(combo) => combo.rendered_label(), + Action::Run(payload) => { + format!("Run: {}", run_target_short_name(payload)) + } + Action::PasteText(text) => { + let mut snippet: String = text + .lines() + .next() + .unwrap_or_default() + .chars() + .take(18) + .collect(); + if snippet.chars().count() < text.chars().count() { + snippet.push('…'); + } + format!("Paste: {snippet}") + } + Action::Folder(items) => { + let filled = items + .values() + .filter(|action| !matches!(action, Action::None)) + .count(); + format!("Folder ({filled})") + } + Action::Named { name, action } => { + if name.is_empty() { + action.label() + } else { + name.clone() + } + } } } @@ -621,8 +1052,9 @@ impl Action { | Action::MiddleClick | Action::MouseBack | Action::MouseForward => Category::Mouse, - // CustomShortcut is assigned to Editing so it doesn't need a - // separate arm (it's not in the picker catalog). + // CustomShortcut and PasteText are assigned to Editing, Run to + // System, so they don't need separate arms (none are in the + // picker catalog — they're entered via dedicated editor rows). Action::Copy | Action::Paste | Action::Cut @@ -631,7 +1063,8 @@ impl Action { | Action::SelectAll | Action::Find | Action::Save - | Action::CustomShortcut(_) => Category::Editing, + | Action::CustomShortcut(_) + | Action::PasteText(_) => Category::Editing, Action::BrowserBack | Action::BrowserForward | Action::NewTab @@ -646,9 +1079,12 @@ impl Action { | Action::NextDesktop | Action::ShowDesktop | Action::LaunchpadShow => Category::Navigation, - Action::None | Action::LockScreen | Action::Screenshot | Action::CaptureRegion => { - Category::System - } + Action::None + | Action::LockScreen + | Action::Screenshot + | Action::CaptureRegion + | Action::Run(_) + | Action::Folder(_) => Category::System, Action::PlayPause | Action::NextTrack | Action::PrevTrack @@ -662,13 +1098,18 @@ impl Action { | Action::ScrollDown | Action::HorizontalScrollLeft | Action::HorizontalScrollRight => Category::Scroll, + // A label doesn't change what an action is. + Action::Named { action, .. } => action.category(), } } /// All pickable actions in a deterministic order. /// - /// [`Action::CustomShortcut`] is intentionally excluded — it is opened via - /// "Record shortcut…" (P1.3), not selected from the catalog. + /// [`Action::CustomShortcut`], [`Action::Run`], [`Action::PasteText`] + /// and [`Action::Folder`] are intentionally excluded — they carry + /// payloads and are entered via their dedicated editor rows ("Record + /// shortcut…", "Run…", "Paste text…", "Folder…"), not selected from the + /// catalog. #[must_use] pub fn catalog() -> Vec { vec![ @@ -758,6 +1199,10 @@ pub fn default_binding(button: ButtonId) -> Action { ButtonId::ThumbwheelScrollUp => Action::HorizontalScrollRight, ButtonId::ThumbwheelScrollDown => Action::HorizontalScrollLeft, ButtonId::GestureButton => Action::MissionControl, + // Vestigial like GestureButton's entry: the Action Ring defaults to + // Binding::Ring (see default_binding_for), whose tap opens the ring + // rather than firing a single action. + ButtonId::ActionRing => Action::None, } } @@ -775,6 +1220,24 @@ pub fn default_gesture_binding(direction: GestureDirection) -> Action { } } +/// Per-sector defaults for the Action Ring: opposing pairs (copy/paste, +/// undo/redo) on the cardinal slots, with capture, media, and window controls +/// on the diagonals — a productivity set in the spirit of the Options+ ring, +/// shown on first run until the user rebinds the slots. +#[must_use] +pub fn default_ring_binding(slot: RingSlot) -> Action { + match slot { + RingSlot::North => Action::Copy, + RingSlot::NorthEast => Action::CaptureRegion, + RingSlot::East => Action::Redo, + RingSlot::SouthEast => Action::PlayPause, + RingSlot::South => Action::Paste, + RingSlot::SouthWest => Action::ShowDesktop, + RingSlot::West => Action::Undo, + RingSlot::NorthWest => Action::MissionControl, + } +} + /// The canonical default [`Binding`] for a fresh button in the merged model. /// /// [`ButtonId::GestureButton`] defaults to [`Binding::Gesture`] populated from @@ -797,6 +1260,12 @@ pub fn default_binding_for(button: ButtonId) -> Binding { .map(|d| (d, default_gesture_binding(d))) .collect(), ), + ButtonId::ActionRing => Binding::Ring( + RingSlot::ALL + .into_iter() + .map(|s| (s, default_ring_binding(s))) + .collect(), + ), other => Binding::Single(default_binding(other)), } } @@ -837,12 +1306,166 @@ mod tests { let catalog = Action::catalog(); for action in &catalog { assert!( - !matches!(action, Action::CustomShortcut(_)), - "catalog must not contain CustomShortcut" + !matches!( + action, + Action::CustomShortcut(_) + | Action::Run(_) + | Action::PasteText(_) + | Action::Folder(_) + | Action::Named { .. } + ), + "catalog must not contain payload-carrying editor actions" ); } } + #[test] + fn folder_roundtrips_inside_a_ring_and_labels_by_filled_count() { + let folder = Action::Folder(BTreeMap::from([ + (RingSlot::North, Action::PasteText("4 Tracks".into())), + (RingSlot::East, Action::Run("https://chatgpt.com/".into())), + (RingSlot::South, Action::None), + ])); + assert_eq!(folder.label(), "Folder (2)", "None entries are hidden"); + + let mut ring: BTreeMap = RingSlot::ALL + .into_iter() + .map(|s| (s, default_ring_binding(s))) + .collect(); + ring.insert(RingSlot::NorthEast, folder.clone()); + let mut bindings = BTreeMap::new(); + bindings.insert(ButtonId::ActionRing, Binding::Ring(ring.clone())); + let back = binding_roundtrip(bindings); + assert_eq!(back[&ButtonId::ActionRing], Binding::Ring(ring)); + + // The untagged router must still land a bare `{ Folder = … }` table + // on Single, not mistake it for a one-entry Gesture/Ring map. + let parsed = toml::from_str::( + "bindings.Forward = { Folder = { North = \"Copy\" } }", + ) + .expect("deserialize"); + assert!(matches!( + parsed.bindings[&ButtonId::Forward], + Binding::Single(Action::Folder(_)) + )); + } + + #[test] + fn named_labels_by_name_but_stays_the_wrapped_action() { + let named = Action::Run("https://gemini.google.com/".into()).with_name("Rephrase"); + assert_eq!(named.label(), "Rephrase"); + assert_eq!(named.display_name(), Some("Rephrase")); + assert_eq!( + named.inner(), + &Action::Run("https://gemini.google.com/".into()), + "dispatch sees through the label" + ); + assert_eq!( + named.category(), + Action::Run(String::new()).category(), + "a label does not re-categorize" + ); + + // Renaming replaces the wrapper instead of stacking one. + let renamed = named.with_name("Gemini"); + assert_eq!(renamed.display_name(), Some("Gemini")); + assert_eq!( + renamed.inner(), + &Action::Run("https://gemini.google.com/".into()) + ); + // An empty name unwraps rather than showing a blank slot. + assert_eq!( + renamed.with_name(""), + Action::Run("https://gemini.google.com/".into()) + ); + // An empty name inside a stored action still renders something. + let blank = Action::Named { + name: String::new(), + action: Box::new(Action::Copy), + }; + assert_eq!(blank.label(), "Copy"); + assert_eq!(blank.display_name(), None); + } + + #[test] + fn named_roundtrips_through_toml() { + let bindings = BTreeMap::from([( + ButtonId::Forward, + Binding::Single(Action::PasteText("hi".into()).with_name("Greeting")), + )]); + let back = binding_roundtrip(bindings); + assert_eq!( + back[&ButtonId::Forward], + Binding::Single(Action::PasteText("hi".into()).with_name("Greeting")) + ); + } + + #[test] + fn key_combo_parse_accepts_chords_and_rejects_garbage() { + let combo = KeyCombo::parse("win + ctrl + space").expect("valid chord"); + assert_eq!(combo.modifiers, KeyCombo::MOD_WIN | KeyCombo::MOD_CTRL); + assert_eq!(combo.key_code, 0x31); + assert_eq!(combo.display, "Win+Ctrl+Space"); + + let combo = KeyCombo::parse("Alt+Shift+z").expect("valid chord"); + assert_eq!(combo.modifiers, KeyCombo::MOD_OPTION | KeyCombo::MOD_SHIFT); + assert_eq!(combo.key_code, 0x06); + assert_eq!(combo.display, "Alt+Shift+Z"); + + assert_eq!(KeyCombo::parse("F5").map(|c| c.key_code), Some(0x60)); + // Bare modifiers, two keys, unknown names, empties: all rejected. + assert!(KeyCombo::parse("Ctrl+Shift").is_none()); + assert!(KeyCombo::parse("A+B").is_none()); + assert!(KeyCombo::parse("Ctrl+Wibble").is_none()); + assert!(KeyCombo::parse("").is_none()); + assert!(KeyCombo::parse("Ctrl++A").is_none()); + } + + #[test] + fn key_combo_win_modifier_renders_first() { + let combo = KeyCombo { + modifiers: KeyCombo::MOD_WIN | KeyCombo::MOD_CTRL, + key_code: 0x08, + display: String::new(), + }; + assert_eq!(combo.rendered_label(), "⊞⌃C"); + } + + #[test] + fn split_run_target_handles_args_and_whitespace() { + assert_eq!( + split_run_target("https://gemini.google.com/"), + ("https://gemini.google.com/", None) + ); + assert_eq!( + split_run_target(r"C:\tools\wispr.exe || --toggle voice"), + (r"C:\tools\wispr.exe", Some("--toggle voice")) + ); + // An empty argument half collapses to None. + assert_eq!(split_run_target("notepad.exe||"), ("notepad.exe", None)); + // Only the FIRST `||` splits — later ones belong to the arguments. + assert_eq!(split_run_target("a.exe||x||y"), ("a.exe", Some("x||y"))); + } + + #[test] + fn run_and_paste_labels_stay_short_and_readable() { + assert_eq!( + Action::Run("https://gemini.google.com/app?q=1".into()).label(), + "Run: gemini.google.com" + ); + assert_eq!( + Action::Run(r"C:\Program Files\Wispr\wispr.exe||--paste".into()).label(), + "Run: wispr" + ); + assert_eq!( + Action::PasteText("Build Phase Two".into()).label(), + "Paste: Build Phase Two" + ); + // Long / multi-line text truncates with an ellipsis marker. + let long = Action::PasteText("Please write a draft response to this\nsecond line".into()); + assert_eq!(long.label(), "Paste: Please write a dra…"); + } + // ── Binding (merged model) serde routing ────────────────────────────────── /// On-disk shape: a `ButtonId` → [`Binding`] map, as `DeviceConfig.bindings` @@ -919,6 +1542,105 @@ mod tests { } } + #[test] + fn binding_ring_roundtrips() { + let map: BTreeMap = RingSlot::ALL + .into_iter() + .map(|s| (s, default_ring_binding(s))) + .collect(); + let mut bindings = BTreeMap::new(); + bindings.insert(ButtonId::ActionRing, Binding::Ring(map.clone())); + let back = binding_roundtrip(bindings); + assert_eq!(back[&ButtonId::ActionRing], Binding::Ring(map)); + } + + /// The ring-side untagged-routing guard, including the sparse case: a table + /// keyed by ANY single [`RingSlot`] name must land on [`Binding::Ring`] — + /// never parse as a valid externally-tagged [`Action`] (which would route + /// `Single`) and never satisfy the [`GestureDirection`]-keyed map (which + /// would route `Gesture`). A collision in either namespace fails here. + #[test] + fn binding_ring_slot_keyed_table_routes_to_ring() { + for slot in RingSlot::ALL { + let toml = format!("bindings.ActionRing.{slot:?} = \"None\""); + let parsed = toml::from_str::(&toml).expect("deserialize"); + assert!( + matches!(parsed.bindings[&ButtonId::ActionRing], Binding::Ring(_)), + "a {slot:?}-keyed table must route to Ring, not Single/Gesture" + ); + } + } + + /// The payload variants added for Options+ parity (`Run`, `PasteText`) + /// serialize as single-key tables (`{ Run = "…" }`) — the untagged router + /// must still land them on [`Binding::Single`], not mistake them for a + /// one-entry Gesture/Ring map. Their variant names live in the same + /// namespace as [`GestureDirection`] and [`RingSlot`] keys, so a rename + /// on either side shows up here. + #[test] + fn binding_payload_variant_tables_route_to_single() { + for toml in [ + "bindings.Forward = { Run = \"https://gemini.google.com/\" }", + "bindings.Forward = { PasteText = \"Build Phase Two\" }", + ] { + let parsed = toml::from_str::(toml).expect("deserialize"); + assert!( + matches!(parsed.bindings[&ButtonId::Forward], Binding::Single(_)), + "{toml} must route to Single" + ); + } + let roundtrip = binding_roundtrip(BTreeMap::from([ + ( + ButtonId::Back, + Binding::Single(Action::Run("notepad.exe||readme.txt".into())), + ), + ( + ButtonId::Forward, + Binding::Single(Action::PasteText("Master Spec".into())), + ), + ])); + assert_eq!( + roundtrip[&ButtonId::Back], + Binding::Single(Action::Run("notepad.exe||readme.txt".into())) + ); + assert_eq!( + roundtrip[&ButtonId::Forward], + Binding::Single(Action::PasteText("Master Spec".into())) + ); + } + + #[test] + fn ring_default_covers_every_slot_and_projects_no_click_action() { + let binding = default_binding_for(ButtonId::ActionRing); + let Binding::Ring(map) = &binding else { + panic!("ActionRing must default to a Ring binding, got {binding:?}"); + }; + assert_eq!(map.len(), RingSlot::ALL.len(), "all eight slots seeded"); + // The pad's tap opens the ring — the single-action projection the + // agent-side dispatch reads must be a no-op, or a tap would both open + // the ring and fire an action. + assert_eq!(binding.click_action(), Action::None); + assert!(binding.is_ring()); + assert_eq!( + binding.ring_action(RingSlot::North), + Some(&default_ring_binding(RingSlot::North)) + ); + } + + #[test] + fn fill_ring_defaults_completes_a_sparse_map_preserving_user_choices() { + let mut sparse = BTreeMap::new(); + sparse.insert(RingSlot::East, Action::LockScreen); + let mut binding = Binding::Ring(sparse); + binding.fill_ring_defaults(); + let Binding::Ring(map) = &binding else { + panic!("fill_ring_defaults must not change the arm"); + }; + assert_eq!(map.len(), RingSlot::ALL.len()); + assert_eq!(map[&RingSlot::East], Action::LockScreen, "user choice kept"); + assert_eq!(map[&RingSlot::North], default_ring_binding(RingSlot::North)); + } + /// The collision case: a payload [`Action`] also serializes as a single-key /// table, but untagged must keep it [`Binding::Single`] (it parses as a valid /// externally-tagged `Action` before the `Gesture` arm is tried). diff --git a/crates/openlogi-core/src/config.rs b/crates/openlogi-core/src/config.rs index dead22c3..4f75b58f 100644 --- a/crates/openlogi-core/src/config.rs +++ b/crates/openlogi-core/src/config.rs @@ -34,6 +34,13 @@ use crate::paths::{self, PathsError}; /// changes; readers branch on the parsed value before consuming the rest of /// the file. /// +/// v4 adds bindings a v3 reader cannot represent: `ButtonId::ActionRing` with +/// its `Binding::Ring` slot map, and the `Run` / `PasteText` / `Folder` / +/// `Named` actions. A v3 build parsing them fails and falls back to defaults, +/// which the next save then writes over the user's real config — the exact +/// silent wipe the version gate exists to prevent, so writing any of them +/// must declare v4. +/// /// v3 changes the device map from model keys to physical-device keys. No v2 /// device entries are migrated because model-scoped settings cannot be assigned /// safely when two identical devices exist. @@ -43,7 +50,7 @@ use crate::paths::{self, PathsError}; /// `RawDeviceConfig` shim folds the legacy fields) and self-heals to v2 on the /// next save; [`Config::load_from_path`] rejects only versions *newer* than this /// so a forward file fails loudly instead of silently losing bindings. -pub const SCHEMA_VERSION: u32 = 3; +pub const SCHEMA_VERSION: u32 = 4; /// Top-level config document. #[derive(Debug, Clone, Serialize, Deserialize)] @@ -65,6 +72,12 @@ pub struct Config { /// an entry. #[serde(default)] pub devices: BTreeMap, + /// Set when this doc is a stand-in for a config file that exists but + /// could not be read (see [`Self::defaults_for_unreadable`]). Saving is + /// then refused, because writing defaults over a file we failed to parse + /// destroys the user's real settings. + #[serde(skip)] + unreadable_source: bool, } impl Default for Config { @@ -74,6 +87,7 @@ impl Default for Config { app_settings: AppSettings::default(), selected_device: None, devices: BTreeMap::new(), + unreadable_source: false, } } } @@ -141,6 +155,31 @@ impl Config { Self::load_from_path(&paths::config_path()?) } + /// Defaults to run on after [`Self::load_or_default`] failed — a config + /// file exists but is unparseable, or was written by a newer build. + /// + /// Callers must use this rather than [`Self::default`], because the + /// resulting doc **refuses to save**. Persisting plain defaults over a + /// file we could not read is what turns "this build is too old for your + /// config" into "your bindings are gone": the failing build starts up + /// blank, and its first write — any setting toggle, any device + /// re-detection — replaces the user's real settings with that blank + /// state. + #[must_use] + pub fn defaults_for_unreadable() -> Self { + Self { + unreadable_source: true, + ..Self::default() + } + } + + /// Whether this doc stands in for an unreadable file and so will not be + /// persisted (see [`Self::defaults_for_unreadable`]). + #[must_use] + pub const fn is_read_only(&self) -> bool { + self.unreadable_source + } + /// Same as [`Self::load_or_default`] but reads from `path`. Used by tests /// to avoid touching the real user config. pub fn load_from_path(path: &Path) -> Result { @@ -185,6 +224,14 @@ impl Config { /// Same as [`Self::save_atomic`] but writes to `path`. Used by tests. pub fn save_to_path(&self, path: &Path) -> Result<(), ConfigError> { + // Never let a build that couldn't read the config write over it — + // that is how an unreadable file becomes a lost one (see + // [`Self::defaults_for_unreadable`]). Not an error: the caller's save + // is genuinely unnecessary, and failing it would only surface as a + // second, more confusing symptom. + if self.unreadable_source { + return Ok(()); + } if let Some(parent) = path.parent() { fs::create_dir_all(parent).map_err(|source| ConfigError::Write { path: path.to_path_buf(), @@ -257,6 +304,93 @@ impl Config { } } + /// Records `action` for one `slot` of the Action Ring, creating the + /// device entry if needed. A missing — or single-action — `ActionRing` + /// binding is replaced by the canonical default ring first and any + /// unbound slots are seeded, so the edited map is always complete + /// (guarded by `set_ring_slot_seeds_a_complete_map`). + pub fn set_ring_slot( + &mut self, + device_key: &str, + slot: crate::binding::RingSlot, + action: Action, + ) { + let entry = self + .devices + .entry(device_key.to_string()) + .or_default() + .bindings + .entry(ButtonId::ActionRing) + .or_insert_with(|| default_binding_for(ButtonId::ActionRing)); + if !entry.is_ring() { + *entry = default_binding_for(ButtonId::ActionRing); + } + entry.fill_ring_defaults(); + if let Binding::Ring(map) = entry { + map.insert(slot, action); + } + } + + /// Converts the Action Ring `slot` into a [`Action::Folder`], keeping a + /// plain action it previously held as the folder's North entry so the + /// conversion never silently discards a binding. Idempotent: a slot that + /// already holds a folder is left untouched. + pub fn convert_ring_slot_to_folder( + &mut self, + device_key: &str, + slot: crate::binding::RingSlot, + ) { + use crate::binding::RingSlot; + let current = self.ring_slot_action(device_key, slot); + if matches!(current, Some(Action::Folder(_))) { + return; + } + let mut items = std::collections::BTreeMap::new(); + if let Some(action) = current + && action != Action::None + { + items.insert(RingSlot::North, action); + } + self.set_ring_slot(device_key, slot, Action::Folder(items)); + } + + /// Records `action` for one `sub_slot` inside the folder at `slot`, + /// converting the slot into a folder first when it holds a plain action + /// (see [`Self::convert_ring_slot_to_folder`]). + pub fn set_ring_folder_slot( + &mut self, + device_key: &str, + slot: crate::binding::RingSlot, + sub_slot: crate::binding::RingSlot, + action: Action, + ) { + self.convert_ring_slot_to_folder(device_key, slot); + let entry = self + .devices + .entry(device_key.to_string()) + .or_default() + .bindings + .entry(ButtonId::ActionRing) + .or_insert_with(|| default_binding_for(ButtonId::ActionRing)); + if let Binding::Ring(map) = entry + && let Some(Action::Folder(items)) = map.get_mut(&slot) + { + items.insert(sub_slot, action); + } + } + + /// The action currently bound to one Action Ring `slot`, if the device + /// has a ring binding at all. + fn ring_slot_action(&self, device_key: &str, slot: crate::binding::RingSlot) -> Option { + self.devices + .get(device_key) + .and_then(|device| device.bindings.get(&ButtonId::ActionRing)) + .and_then(|binding| match binding { + Binding::Ring(map) => map.get(&slot).cloned(), + _ => None, + }) + } + /// Ensure `button` on `device_key` is a [`Binding::Gesture`], creating the /// device + a default binding if needed and upgrading a [`Binding::Single`] /// in place (its action kept as the [`GestureDirection::Click`]). Returns the @@ -609,6 +743,135 @@ mod tests { assert!(cfg.devices.is_empty()); } + /// The data-loss guard: a build that cannot read the config must never + /// overwrite it. This is the exact sequence that wiped a real user's + /// bindings — an older build parsed a config carrying actions it did not + /// know, fell back to defaults, and saved those defaults back. + #[test] + fn defaults_for_an_unreadable_config_never_overwrite_it() { + let dir = tempfile::tempdir().expect("tempdir"); + let path = dir.path().join("config.toml"); + let original = "schema_version = 4\nthis is not valid toml at all\n"; + fs::write(&path, original).expect("seed"); + + let err = Config::load_from_path(&path).expect_err("must not parse"); + assert!(matches!(err, ConfigError::Parse { .. })); + + // The fallback a binary uses on that error, then a save it would + // normally perform (a settings toggle, a device re-detection). + let fallback = Config::defaults_for_unreadable(); + assert!(fallback.is_read_only()); + fallback + .save_to_path(&path) + .expect("save is a no-op, not an error"); + + assert_eq!( + fs::read_to_string(&path).expect("read back"), + original, + "the unreadable config must be left exactly as it was" + ); + + // A normally-loaded config still saves. + let ok = Config::default(); + assert!(!ok.is_read_only()); + ok.save_to_path(&path).expect("save"); + assert_ne!(fs::read_to_string(&path).expect("read back"), original); + } + + /// A newer config must be refused rather than silently reset — the + /// version gate only works if writers bump [`SCHEMA_VERSION`] whenever + /// they emit bindings older readers cannot represent. + #[test] + fn a_newer_schema_is_rejected_and_left_untouched() { + let dir = tempfile::tempdir().expect("tempdir"); + let path = dir.path().join("config.toml"); + let original = format!("schema_version = {}\n", SCHEMA_VERSION + 1); + fs::write(&path, &original).expect("seed"); + + let err = Config::load_from_path(&path).expect_err("must be refused"); + assert!(matches!(err, ConfigError::UnsupportedSchemaVersion { .. })); + + Config::defaults_for_unreadable() + .save_to_path(&path) + .expect("no-op"); + assert_eq!(fs::read_to_string(&path).expect("read back"), original); + } + + #[test] + fn folder_conversion_keeps_the_old_action_and_edits_nest() { + use crate::binding::{Action, RingSlot}; + + let mut cfg = Config::default(); + cfg.set_ring_slot("2b042", RingSlot::East, Action::LockScreen); + cfg.convert_ring_slot_to_folder("2b042", RingSlot::East); + cfg.set_ring_folder_slot( + "2b042", + RingSlot::East, + RingSlot::SouthEast, + Action::Run("https://chatgpt.com/".into()), + ); + // Converting twice must not wipe the folder. + cfg.convert_ring_slot_to_folder("2b042", RingSlot::East); + + let Some(Binding::Ring(map)) = cfg.bindings_for("2b042").remove(&ButtonId::ActionRing) + else { + panic!("ActionRing must stay ring-shaped"); + }; + let Action::Folder(items) = &map[&RingSlot::East] else { + panic!("East must hold a folder, got {:?}", map[&RingSlot::East]); + }; + assert_eq!( + items[&RingSlot::North], + Action::LockScreen, + "the pre-conversion action survives as North" + ); + assert_eq!( + items[&RingSlot::SouthEast], + Action::Run("https://chatgpt.com/".into()) + ); + + // A folder edit on a slot holding a plain action converts implicitly. + cfg.set_ring_folder_slot("2b042", RingSlot::West, RingSlot::North, Action::Copy); + let Some(Binding::Ring(map)) = cfg.bindings_for("2b042").remove(&ButtonId::ActionRing) + else { + panic!("ActionRing must stay ring-shaped"); + }; + let Action::Folder(items) = &map[&RingSlot::West] else { + panic!("West must hold a folder"); + }; + // West's default (Undo) became the folder's North; the edit then + // overwrote North with Copy — dropping nothing silently. + assert_eq!(items[&RingSlot::North], Action::Copy); + } + + #[test] + fn set_ring_slot_seeds_a_complete_map() { + use crate::binding::{RingSlot, default_ring_binding}; + + // Fresh device: one edit yields a full eight-slot ring around it. + let mut cfg = Config::default(); + cfg.set_ring_slot("2b042", RingSlot::SouthWest, Action::CaptureRegion); + let Some(Binding::Ring(map)) = cfg.bindings_for("2b042").remove(&ButtonId::ActionRing) + else { + panic!("ActionRing must be ring-shaped after a slot edit"); + }; + assert_eq!(map.len(), RingSlot::ALL.len(), "all slots seeded"); + assert_eq!(map[&RingSlot::SouthWest], Action::CaptureRegion); + assert_eq!(map[&RingSlot::North], default_ring_binding(RingSlot::North)); + + // A pad demoted to a single action is promoted back to a ring, and + // the whole map survives a save/load roundtrip. + cfg.set_binding("2b042", ButtonId::ActionRing, Action::Copy.into()); + cfg.set_ring_slot("2b042", RingSlot::East, Action::LockScreen); + let back = write_and_read(&cfg); + let Some(Binding::Ring(map)) = back.bindings_for("2b042").remove(&ButtonId::ActionRing) + else { + panic!("ring must survive the roundtrip"); + }; + assert_eq!(map[&RingSlot::East], Action::LockScreen); + assert_eq!(map.len(), RingSlot::ALL.len()); + } + #[test] fn lighting_roundtrips_per_device() { let mut cfg = Config::default(); @@ -844,7 +1107,10 @@ mod tests { // The key only contains [A-Za-z0-9_], so TOML emits it as a bare-word // table key (no surrounding quotes). The test asserts the observable // structure rather than locking in a specific quoting. - assert!(body.contains("schema_version = 3"), "got: {body}"); + assert!( + body.contains(&format!("schema_version = {SCHEMA_VERSION}")), + "got: {body}" + ); assert!(body.contains("[devices.2b042.bindings]"), "got: {body}"); // A `Single` binding serializes byte-identically to the pre-v2 bare // `Action`, so the leaf line is unchanged. @@ -1109,7 +1375,10 @@ Click = \"Paste\" // Saving self-heals to the current shape: stamped version + merged table, // legacy field names gone. let body = toml::to_string_pretty(&cfg).expect("serialize"); - assert!(body.contains("schema_version = 3"), "got: {body}"); + assert!( + body.contains(&format!("schema_version = {SCHEMA_VERSION}")), + "got: {body}" + ); assert!(body.contains("[devices.2b042.bindings]"), "got: {body}"); assert!(!body.contains("button_bindings"), "got: {body}"); assert!(!body.contains("gesture_bindings"), "got: {body}"); diff --git a/crates/openlogi-gui/Cargo.toml b/crates/openlogi-gui/Cargo.toml index 1e3f3e9d..111e1d8f 100644 --- a/crates/openlogi-gui/Cargo.toml +++ b/crates/openlogi-gui/Cargo.toml @@ -47,6 +47,9 @@ walkdir = "2.5.0" fluent-langneg = "0.14.2" backon.workspace = true opener = { workspace = true } +# The Action Ring overlay reads the raw HWND off the gpui window (same 0.6.x +# gpui itself uses, so the resolve adds an edge, not a crate). +raw-window-handle = "0.6" # Windows exe resources (app icon + VERSIONINFO) — see build.rs. The exact # version already in Cargo.lock as gpui's own build-dependency, so the resolve @@ -54,6 +57,21 @@ opener = { workspace = true } [build-dependencies] embed-resource = "3.0.9" +# Action Ring overlay window plumbing gpui doesn't expose: no-activate + +# topmost styles, show/hide without activation, the global cursor, and the +# Esc / outside-click cancel polls (see ring.rs::platform_win). +[target.'cfg(target_os = "windows")'.dependencies] +windows-sys = { workspace = true, features = [ + "Win32_Foundation", + # MonitorFromPoint / GetMonitorInfoW for the ring's work-area clamp. + "Win32_Graphics_Gdi", + # GetProcAddress for the undocumented SetWindowCompositionAttribute. + "Win32_System_LibraryLoader", + "Win32_UI_HiDpi", + "Win32_UI_Input_KeyboardAndMouse", + "Win32_UI_WindowsAndMessaging", +] } + # Menu-bar (NSStatusItem) FFI — GPUI has no status-bar API. objc2 gives typed, # `Retained`-owned AppKit bindings so the status-item code can't leak (#99). [target.'cfg(target_os = "macos")'.dependencies] diff --git a/crates/openlogi-gui/action-icons/folder.svg b/crates/openlogi-gui/action-icons/folder.svg new file mode 100644 index 00000000..47fe1aae --- /dev/null +++ b/crates/openlogi-gui/action-icons/folder.svg @@ -0,0 +1 @@ + diff --git a/crates/openlogi-gui/locales/da.yml b/crates/openlogi-gui/locales/da.yml index cf5983fb..29734ea5 100644 --- a/crates/openlogi-gui/locales/da.yml +++ b/crates/openlogi-gui/locales/da.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "DPI-skift" "Thumb Wheel": "Tommelfingerhjul" "Gesture Button": "Bevægelsesknap" +"Action Ring": "Handlingsring" +"8 actions": "8 handlinger" +"Top": "Øverst" +"Top Right": "Øverst til højre" +"Bottom Right": "Nederst til højre" +"Bottom": "Nederst" +"Bottom Left": "Nederst til venstre" +"Top Left": "Øverst til venstre" +"CUSTOM": "BRUGERDEFINERET" +"Run Command": "Kør kommando" +"Paste Text": "Indsæt tekst" +"Command or URL": "Kommando eller URL" +"Text to paste": "Tekst der skal indsættes" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "En URL, fil eller et program. Efter en programsti adskiller || argumenterne; %VAR%-miljøvariabler udvides." +"Typed at the cursor exactly as written.": "Skrives ved markøren præcis som skrevet." +"Folder": "Mappe" +"Open Folder": "Åbn mappe" +"Keyboard Shortcut": "Tastaturgenvej" +"Press Keys": "Tryk på taster" +"Name": "Navn" +"Optional — shown on the ring": "Valgfrit — vises på ringen" +"Command": "Kommando" +"Text": "Tekst" +"Shortcut": "Genvej" +"Listening…": "Lytter…" +"Press a shortcut…": "Tryk en genvej…" +"Or record it: hold the keys, then let go.": "Eller optag den: hold tasterne nede, og slip så." +"e.g. Ctrl+Shift+P": "f.eks. Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Modifikatorer adskilt med +, derefter én tast: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "Genvejen kunne ikke læses — brug formen Ctrl+Shift+P." "Up": "Op" "Down": "Ned" "Left": "Venstre" diff --git a/crates/openlogi-gui/locales/de.yml b/crates/openlogi-gui/locales/de.yml index 203108dd..d4d0c44c 100644 --- a/crates/openlogi-gui/locales/de.yml +++ b/crates/openlogi-gui/locales/de.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "DPI-Umschaltung" "Thumb Wheel": "Daumenrad" "Gesture Button": "Gestentaste" +"Action Ring": "Aktionsring" +"8 actions": "8 Aktionen" +"Top": "Oben" +"Top Right": "Oben rechts" +"Bottom Right": "Unten rechts" +"Bottom": "Unten" +"Bottom Left": "Unten links" +"Top Left": "Oben links" +"CUSTOM": "BENUTZERDEFINIERT" +"Run Command": "Befehl ausführen" +"Paste Text": "Text einfügen" +"Command or URL": "Befehl oder URL" +"Text to paste": "Einzufügender Text" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "Eine URL, Datei oder ein Programm. Nach einem Programmpfad trennt || die Argumente; %VAR%-Umgebungsvariablen werden expandiert." +"Typed at the cursor exactly as written.": "Wird an der Cursorposition genau wie geschrieben eingetippt." +"Folder": "Ordner" +"Open Folder": "Ordner öffnen" +"Keyboard Shortcut": "Tastenkombination" +"Press Keys": "Tasten drücken" +"Name": "Name" +"Optional — shown on the ring": "Optional — wird im Ring angezeigt" +"Command": "Befehl" +"Text": "Text" +"Shortcut": "Tastenkombination" +"Listening…": "Aufnahme…" +"Press a shortcut…": "Tastenkombination drücken…" +"Or record it: hold the keys, then let go.": "Oder aufnehmen: Tasten halten und dann loslassen." +"e.g. Ctrl+Shift+P": "z. B. Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Modifikatoren mit + verbunden, dann eine Taste: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "Die Tastenkombination konnte nicht gelesen werden — verwende die Form Ctrl+Shift+P." "Up": "Oben" "Down": "Unten" "Left": "Links" diff --git a/crates/openlogi-gui/locales/el.yml b/crates/openlogi-gui/locales/el.yml index 80d7156d..06fccc69 100644 --- a/crates/openlogi-gui/locales/el.yml +++ b/crates/openlogi-gui/locales/el.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "Εναλλαγή DPI" "Thumb Wheel": "Πλαϊνός τροχός" "Gesture Button": "Κουμπί χειρονομιών" +"Action Ring": "Δακτύλιος ενεργειών" +"8 actions": "8 ενέργειες" +"Top": "Επάνω" +"Top Right": "Επάνω δεξιά" +"Bottom Right": "Κάτω δεξιά" +"Bottom": "Κάτω" +"Bottom Left": "Κάτω αριστερά" +"Top Left": "Επάνω αριστερά" +"CUSTOM": "ΠΡΟΣΑΡΜΟΣΜΕΝΑ" +"Run Command": "Εκτέλεση εντολής" +"Paste Text": "Επικόλληση κειμένου" +"Command or URL": "Εντολή ή URL" +"Text to paste": "Κείμενο για επικόλληση" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "Ένα URL, αρχείο ή πρόγραμμα. Μετά τη διαδρομή προγράμματος, το || διαχωρίζει τα ορίσματα· οι μεταβλητές περιβάλλοντος %VAR% αναπτύσσονται." +"Typed at the cursor exactly as written.": "Πληκτρολογείται στον δρομέα ακριβώς όπως γράφτηκε." +"Folder": "Φάκελος" +"Open Folder": "Άνοιγμα φακέλου" +"Keyboard Shortcut": "Συντόμευση πληκτρολογίου" +"Press Keys": "Πατήστε πλήκτρα" +"Name": "Όνομα" +"Optional — shown on the ring": "Προαιρετικό — εμφανίζεται στον δακτύλιο" +"Command": "Εντολή" +"Text": "Κείμενο" +"Shortcut": "Συντόμευση" +"Listening…": "Ακρόαση…" +"Press a shortcut…": "Πατήστε μια συντόμευση…" +"Or record it: hold the keys, then let go.": "Ή καταγράψτε την: κρατήστε τα πλήκτρα και μετά αφήστε τα." +"e.g. Ctrl+Shift+P": "π.χ. Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Τροποποιητές ενωμένοι με +, μετά ένα πλήκτρο: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "Η συντόμευση δεν διαβάστηκε — χρησιμοποιήστε τη μορφή Ctrl+Shift+P." "Up": "Πάνω" "Down": "Κάτω" "Left": "Αριστερά" diff --git a/crates/openlogi-gui/locales/en.yml b/crates/openlogi-gui/locales/en.yml index e574c8c5..42fa42e3 100644 --- a/crates/openlogi-gui/locales/en.yml +++ b/crates/openlogi-gui/locales/en.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "DPI Toggle" "Thumb Wheel": "Thumb Wheel" "Gesture Button": "Gesture Button" +"Action Ring": "Action Ring" +"8 actions": "8 actions" +"Top": "Top" +"Top Right": "Top Right" +"Bottom Right": "Bottom Right" +"Bottom": "Bottom" +"Bottom Left": "Bottom Left" +"Top Left": "Top Left" +"CUSTOM": "CUSTOM" +"Run Command": "Run Command" +"Paste Text": "Paste Text" +"Command or URL": "Command or URL" +"Text to paste": "Text to paste" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand." +"Typed at the cursor exactly as written.": "Typed at the cursor exactly as written." +"Folder": "Folder" +"Open Folder": "Open Folder" +"Keyboard Shortcut": "Keyboard Shortcut" +"Press Keys": "Press Keys" +"Name": "Name" +"Optional — shown on the ring": "Optional — shown on the ring" +"Command": "Command" +"Text": "Text" +"Shortcut": "Shortcut" +"Listening…": "Listening…" +"Press a shortcut…": "Press a shortcut…" +"Or record it: hold the keys, then let go.": "Or record it: hold the keys, then let go." +"e.g. Ctrl+Shift+P": "e.g. Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "That shortcut could not be read — use the Ctrl+Shift+P shape." "Up": "Up" "Down": "Down" "Left": "Left" diff --git a/crates/openlogi-gui/locales/es.yml b/crates/openlogi-gui/locales/es.yml index 37f0c3a2..df32db76 100644 --- a/crates/openlogi-gui/locales/es.yml +++ b/crates/openlogi-gui/locales/es.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "Cambiar DPI" "Thumb Wheel": "Rueda lateral" "Gesture Button": "Botón de gestos" +"Action Ring": "Anillo de acciones" +"8 actions": "8 acciones" +"Top": "Arriba" +"Top Right": "Arriba a la derecha" +"Bottom Right": "Abajo a la derecha" +"Bottom": "Abajo" +"Bottom Left": "Abajo a la izquierda" +"Top Left": "Arriba a la izquierda" +"CUSTOM": "PERSONALIZADO" +"Run Command": "Ejecutar comando" +"Paste Text": "Pegar texto" +"Command or URL": "Comando o URL" +"Text to paste": "Texto a pegar" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "Una URL, archivo o programa. Tras la ruta del programa, || separa los argumentos; las variables de entorno %VAR% se expanden." +"Typed at the cursor exactly as written.": "Se escribe en el cursor exactamente como está." +"Folder": "Carpeta" +"Open Folder": "Abrir carpeta" +"Keyboard Shortcut": "Atajo de teclado" +"Press Keys": "Pulsar teclas" +"Name": "Nombre" +"Optional — shown on the ring": "Opcional: se muestra en el anillo" +"Command": "Comando" +"Text": "Texto" +"Shortcut": "Atajo" +"Listening…": "Escuchando…" +"Press a shortcut…": "Pulsa un atajo…" +"Or record it: hold the keys, then let go.": "O grábalo: mantén las teclas y luego suéltalas." +"e.g. Ctrl+Shift+P": "p. ej. Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Modificadores unidos con + y una tecla: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "No se pudo leer el atajo — usa la forma Ctrl+Shift+P." "Up": "Arriba" "Down": "Abajo" "Left": "Izquierda" diff --git a/crates/openlogi-gui/locales/fi.yml b/crates/openlogi-gui/locales/fi.yml index b14640ce..abe04aba 100644 --- a/crates/openlogi-gui/locales/fi.yml +++ b/crates/openlogi-gui/locales/fi.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "DPI-vaihto" "Thumb Wheel": "Peukalorulla" "Gesture Button": "Eletoiminto" +"Action Ring": "Toimintorengas" +"8 actions": "8 toimintoa" +"Top": "Ylhäällä" +"Top Right": "Oikealla ylhäällä" +"Bottom Right": "Oikealla alhaalla" +"Bottom": "Alhaalla" +"Bottom Left": "Vasemmalla alhaalla" +"Top Left": "Vasemmalla ylhäällä" +"CUSTOM": "MUKAUTETUT" +"Run Command": "Suorita komento" +"Paste Text": "Liitä teksti" +"Command or URL": "Komento tai URL" +"Text to paste": "Liitettävä teksti" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "URL, tiedosto tai ohjelma. Ohjelmapolun jälkeen || erottaa argumentit; %VAR%-ympäristömuuttujat laajennetaan." +"Typed at the cursor exactly as written.": "Kirjoitetaan kohdistimen kohtaan täsmälleen sellaisenaan." +"Folder": "Kansio" +"Open Folder": "Avaa kansio" +"Keyboard Shortcut": "Pikanäppäin" +"Press Keys": "Paina näppäimiä" +"Name": "Nimi" +"Optional — shown on the ring": "Valinnainen — näkyy renkaassa" +"Command": "Komento" +"Text": "Teksti" +"Shortcut": "Pikanäppäin" +"Listening…": "Kuunnellaan…" +"Press a shortcut…": "Paina pikanäppäintä…" +"Or record it: hold the keys, then let go.": "Tai tallenna se: pidä näppäimiä pohjassa ja päästä irti." +"e.g. Ctrl+Shift+P": "esim. Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Muokkaimet yhdistettynä +-merkillä ja yksi näppäin: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "Pikanäppäintä ei voitu lukea — käytä muotoa Ctrl+Shift+P." "Up": "Ylös" "Down": "Alas" "Left": "Vasen" diff --git a/crates/openlogi-gui/locales/fr.yml b/crates/openlogi-gui/locales/fr.yml index cdb201d9..d7cd9907 100644 --- a/crates/openlogi-gui/locales/fr.yml +++ b/crates/openlogi-gui/locales/fr.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "Bascule DPI" "Thumb Wheel": "Molette latérale" "Gesture Button": "Bouton de gestes" +"Action Ring": "Anneau d'actions" +"8 actions": "8 actions" +"Top": "Haut" +"Top Right": "En haut à droite" +"Bottom Right": "En bas à droite" +"Bottom": "Bas" +"Bottom Left": "En bas à gauche" +"Top Left": "En haut à gauche" +"CUSTOM": "PERSONNALISÉ" +"Run Command": "Exécuter une commande" +"Paste Text": "Coller du texte" +"Command or URL": "Commande ou URL" +"Text to paste": "Texte à coller" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "Une URL, un fichier ou un programme. Après le chemin du programme, || sépare les arguments ; les variables d'environnement %VAR% sont développées." +"Typed at the cursor exactly as written.": "Saisi au curseur exactement tel quel." +"Folder": "Dossier" +"Open Folder": "Ouvrir le dossier" +"Keyboard Shortcut": "Raccourci clavier" +"Press Keys": "Appuyer sur les touches" +"Name": "Nom" +"Optional — shown on the ring": "Facultatif — affiché sur l'anneau" +"Command": "Commande" +"Text": "Texte" +"Shortcut": "Raccourci" +"Listening…": "Écoute…" +"Press a shortcut…": "Appuyez sur un raccourci…" +"Or record it: hold the keys, then let go.": "Ou enregistrez-le : maintenez les touches, puis relâchez." +"e.g. Ctrl+Shift+P": "p. ex. Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Modificateurs reliés par +, puis une touche : Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "Le raccourci n'a pas pu être lu — utilisez la forme Ctrl+Shift+P." "Up": "Haut" "Down": "Bas" "Left": "Gauche" diff --git a/crates/openlogi-gui/locales/it.yml b/crates/openlogi-gui/locales/it.yml index f35d58a8..bdc1d64d 100644 --- a/crates/openlogi-gui/locales/it.yml +++ b/crates/openlogi-gui/locales/it.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "Cambia DPI" "Thumb Wheel": "Volante da pollice" "Gesture Button": "Pulsante gesture" +"Action Ring": "Anello delle azioni" +"8 actions": "8 azioni" +"Top": "In alto" +"Top Right": "In alto a destra" +"Bottom Right": "In basso a destra" +"Bottom": "In basso" +"Bottom Left": "In basso a sinistra" +"Top Left": "In alto a sinistra" +"CUSTOM": "PERSONALIZZATO" +"Run Command": "Esegui comando" +"Paste Text": "Incolla testo" +"Command or URL": "Comando o URL" +"Text to paste": "Testo da incollare" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "Un URL, file o programma. Dopo il percorso del programma, || separa gli argomenti; le variabili d'ambiente %VAR% vengono espanse." +"Typed at the cursor exactly as written.": "Digitato al cursore esattamente come scritto." +"Folder": "Cartella" +"Open Folder": "Apri cartella" +"Keyboard Shortcut": "Scorciatoia da tastiera" +"Press Keys": "Premi i tasti" +"Name": "Nome" +"Optional — shown on the ring": "Facoltativo — mostrato sull'anello" +"Command": "Comando" +"Text": "Testo" +"Shortcut": "Scorciatoia" +"Listening…": "In ascolto…" +"Press a shortcut…": "Premi una scorciatoia…" +"Or record it: hold the keys, then let go.": "Oppure registrala: tieni premuti i tasti, poi rilascia." +"e.g. Ctrl+Shift+P": "es. Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Modificatori uniti con + e un tasto: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "Impossibile leggere la scorciatoia — usa la forma Ctrl+Shift+P." "Up": "Su" "Down": "Giù" "Left": "Sinistra" diff --git a/crates/openlogi-gui/locales/ja.yml b/crates/openlogi-gui/locales/ja.yml index ba765827..f2f73302 100644 --- a/crates/openlogi-gui/locales/ja.yml +++ b/crates/openlogi-gui/locales/ja.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "DPI 切り替え" "Thumb Wheel": "サムホイール" "Gesture Button": "ジェスチャーボタン" +"Action Ring": "アクションリング" +"8 actions": "8つのアクション" +"Top": "上" +"Top Right": "右上" +"Bottom Right": "右下" +"Bottom": "下" +"Bottom Left": "左下" +"Top Left": "左上" +"CUSTOM": "カスタム" +"Run Command": "コマンドを実行" +"Paste Text": "テキストを貼り付け" +"Command or URL": "コマンドまたは URL" +"Text to paste": "貼り付けるテキスト" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "URL、ファイル、またはプログラム。プログラムのパスの後に || で引数を区切ります。%VAR% 環境変数は展開されます。" +"Typed at the cursor exactly as written.": "書かれたとおりにカーソル位置に入力されます。" +"Folder": "フォルダー" +"Open Folder": "フォルダーを開く" +"Keyboard Shortcut": "キーボードショートカット" +"Press Keys": "キーを押す" +"Name": "名前" +"Optional — shown on the ring": "任意 — リングに表示されます" +"Command": "コマンド" +"Text": "テキスト" +"Shortcut": "ショートカット" +"Listening…": "入力待ち…" +"Press a shortcut…": "ショートカットを押してください…" +"Or record it: hold the keys, then let go.": "録音もできます: キーを押したまま、離してください。" +"e.g. Ctrl+Shift+P": "例: Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "修飾キーを + でつなぎ、最後にキーを 1 つ: Ctrl+Shift+P、Win+Ctrl+Space、Alt+F4。" +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "ショートカットを読み取れませんでした。Ctrl+Shift+P の形式で入力してください。" "Up": "上" "Down": "下" "Left": "左" diff --git a/crates/openlogi-gui/locales/ko.yml b/crates/openlogi-gui/locales/ko.yml index 1f6cfa17..c85134f6 100644 --- a/crates/openlogi-gui/locales/ko.yml +++ b/crates/openlogi-gui/locales/ko.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "DPI 전환" "Thumb Wheel": "썸휠" "Gesture Button": "제스처 버튼" +"Action Ring": "액션 링" +"8 actions": "8개 동작" +"Top": "위" +"Top Right": "오른쪽 위" +"Bottom Right": "오른쪽 아래" +"Bottom": "아래" +"Bottom Left": "왼쪽 아래" +"Top Left": "왼쪽 위" +"CUSTOM": "사용자 지정" +"Run Command": "명령 실행" +"Paste Text": "텍스트 붙여넣기" +"Command or URL": "명령 또는 URL" +"Text to paste": "붙여넣을 텍스트" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "URL, 파일 또는 프로그램. 프로그램 경로 뒤에 || 로 인수를 구분합니다. %VAR% 환경 변수는 확장됩니다." +"Typed at the cursor exactly as written.": "쓰인 그대로 커서 위치에 입력됩니다." +"Folder": "폴더" +"Open Folder": "폴더 열기" +"Keyboard Shortcut": "키보드 단축키" +"Press Keys": "키 누르기" +"Name": "이름" +"Optional — shown on the ring": "선택 사항 — 링에 표시됩니다" +"Command": "명령" +"Text": "텍스트" +"Shortcut": "단축키" +"Listening…": "대기 중…" +"Press a shortcut…": "단축키를 누르세요…" +"Or record it: hold the keys, then let go.": "또는 녹화하세요: 키를 누른 채 있다가 떼세요." +"e.g. Ctrl+Shift+P": "예: Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "보조 키를 + 로 잇고 마지막에 키 하나: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "단축키를 읽을 수 없습니다 — Ctrl+Shift+P 형식을 사용하세요." "Up": "위" "Down": "아래" "Left": "왼쪽" diff --git a/crates/openlogi-gui/locales/nb.yml b/crates/openlogi-gui/locales/nb.yml index 3c74b79e..9abda612 100644 --- a/crates/openlogi-gui/locales/nb.yml +++ b/crates/openlogi-gui/locales/nb.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "DPI-veksling" "Thumb Wheel": "Tommelhjul" "Gesture Button": "Bevegelsesknapp" +"Action Ring": "Handlingsring" +"8 actions": "8 handlinger" +"Top": "Øverst" +"Top Right": "Øverst til høyre" +"Bottom Right": "Nederst til høyre" +"Bottom": "Nederst" +"Bottom Left": "Nederst til venstre" +"Top Left": "Øverst til venstre" +"CUSTOM": "EGENDEFINERT" +"Run Command": "Kjør kommando" +"Paste Text": "Lim inn tekst" +"Command or URL": "Kommando eller URL" +"Text to paste": "Tekst som skal limes inn" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "En URL, fil eller et program. Etter en programsti skiller || argumentene; %VAR%-miljøvariabler utvides." +"Typed at the cursor exactly as written.": "Skrives ved markøren nøyaktig som skrevet." +"Folder": "Mappe" +"Open Folder": "Åpne mappe" +"Keyboard Shortcut": "Hurtigtast" +"Press Keys": "Trykk taster" +"Name": "Navn" +"Optional — shown on the ring": "Valgfritt — vises på ringen" +"Command": "Kommando" +"Text": "Tekst" +"Shortcut": "Hurtigtast" +"Listening…": "Lytter…" +"Press a shortcut…": "Trykk en hurtigtast…" +"Or record it: hold the keys, then let go.": "Eller ta den opp: hold tastene, og slipp så." +"e.g. Ctrl+Shift+P": "f.eks. Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Modifikatorer koblet med +, deretter én tast: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "Hurtigtasten kunne ikke leses — bruk formen Ctrl+Shift+P." "Up": "Opp" "Down": "Ned" "Left": "Venstre" diff --git a/crates/openlogi-gui/locales/nl.yml b/crates/openlogi-gui/locales/nl.yml index f9e485dc..b4546693 100644 --- a/crates/openlogi-gui/locales/nl.yml +++ b/crates/openlogi-gui/locales/nl.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "DPI wisselen" "Thumb Wheel": "Duimwiel" "Gesture Button": "Gebarenknop" +"Action Ring": "Actiering" +"8 actions": "8 acties" +"Top": "Boven" +"Top Right": "Rechtsboven" +"Bottom Right": "Rechtsonder" +"Bottom": "Onder" +"Bottom Left": "Linksonder" +"Top Left": "Linksboven" +"CUSTOM": "AANGEPAST" +"Run Command": "Opdracht uitvoeren" +"Paste Text": "Tekst plakken" +"Command or URL": "Opdracht of URL" +"Text to paste": "Te plakken tekst" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "Een URL, bestand of programma. Na een programmapad scheidt || de argumenten; %VAR%-omgevingsvariabelen worden uitgebreid." +"Typed at the cursor exactly as written.": "Wordt bij de cursor exact zoals geschreven getypt." +"Folder": "Map" +"Open Folder": "Map openen" +"Keyboard Shortcut": "Sneltoets" +"Press Keys": "Toetsen indrukken" +"Name": "Naam" +"Optional — shown on the ring": "Optioneel — te zien op de ring" +"Command": "Opdracht" +"Text": "Tekst" +"Shortcut": "Sneltoets" +"Listening…": "Luisteren…" +"Press a shortcut…": "Druk een sneltoets in…" +"Or record it: hold the keys, then let go.": "Of neem hem op: houd de toetsen ingedrukt en laat los." +"e.g. Ctrl+Shift+P": "bijv. Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Modificatietoetsen verbonden met +, dan één toets: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "De sneltoets kon niet worden gelezen — gebruik de vorm Ctrl+Shift+P." "Up": "Omhoog" "Down": "Omlaag" "Left": "Links" diff --git a/crates/openlogi-gui/locales/pl.yml b/crates/openlogi-gui/locales/pl.yml index e72d22b1..711178d4 100644 --- a/crates/openlogi-gui/locales/pl.yml +++ b/crates/openlogi-gui/locales/pl.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "Przełącznik DPI" "Thumb Wheel": "Rolka kciukowa" "Gesture Button": "Przycisk gestów" +"Action Ring": "Pierścień akcji" +"8 actions": "8 akcji" +"Top": "Góra" +"Top Right": "Prawy górny" +"Bottom Right": "Prawy dolny" +"Bottom": "Dół" +"Bottom Left": "Lewy dolny" +"Top Left": "Lewy górny" +"CUSTOM": "NIESTANDARDOWE" +"Run Command": "Uruchom polecenie" +"Paste Text": "Wklej tekst" +"Command or URL": "Polecenie lub URL" +"Text to paste": "Tekst do wklejenia" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "URL, plik lub program. Po ścieżce programu || oddziela argumenty; zmienne środowiskowe %VAR% są rozwijane." +"Typed at the cursor exactly as written.": "Wpisywany przy kursorze dokładnie tak, jak napisano." +"Folder": "Folder" +"Open Folder": "Otwórz folder" +"Keyboard Shortcut": "Skrót klawiszowy" +"Press Keys": "Naciśnij klawisze" +"Name": "Nazwa" +"Optional — shown on the ring": "Opcjonalnie — widoczne na pierścieniu" +"Command": "Polecenie" +"Text": "Tekst" +"Shortcut": "Skrót" +"Listening…": "Nasłuchiwanie…" +"Press a shortcut…": "Naciśnij skrót…" +"Or record it: hold the keys, then let go.": "Albo nagraj go: przytrzymaj klawisze, a potem puść." +"e.g. Ctrl+Shift+P": "np. Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Modyfikatory połączone znakiem + i jeden klawisz: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "Nie udało się odczytać skrótu — użyj formy Ctrl+Shift+P." "Up": "W górę" "Down": "W dół" "Left": "W lewo" diff --git a/crates/openlogi-gui/locales/pt-BR.yml b/crates/openlogi-gui/locales/pt-BR.yml index a298fe26..5dfd739d 100644 --- a/crates/openlogi-gui/locales/pt-BR.yml +++ b/crates/openlogi-gui/locales/pt-BR.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "Alternar DPI" "Thumb Wheel": "Roda do Polegar" "Gesture Button": "Botão de Gesto" +"Action Ring": "Anel de Ações" +"8 actions": "8 ações" +"Top": "Superior" +"Top Right": "Superior direito" +"Bottom Right": "Inferior direito" +"Bottom": "Inferior" +"Bottom Left": "Inferior esquerdo" +"Top Left": "Superior esquerdo" +"CUSTOM": "PERSONALIZADO" +"Run Command": "Executar comando" +"Paste Text": "Colar texto" +"Command or URL": "Comando ou URL" +"Text to paste": "Texto a colar" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "Um URL, arquivo ou programa. Após o caminho do programa, || separa os argumentos; variáveis de ambiente %VAR% são expandidas." +"Typed at the cursor exactly as written.": "Digitado no cursor exatamente como escrito." +"Folder": "Pasta" +"Open Folder": "Abrir pasta" +"Keyboard Shortcut": "Atalho de teclado" +"Press Keys": "Pressionar teclas" +"Name": "Nome" +"Optional — shown on the ring": "Opcional — exibido no anel" +"Command": "Comando" +"Text": "Texto" +"Shortcut": "Atalho" +"Listening…": "Ouvindo…" +"Press a shortcut…": "Pressione um atalho…" +"Or record it: hold the keys, then let go.": "Ou grave: segure as teclas e depois solte." +"e.g. Ctrl+Shift+P": "ex.: Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Modificadores unidos com + e uma tecla: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "Não foi possível ler o atalho — use a forma Ctrl+Shift+P." "Up": "Cima" "Down": "Baixo" "Left": "Esquerda" diff --git a/crates/openlogi-gui/locales/pt-PT.yml b/crates/openlogi-gui/locales/pt-PT.yml index dfe9346b..a06fc2e9 100644 --- a/crates/openlogi-gui/locales/pt-PT.yml +++ b/crates/openlogi-gui/locales/pt-PT.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "Alternar DPI" "Thumb Wheel": "Roda de polegar" "Gesture Button": "Botão de gesto" +"Action Ring": "Anel de ações" +"8 actions": "8 ações" +"Top": "Superior" +"Top Right": "Superior direito" +"Bottom Right": "Inferior direito" +"Bottom": "Inferior" +"Bottom Left": "Inferior esquerdo" +"Top Left": "Superior esquerdo" +"CUSTOM": "PERSONALIZADO" +"Run Command": "Executar comando" +"Paste Text": "Colar texto" +"Command or URL": "Comando ou URL" +"Text to paste": "Texto a colar" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "Um URL, ficheiro ou programa. Após o caminho do programa, || separa os argumentos; as variáveis de ambiente %VAR% são expandidas." +"Typed at the cursor exactly as written.": "Escrito no cursor exatamente como está." +"Folder": "Pasta" +"Open Folder": "Abrir pasta" +"Keyboard Shortcut": "Atalho de teclado" +"Press Keys": "Premir teclas" +"Name": "Nome" +"Optional — shown on the ring": "Opcional — apresentado no anel" +"Command": "Comando" +"Text": "Texto" +"Shortcut": "Atalho" +"Listening…": "A ouvir…" +"Press a shortcut…": "Prima um atalho…" +"Or record it: hold the keys, then let go.": "Ou grave: mantenha as teclas premidas e depois solte." +"e.g. Ctrl+Shift+P": "p. ex. Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Modificadores unidos com + e uma tecla: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "Não foi possível ler o atalho — utilize a forma Ctrl+Shift+P." "Up": "Cima" "Down": "Baixo" "Left": "Esquerda" diff --git a/crates/openlogi-gui/locales/ru.yml b/crates/openlogi-gui/locales/ru.yml index c50a9281..408b6432 100644 --- a/crates/openlogi-gui/locales/ru.yml +++ b/crates/openlogi-gui/locales/ru.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "Переключение DPI" "Thumb Wheel": "Колесо под большой палец" "Gesture Button": "Кнопка жестов" +"Action Ring": "Кольцо действий" +"8 actions": "8 действий" +"Top": "Верх" +"Top Right": "Справа сверху" +"Bottom Right": "Справа снизу" +"Bottom": "Низ" +"Bottom Left": "Слева снизу" +"Top Left": "Слева сверху" +"CUSTOM": "ПОЛЬЗОВАТЕЛЬСКИЕ" +"Run Command": "Выполнить команду" +"Paste Text": "Вставить текст" +"Command or URL": "Команда или URL" +"Text to paste": "Текст для вставки" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "URL, файл или программа. После пути к программе || отделяет аргументы; переменные окружения %VAR% раскрываются." +"Typed at the cursor exactly as written.": "Вводится у курсора точно как написано." +"Folder": "Папка" +"Open Folder": "Открыть папку" +"Keyboard Shortcut": "Сочетание клавиш" +"Press Keys": "Нажмите клавиши" +"Name": "Имя" +"Optional — shown on the ring": "Необязательно — отображается в кольце" +"Command": "Команда" +"Text": "Текст" +"Shortcut": "Сочетание" +"Listening…": "Ожидание…" +"Press a shortcut…": "Нажмите сочетание…" +"Or record it: hold the keys, then let go.": "Или запишите: удержите клавиши, затем отпустите." +"e.g. Ctrl+Shift+P": "напр. Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Модификаторы через + и одна клавиша: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "Не удалось прочитать сочетание — используйте форму Ctrl+Shift+P." "Up": "Вверх" "Down": "Вниз" "Left": "Влево" diff --git a/crates/openlogi-gui/locales/sv.yml b/crates/openlogi-gui/locales/sv.yml index df82147f..8dd0bee8 100644 --- a/crates/openlogi-gui/locales/sv.yml +++ b/crates/openlogi-gui/locales/sv.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "DPI-växling" "Thumb Wheel": "Tumhjul" "Gesture Button": "Gestknapp" +"Action Ring": "Åtgärdsring" +"8 actions": "8 åtgärder" +"Top": "Överst" +"Top Right": "Uppe till höger" +"Bottom Right": "Nere till höger" +"Bottom": "Nederst" +"Bottom Left": "Nere till vänster" +"Top Left": "Uppe till vänster" +"CUSTOM": "ANPASSAT" +"Run Command": "Kör kommando" +"Paste Text": "Klistra in text" +"Command or URL": "Kommando eller URL" +"Text to paste": "Text att klistra in" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "En URL, fil eller ett program. Efter en programsökväg avgränsar || argumenten; %VAR%-miljövariabler expanderas." +"Typed at the cursor exactly as written.": "Skrivs vid markören exakt som skrivet." +"Folder": "Mapp" +"Open Folder": "Öppna mapp" +"Keyboard Shortcut": "Kortkommando" +"Press Keys": "Tryck på tangenter" +"Name": "Namn" +"Optional — shown on the ring": "Valfritt — visas på ringen" +"Command": "Kommando" +"Text": "Text" +"Shortcut": "Kortkommando" +"Listening…": "Lyssnar…" +"Press a shortcut…": "Tryck ett kortkommando…" +"Or record it: hold the keys, then let go.": "Eller spela in det: håll ner tangenterna och släpp sedan." +"e.g. Ctrl+Shift+P": "t.ex. Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "Modifierare sammanfogade med + och en tangent: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4." +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "Kortkommandot kunde inte läsas — använd formen Ctrl+Shift+P." "Up": "Upp" "Down": "Ned" "Left": "Vänster" diff --git a/crates/openlogi-gui/locales/zh-CN.yml b/crates/openlogi-gui/locales/zh-CN.yml index 318d29eb..8543db23 100644 --- a/crates/openlogi-gui/locales/zh-CN.yml +++ b/crates/openlogi-gui/locales/zh-CN.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "灵敏度切换" "Thumb Wheel": "拇指滚轮" "Gesture Button": "手势按钮" +"Action Ring": "操作环" +"8 actions": "8 个操作" +"Top": "上" +"Top Right": "右上" +"Bottom Right": "右下" +"Bottom": "下" +"Bottom Left": "左下" +"Top Left": "左上" +"CUSTOM": "自定义" +"Run Command": "运行命令" +"Paste Text": "粘贴文本" +"Command or URL": "命令或 URL" +"Text to paste": "要粘贴的文本" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "URL、文件或程序。在程序路径后用 || 分隔参数;%VAR% 环境变量会展开。" +"Typed at the cursor exactly as written.": "按原样在光标处输入。" +"Folder": "文件夹" +"Open Folder": "打开文件夹" +"Keyboard Shortcut": "键盘快捷键" +"Press Keys": "按下按键" +"Name": "名称" +"Optional — shown on the ring": "可选——显示在环上" +"Command": "命令" +"Text": "文本" +"Shortcut": "快捷键" +"Listening…": "监听中…" +"Press a shortcut…": "请按下快捷键…" +"Or record it: hold the keys, then let go.": "也可以录制:按住按键,然后松开。" +"e.g. Ctrl+Shift+P": "例如 Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "修饰键用 + 连接,最后一个键:Ctrl+Shift+P、Win+Ctrl+Space、Alt+F4。" +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "无法读取该快捷键——请使用 Ctrl+Shift+P 的格式。" "Up": "上" "Down": "下" "Left": "左" diff --git a/crates/openlogi-gui/locales/zh-HK.yml b/crates/openlogi-gui/locales/zh-HK.yml index 65a363c5..348459c6 100644 --- a/crates/openlogi-gui/locales/zh-HK.yml +++ b/crates/openlogi-gui/locales/zh-HK.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "靈敏度切換" "Thumb Wheel": "拇指滾輪" "Gesture Button": "手勢按鈕" +"Action Ring": "操作環" +"8 actions": "8 個操作" +"Top": "上" +"Top Right": "右上" +"Bottom Right": "右下" +"Bottom": "下" +"Bottom Left": "左下" +"Top Left": "左上" +"CUSTOM": "自訂" +"Run Command": "執行指令" +"Paste Text": "貼上文字" +"Command or URL": "指令或 URL" +"Text to paste": "要貼上的文字" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "URL、檔案或程式。在程式路徑後以 || 分隔參數;%VAR% 環境變數會展開。" +"Typed at the cursor exactly as written.": "按原樣在游標處輸入。" +"Folder": "資料夾" +"Open Folder": "開啟資料夾" +"Keyboard Shortcut": "鍵盤快速鍵" +"Press Keys": "按下按鍵" +"Name": "名稱" +"Optional — shown on the ring": "選填——顯示在圓環上" +"Command": "指令" +"Text": "文字" +"Shortcut": "快速鍵" +"Listening…": "聆聽中…" +"Press a shortcut…": "請按下快速鍵…" +"Or record it: hold the keys, then let go.": "也可以錄製:按住按鍵,然後放開。" +"e.g. Ctrl+Shift+P": "例如 Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "修飾鍵以 + 連接,最後一個鍵:Ctrl+Shift+P、Win+Ctrl+Space、Alt+F4。" +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "無法讀取該快速鍵——請使用 Ctrl+Shift+P 的格式。" "Up": "上" "Down": "下" "Left": "左" diff --git a/crates/openlogi-gui/locales/zh-TW.yml b/crates/openlogi-gui/locales/zh-TW.yml index 7505b25a..578f4ffc 100644 --- a/crates/openlogi-gui/locales/zh-TW.yml +++ b/crates/openlogi-gui/locales/zh-TW.yml @@ -156,6 +156,36 @@ _version: 1 "DPI Toggle": "靈敏度切換" "Thumb Wheel": "拇指滾輪" "Gesture Button": "手勢按鈕" +"Action Ring": "動作環" +"8 actions": "8 個動作" +"Top": "上" +"Top Right": "右上" +"Bottom Right": "右下" +"Bottom": "下" +"Bottom Left": "左下" +"Top Left": "左上" +"CUSTOM": "自訂" +"Run Command": "執行命令" +"Paste Text": "貼上文字" +"Command or URL": "命令或 URL" +"Text to paste": "要貼上的文字" +"A URL, file, or program. After a program path, use || to separate arguments; %VAR% environment variables expand.": "URL、檔案或程式。在程式路徑後以 || 分隔參數;%VAR% 環境變數會展開。" +"Typed at the cursor exactly as written.": "按原樣在游標處輸入。" +"Folder": "資料夾" +"Open Folder": "開啟資料夾" +"Keyboard Shortcut": "鍵盤快速鍵" +"Press Keys": "按下按鍵" +"Name": "名稱" +"Optional — shown on the ring": "選填——顯示在圓環上" +"Command": "命令" +"Text": "文字" +"Shortcut": "快速鍵" +"Listening…": "聆聽中…" +"Press a shortcut…": "請按下快速鍵…" +"Or record it: hold the keys, then let go.": "也可以錄製:按住按鍵,然後放開。" +"e.g. Ctrl+Shift+P": "例如 Ctrl+Shift+P" +"Modifier names joined with +, then one key: Ctrl+Shift+P, Win+Ctrl+Space, Alt+F4.": "修飾鍵以 + 連接,最後一個鍵:Ctrl+Shift+P、Win+Ctrl+Space、Alt+F4。" +"That shortcut could not be read — use the Ctrl+Shift+P shape.": "無法讀取該快速鍵——請使用 Ctrl+Shift+P 的格式。" "Up": "上" "Down": "下" "Left": "左" diff --git a/crates/openlogi-gui/src/app_assets.rs b/crates/openlogi-gui/src/app_assets.rs index 28d730c2..76dd0cda 100644 --- a/crates/openlogi-gui/src/app_assets.rs +++ b/crates/openlogi-gui/src/app_assets.rs @@ -45,6 +45,7 @@ const ACTION_ICONS: &[(&str, &[u8])] = &[ ("action-icons/circle-arrow-right.svg", include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/action-icons/circle-arrow-right.svg"))), ("action-icons/clipboard-paste.svg", include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/action-icons/clipboard-paste.svg"))), ("action-icons/copy.svg", include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/action-icons/copy.svg"))), + ("action-icons/folder.svg", include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/action-icons/folder.svg"))), ("action-icons/gauge.svg", include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/action-icons/gauge.svg"))), ("action-icons/grid-3x3.svg", include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/action-icons/grid-3x3.svg"))), ("action-icons/keyboard.svg", include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/action-icons/keyboard.svg"))), diff --git a/crates/openlogi-gui/src/chord_recorder.rs b/crates/openlogi-gui/src/chord_recorder.rs new file mode 100644 index 00000000..55558837 --- /dev/null +++ b/crates/openlogi-gui/src/chord_recorder.rs @@ -0,0 +1,258 @@ +//! Physical key-chord recorder for the shortcut editor. +//! +//! Reads the keyboard's **physical** state (`GetAsyncKeyState`) on a timer +//! rather than handling key events, for two reasons: the dialog must record +//! chords the OS or another app has already claimed as a global hotkey +//! (`Win+Ctrl+Space` is exactly such a case — the owner swallows the +//! message, but the physical state is still readable), and the same +//! technique already backs the ring overlay's Esc/outside-click watcher. +//! +//! The recorder emits the **canonical chord text** +//! ([`KeyCombo::parse`]'s input language, e.g. `"Win+Ctrl+Space"`) instead +//! of a [`KeyCombo`], so parsing and display keep exactly one source of +//! truth: whatever a user could type, the recorder produces, and vice versa. + +/// What one [`ChordRecorder::poll`] observed. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Poll { + /// Nothing pressed yet — keep listening. + Idle, + /// Keys are down; `0` is the chord so far (shown live in the dialog). + Holding(String), + /// Every key was released: `0` is the finished chord. + Done(String), + /// Escape alone — the user backed out of listening. + Cancelled, +} + +/// Accumulates the chord across polls: the modifiers held when a +/// non-modifier key goes down, finalized when everything is released. +#[derive(Default)] +pub struct ChordRecorder { + /// The best (most complete) chord seen while keys were held. + held: Option, +} + +impl ChordRecorder { + /// Sample the keyboard once. Call on a ~30 ms timer while listening. + pub fn poll(&mut self) -> Poll { + self.advance(platform::sample()) + } + + /// [`Self::poll`] with the keyboard reading supplied, so the state + /// machine is testable without depending on what is physically held + /// while the suite runs. + fn advance(&mut self, sample: (Vec<&'static str>, Option<&'static str>)) -> Poll { + let (modifiers, key) = sample; + // Escape with no modifiers is the cancel gesture, never a binding — + // matching the ring overlay, where Esc means "back out". + if modifiers.is_empty() && key == Some("Escape") { + self.held = None; + return Poll::Cancelled; + } + match key { + Some(key) => { + let mut chord = String::new(); + for name in &modifiers { + chord.push_str(name); + chord.push('+'); + } + chord.push_str(key); + self.held = Some(chord.clone()); + Poll::Holding(chord) + } + // A bare modifier is not a chord; wait for the real key. + None if !modifiers.is_empty() => Poll::Idle, + // Everything is up: a chord that was held is now complete. + None => match self.held.take() { + Some(chord) => Poll::Done(chord), + None => Poll::Idle, + }, + } + } +} + +#[cfg(target_os = "windows")] +mod platform { + #![expect( + unsafe_code, + reason = "GetAsyncKeyState is the Win32 physical-key-state API" + )] + + use windows_sys::Win32::UI::Input::KeyboardAndMouse::GetAsyncKeyState; + + /// Modifier virtual keys, in the canonical order [`super::ChordRecorder`] + /// emits them (matching `KeyCombo::parse`'s rendering). + const MODIFIERS: &[(i32, &str)] = &[ + (0x5B, "Win"), // VK_LWIN + (0x5C, "Win"), // VK_RWIN + (0x11, "Ctrl"), + (0x12, "Alt"), + (0x10, "Shift"), + ]; + + /// Named non-modifier keys. Letters, digits and F-keys are generated in + /// [`sample`] rather than listed. + const NAMED: &[(i32, &str)] = &[ + (0x20, "Space"), + (0x0D, "Enter"), + (0x09, "Tab"), + (0x1B, "Escape"), + (0x08, "Backspace"), + (0x2E, "Delete"), + (0x24, "Home"), + (0x23, "End"), + (0x21, "PageUp"), + (0x22, "PageDown"), + (0x26, "Up"), + (0x28, "Down"), + (0x25, "Left"), + (0x27, "Right"), + ]; + + /// Whether `vk` is physically down right now. + fn down(vk: i32) -> bool { + // SAFETY: GetAsyncKeyState takes a virtual-key code and only reads + // process-wide keyboard state; no pointers are involved. + let state = unsafe { GetAsyncKeyState(vk) }; + state.cast_unsigned() & 0x8000 != 0 + } + + /// The modifiers currently held (deduplicated, canonical order) and the + /// first non-modifier key held, if any. + pub fn sample() -> (Vec<&'static str>, Option<&'static str>) { + let mut modifiers: Vec<&'static str> = Vec::new(); + for (vk, name) in MODIFIERS { + if down(*vk) && !modifiers.contains(name) { + modifiers.push(name); + } + } + + // Letters (VK_A..VK_Z) and digits (VK_0..VK_9) share their ASCII + // codes, so their names come straight from the code. + for vk in 0x41..=0x5A_i32 { + if down(vk) { + let name = LETTERS[usize::try_from(vk - 0x41).unwrap_or(0)]; + return (modifiers, Some(name)); + } + } + for vk in 0x30..=0x39_i32 { + if down(vk) { + let name = DIGITS[usize::try_from(vk - 0x30).unwrap_or(0)]; + return (modifiers, Some(name)); + } + } + for vk in 0x70..=0x7B_i32 { + if down(vk) { + let name = FUNCTION_KEYS[usize::try_from(vk - 0x70).unwrap_or(0)]; + return (modifiers, Some(name)); + } + } + for (vk, name) in NAMED { + if down(*vk) { + return (modifiers, Some(name)); + } + } + (modifiers, None) + } + + /// `'static` names for VK_A..VK_Z, indexed by `vk - 0x41`. + const LETTERS: [&str; 26] = [ + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", + "S", "T", "U", "V", "W", "X", "Y", "Z", + ]; + /// `'static` names for VK_0..VK_9, indexed by `vk - 0x30`. + const DIGITS: [&str; 10] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]; + /// `'static` names for VK_F1..VK_F12, indexed by `vk - 0x70`. + const FUNCTION_KEYS: [&str; 12] = [ + "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", + ]; +} + +#[cfg(not(target_os = "windows"))] +mod platform { + /// Recording is Windows-first, like the ring overlay itself; elsewhere + /// the dialog's typed-chord path is the way in. + pub fn sample() -> (Vec<&'static str>, Option<&'static str>) { + (Vec::new(), None) + } +} + +/// Whether this platform can record chords (gates the dialog's button). +#[must_use] +pub const fn is_supported() -> bool { + cfg!(target_os = "windows") +} + +#[cfg(test)] +mod tests { + use super::{ChordRecorder, Poll}; + + /// Nothing held: no chord is ever invented, however long we wait. + #[test] + fn idle_polls_never_finalize_a_chord() { + let mut recorder = ChordRecorder::default(); + assert_eq!(recorder.advance((vec![], None)), Poll::Idle); + assert_eq!(recorder.advance((vec![], None)), Poll::Idle); + } + + /// The full gesture: modifiers first (not yet a chord), then the key, + /// then release — emitting the chord exactly once. + #[test] + fn a_held_chord_is_emitted_once_on_release() { + let mut recorder = ChordRecorder::default(); + assert_eq!( + recorder.advance((vec!["Ctrl"], None)), + Poll::Idle, + "a bare modifier is not a chord" + ); + assert_eq!( + recorder.advance((vec!["Ctrl", "Shift"], Some("P"))), + Poll::Holding("Ctrl+Shift+P".into()) + ); + assert_eq!( + recorder.advance((vec!["Ctrl"], None)), + Poll::Idle, + "still coming up — the chord is not final until everything is up" + ); + assert_eq!( + recorder.advance((vec![], None)), + Poll::Done("Ctrl+Shift+P".into()) + ); + assert_eq!( + recorder.advance((vec![], None)), + Poll::Idle, + "not re-emitted" + ); + } + + /// A chord that grows keeps its most complete form. + #[test] + fn the_last_held_chord_wins() { + let mut recorder = ChordRecorder::default(); + let _ = recorder.advance((vec!["Ctrl"], Some("Space"))); + let _ = recorder.advance((vec!["Win", "Ctrl"], Some("Space"))); + assert_eq!( + recorder.advance((vec![], None)), + Poll::Done("Win+Ctrl+Space".into()) + ); + } + + /// Escape alone backs out and discards anything held. + #[test] + fn escape_cancels_without_emitting() { + let mut recorder = ChordRecorder::default(); + let _ = recorder.advance((vec!["Ctrl"], Some("P"))); + assert_eq!(recorder.advance((vec![], Some("Escape"))), Poll::Cancelled); + assert_eq!( + recorder.advance((vec![], None)), + Poll::Idle, + "the cancelled chord is gone, not pending" + ); + // Escape *with* a modifier is a real binding, not a cancel. + assert_eq!( + recorder.advance((vec!["Ctrl"], Some("Escape"))), + Poll::Holding("Ctrl+Escape".into()) + ); + } +} diff --git a/crates/openlogi-gui/src/ipc_client.rs b/crates/openlogi-gui/src/ipc_client.rs index 73040715..45e99ea0 100644 --- a/crates/openlogi-gui/src/ipc_client.rs +++ b/crates/openlogi-gui/src/ipc_client.rs @@ -21,8 +21,9 @@ use std::time::{Duration, Instant}; use openlogi_agent_core::ipc::{ AgentClient, AgentStatus, InventoryHealth, PROTOCOL_VERSION, PairingCommandError, - PairingFailure, PairingUpdate, + PairingFailure, PairingUpdate, RingPress, }; +use openlogi_core::binding::Action; use openlogi_core::config::Lighting; use openlogi_core::device::DeviceInventory; use openlogi_hid::{ @@ -101,15 +102,21 @@ pub enum Command { /// auto-disables it once polls stop. #[cfg(all(target_os = "macos", debug_assertions))] PollEventMonitor(oneshot::Sender>), + /// Fire one bound action through the agent's dispatch path — the ring + /// overlay's selected sector. Fire-and-forget like the other "apply now" + /// writes. + ExecuteAction(Action), } /// Handle the GUI holds to talk to the agent: a stream of poll updates, a -/// sender for device commands, and a stream of pairing events (long-polled on a -/// separate connection so a held pairing poll never stalls inventory). +/// sender for device commands, and streams of pairing events and Action Ring +/// presses (each long-polled on its own connection so a held poll never stalls +/// inventory — and a held pairing poll never delays a ring press). pub struct IpcClient { pub updates: mpsc::UnboundedReceiver, pub commands: mpsc::UnboundedSender, pub pairing: mpsc::UnboundedReceiver, + pub ring: mpsc::UnboundedReceiver, } /// Spawn the IPC client thread. Returns immediately; the thread connects (and @@ -119,6 +126,7 @@ pub fn spawn(poll_period: Duration) -> IpcClient { let (update_tx, updates) = mpsc::unbounded_channel(); let (commands, mut cmd_rx) = mpsc::unbounded_channel::(); let (pairing_tx, pairing) = mpsc::unbounded_channel(); + let (ring_tx, ring) = mpsc::unbounded_channel(); let spawn_result = std::thread::Builder::new() .name("openlogi-ipc-client".into()) @@ -134,9 +142,11 @@ pub fn spawn(poll_period: Duration) -> IpcClient { } }; rt.block_on(async move { - // Pairing events stream on their own connection + long-poll so - // a held next_pairing never delays the snapshot poll. + // Pairing events and ring presses stream on their own + // connections + long-polls so a held poll never delays the + // snapshot poll (or each other). tokio::spawn(pairing_poll(pairing_tx.clone())); + tokio::spawn(ring_poll(ring_tx)); poll_loop(poll_period, &update_tx, &pairing_tx, &mut cmd_rx).await; }); }); @@ -148,6 +158,7 @@ pub fn spawn(poll_period: Duration) -> IpcClient { updates, commands, pairing, + ring, } } @@ -299,6 +310,37 @@ async fn pairing_poll(tx: mpsc::UnboundedSender) { } } +/// Long-poll the agent's Action Ring press stream on a dedicated connection. +/// A press opens (or confirms a selection in) the overlay, so latency is the +/// whole point — the poll sits held at the agent and answers the instant the +/// pad is tapped. When the pad is idle the agent returns `None` at its hold +/// window and we re-poll. Runs for the client's lifetime. +async fn ring_poll(tx: mpsc::UnboundedSender) { + let mut client: Option = None; + loop { + let Ok(live) = ensure(&mut client).await else { + tokio::time::sleep(Duration::from_secs(1)).await; // agent not up yet + continue; + }; + // The agent holds the poll ~20s; give the request a bit longer so the + // agent answers (with a press or None) before the client deadline. + let mut ctx = context::current(); + ctx.deadline = Instant::now() + Duration::from_secs(25); + match live.next_ring_press(ctx).await { + Ok(Some(press)) => { + if tx.send(press).is_err() { + return; // GUI dropped the receiver → stop + } + } + Ok(None) => {} + Err(_) => { + client = None; // connection dropped (agent restart) — reconnect + tokio::time::sleep(Duration::from_secs(1)).await; + } + } + } +} + /// One pairing long-poll. `Ok(false)` means the GUI receiver is gone; `Err` a /// dropped connection the caller should reconnect. async fn poll_pairing_once( @@ -577,6 +619,9 @@ async fn handle( Command::PollEventMonitor(reply) => { let _ = reply.send(rpc_result(client.poll_event_monitor(ctx).await)?); } + Command::ExecuteAction(action) => { + client.execute_action(ctx, action).await.map_err(|_| ())?; + } } Ok(()) } diff --git a/crates/openlogi-gui/src/main.rs b/crates/openlogi-gui/src/main.rs index 07d07d06..f5e730cf 100644 --- a/crates/openlogi-gui/src/main.rs +++ b/crates/openlogi-gui/src/main.rs @@ -33,6 +33,7 @@ mod app; mod app_assets; mod app_menu; mod asset; +mod chord_recorder; mod components; mod data; mod diagnostics; @@ -40,6 +41,7 @@ mod i18n; mod ipc_client; mod mouse_model; mod platform; +mod ring; mod state; mod theme; mod windows; @@ -141,8 +143,12 @@ fn main() -> Result<()> { let inventories: Vec = Vec::new(); let initial_config = Config::load_or_default().unwrap_or_else(|e| { - warn!(error = %e, "could not load config.toml; using defaults"); - Config::default() + warn!( + error = %e, + "could not load config.toml; running on defaults WITHOUT persisting, \ + so the unreadable file is left intact" + ); + Config::defaults_for_unreadable() }); // Resolve the UI locale before any menu or window is built so the first @@ -156,6 +162,7 @@ fn main() -> Result<()> { updates: mut ipc_updates, commands: ipc_commands, pairing: mut ipc_pairing, + ring: mut ipc_ring, } = ipc_client::spawn(std::time::Duration::from_secs(2)); // Manual asset actions (Settings → Assets): Refresh / Clear cache. The @@ -191,6 +198,11 @@ fn main() -> Result<()> { // Reopen the window when the app is relaunched with none open (dock click). app.on_reopen(|cx| open_main_window(&[], cx)); + // `--background` (login autostart): start resident for the Action Ring + // and the agent's tray, but do not open the main window — the tray's + // "Show Main Window" deeplink opens it on demand. + let background = std::env::args().any(|arg| arg == "--background"); + app.run(move |cx| { gpui_component::init(cx); theme::register_builtin_themes(cx); @@ -201,6 +213,11 @@ fn main() -> Result<()> { // back into this global via the select loop below. cx.set_global(windows::add_device::PairingUi::Idle); + // The Action Ring overlay controller: pad presses from the agent's + // ring long-poll (select loop below) open it / confirm a selection, + // and it fires the chosen action back through the command channel. + ring::init(ipc_commands.clone(), cx); + // The Settings → Assets buttons drive the asset sync (which lives on // the select loop below) through this global. cx.set_global(AssetControl(asset_ctrl_tx)); @@ -213,6 +230,9 @@ fn main() -> Result<()> { // On-demand GUI: quit when the last window closes. The agent stays // resident and keeps remapping (and hosts the menu-bar item from which // the GUI is reopened), so nothing needs the GUI process to linger. + // On Windows this never fires: the ring overlay's always-alive hidden + // window (created eagerly in `ring::init`) keeps the process resident, + // because the on-screen ring lives in this process, not the agent. cx.on_window_closed(|cx, _| { if cx.windows().is_empty() { cx.quit(); @@ -233,15 +253,20 @@ fn main() -> Result<()> { ipc_commands, )); } - open_main_window(&inventories, cx); + if !background { + open_main_window(&inventories, cx); + } }); // First launch only: offer to opt in to the update check, since it // defaults to off. Marked seen either way so it shows just once. + // Deferred in background mode (nothing may pop over the login + // desktop); it stays unseen and shows on the first real open. cx.update(|cx| { - let show = cx - .try_global::() - .is_some_and(|s| !s.app_settings().update_prompt_seen); + let show = !background + && cx + .try_global::() + .is_some_and(|s| !s.app_settings().update_prompt_seen); if show { windows::update_consent::open(cx); } @@ -482,6 +507,19 @@ fn main() -> Result<()> { windows::add_device::apply_update(cx, update); }); } + Some(press) = ipc_ring.recv() => { + tracing::debug!( + seq = press.seq, + device = press.device_key, + "action ring press received" + ); + // An empty key means the agent had no active device; + // fall back to the carousel selection rather than + // rendering nothing. + let device_key = (!press.device_key.is_empty()) + .then_some(press.device_key); + cx.update(|cx| ring::on_pad_press(device_key, cx)); + } Some(cmd) = gui_cmd_rx.recv() => { cx.update(|cx| dispatch_gui_command(cmd, cx)); } diff --git a/crates/openlogi-gui/src/mouse_model/geometry.rs b/crates/openlogi-gui/src/mouse_model/geometry.rs index 7ad9b4ed..642c7da7 100644 --- a/crates/openlogi-gui/src/mouse_model/geometry.rs +++ b/crates/openlogi-gui/src/mouse_model/geometry.rs @@ -217,6 +217,10 @@ fn map_slot_name(name: &str) -> Option { "SLOT_NAME_MODESHIFT_BUTTON" => Some(ButtonId::DpiToggle), "SLOT_NAME_THUMBWHEEL" => Some(ButtonId::Thumbwheel), "SLOT_NAME_GESTURE_BUTTON" => Some(ButtonId::GestureButton), + // The MX Master 4 Action Ring pad. Logi's own marker for it: the + // slotId suffix is `_c416` = CID 0x01a0, the control the capture + // session arms for analytics events. + "ASSIGNMENT_NAME_SHOW_RADIAL_MENU" => Some(ButtonId::ActionRing), _ => None, } } diff --git a/crates/openlogi-gui/src/mouse_model/mod.rs b/crates/openlogi-gui/src/mouse_model/mod.rs index e22dc885..3759b91c 100644 --- a/crates/openlogi-gui/src/mouse_model/mod.rs +++ b/crates/openlogi-gui/src/mouse_model/mod.rs @@ -6,4 +6,5 @@ mod geometry; pub mod leader_lines; pub mod picker; +pub mod ring_editor; pub mod view; diff --git a/crates/openlogi-gui/src/mouse_model/picker.rs b/crates/openlogi-gui/src/mouse_model/picker.rs index 7face4ed..8e69551d 100644 --- a/crates/openlogi-gui/src/mouse_model/picker.rs +++ b/crates/openlogi-gui/src/mouse_model/picker.rs @@ -34,6 +34,7 @@ use crate::data::mouse_buttons::{ use crate::mouse_model::view::MouseModelView; use crate::state::AppState; use crate::theme::{self, ACCENT_BLUE, Palette, SelectableStyle, Typography as _}; +use crate::windows::ring_action_editor::{EditTarget, PayloadKind}; /// Floor width for the [`action_picker`] popover. The action labels drive the /// actual width; this only stops the list from collapsing too narrow. Matches @@ -70,14 +71,19 @@ pub fn action_picker( let pal = theme::palette(cx); let button = rust_i18n::t!(btn.label()); + let mut rows = action_rows("action-item", current.as_ref(), &on_pick, pal); + // Any button can carry a shortcut / command / snippet, not just ring + // slots — the DPI toggle bound to another app's hotkey, say. + rows.extend(payload_rows( + EditTarget::Button(btn), + current.as_ref().unwrap_or(&Action::None), + pal, + )); menu_card(pal) .min_w(px(POPOVER_W)) .child(title(tr!("Bind %{name}", name => button), pal)) .child(divider(pal)) - .child(scroll_list( - "picker-scroll", - action_rows("action-item", current.as_ref(), &on_pick, pal), - )) + .child(scroll_list("picker-scroll", rows)) .into_any_element() } @@ -107,6 +113,66 @@ pub fn gesture_overview( .into_any_element() } +/// The CUSTOM section every binding menu ends with: the payload actions that +/// carry free text and so open the editor dialog instead of committing +/// straight from the list. Appended to the catalog rows so any binding +/// surface — a ring slot, a gesture direction, a plain button — offers the +/// same three. +pub(crate) fn payload_rows(target: EditTarget, current: &Action, pal: Palette) -> Vec { + let mut rows = vec![section_header(&rust_i18n::t!("CUSTOM"), pal)]; + for (idx, kind) in [ + PayloadKind::Run, + PayloadKind::PasteText, + PayloadKind::Shortcut, + ] + .into_iter() + .enumerate() + { + rows.push(payload_editor_row(target, kind, idx, current, pal)); + } + rows +} + +/// A "Run Command…" / "Paste Text…" action-list row. Unlike the catalog rows it +/// commits nothing itself — it opens the payload-editor dialog seeded from +/// the target's current action. Selection styling still mirrors the catalog +/// so a slot bound to a payload action shows where its value lives. +pub(crate) fn payload_editor_row( + target: EditTarget, + kind: PayloadKind, + idx: usize, + current: &Action, + pal: Palette, +) -> AnyElement { + let selected = kind.payload_of(current).is_some(); + let icon_path = kind.icon_path(); + menu_row(("ring-payload", idx), pal, selected) + .child( + h_flex() + .items_center() + .gap_2() + .child( + svg() + .path(icon_path) + .size_4() + .flex_none() + .text_color(pal.text_muted), + ) + .child(div().child(format!("{}…", tr!(kind.title_key())))), + ) + .when(selected, |s| { + s.child( + Icon::new(IconName::Check) + .size_3() + .text_color(rgb(ACCENT_BLUE)), + ) + }) + .on_click(move |_event, _window, cx| { + crate::windows::ring_action_editor::open(target, kind, cx); + }) + .into_any_element() +} + /// The shared floating-card surface for every binding menu — the button picker, /// the gesture plus navigator, and its action flyout — so they read as one /// consistent, app-branded panel instead of two different surfaces. @@ -252,14 +318,16 @@ fn flyout_card( view_pick.update(cx, |_, vcx| vcx.notify()); }); + let mut rows = action_rows("gesture-action", Some(¤t), &on_pick, pal); + // Hold + swipe should reach a keyboard shortcut or a command too, not + // only the built-in catalog. + rows.extend(payload_rows(EditTarget::Gesture(dir), ¤t, pal)); + menu_card(pal) .min_w(px(POPOVER_W)) .child(title(format!("{} {}", dir.glyph(), tr!(dir.label())), pal)) .child(divider(pal)) - .child(scroll_list( - "gesture-dir-scroll", - action_rows("gesture-action", Some(¤t), &on_pick, pal), - )) + .child(scroll_list("gesture-dir-scroll", rows)) .into_any_element() } @@ -268,7 +336,7 @@ fn flyout_card( /// Commit callback invoked when a row is clicked. Boxed so the row builder can /// be shared between the button picker and any future custom picker, which /// differ only in what they do after committing. -type PickFn = Rc; +pub(crate) type PickFn = Rc; /// The action catalog grouped by [`Category`], preserving catalog order within /// each group and first-seen order across groups. @@ -290,13 +358,20 @@ fn grouped_catalog() -> Vec<(Category, Vec)> { /// bound action. pub(crate) const GESTURE_BUTTON_ICON: &str = "action-icons/move.svg"; +/// Icon for the Action Ring's label card — the dots grid echoes the pad's +/// eight-dot ring marking; the ring has no single bound action either. +pub(crate) const RING_BUTTON_ICON: &str = "action-icons/grid-3x3.svg"; + /// Asset path (served by [`crate::app_assets`]) of the vendored lucide glyph for /// an action — the leading icon in each action row and in the leader-line label /// card. Exhaustive on purpose: a new [`Action`] variant must pick an icon here /// (no catch-all fallback). pub(crate) fn action_icon_path(action: &Action) -> &'static str { - match action { - Action::None => "action-icons/ban.svg", + // A label doesn't change the glyph — look through it. + match action.inner() { + // `Named` is unreachable — `inner()` strips labels above — but it + // shares the neutral glyph rather than inventing an icon. + Action::None | Action::Named { .. } => "action-icons/ban.svg", Action::LeftClick | Action::RightClick => "action-icons/mouse-pointer-click.svg", Action::MiddleClick => "action-icons/mouse.svg", // Circled arrows: visually "back/forward as a button", distinct from @@ -304,7 +379,7 @@ pub(crate) fn action_icon_path(action: &Action) -> &'static str { Action::MouseBack => "action-icons/circle-arrow-left.svg", Action::MouseForward => "action-icons/circle-arrow-right.svg", Action::Copy => "action-icons/copy.svg", - Action::Paste => "action-icons/clipboard-paste.svg", + Action::Paste | Action::PasteText(_) => "action-icons/clipboard-paste.svg", Action::Cut => "action-icons/scissors.svg", Action::Undo => "action-icons/undo-2.svg", Action::Redo => "action-icons/redo-2.svg", @@ -322,7 +397,9 @@ pub(crate) fn action_icon_path(action: &Action) -> &'static str { Action::MissionControl => "action-icons/layout-grid.svg", Action::AppExpose => "action-icons/layers.svg", Action::PreviousDesktop => "action-icons/square-arrow-left.svg", - Action::NextDesktop => "action-icons/square-arrow-right.svg", + // Run shares the "launch outward" arrow — the closest glyph in the + // vendored set to Options+'s run icon. + Action::NextDesktop | Action::Run(_) => "action-icons/square-arrow-right.svg", Action::ShowDesktop => "action-icons/monitor.svg", Action::LaunchpadShow => "action-icons/grid-3x3.svg", Action::LockScreen => "action-icons/lock.svg", @@ -340,6 +417,7 @@ pub(crate) fn action_icon_path(action: &Action) -> &'static str { Action::HorizontalScrollLeft => "action-icons/chevrons-left.svg", Action::HorizontalScrollRight => "action-icons/chevrons-right.svg", Action::CustomShortcut(_) => "action-icons/keyboard.svg", + Action::Folder(_) => "action-icons/folder.svg", } } @@ -347,7 +425,7 @@ pub(crate) fn action_icon_path(action: &Action) -> &'static str { /// icon, then its label; `current` adds a trailing accent check. Clicking any /// row invokes `on_pick`. `id_prefix` disambiguates element IDs between pickers /// that share this builder. -fn action_rows( +pub(crate) fn action_rows( id_prefix: &'static str, current: Option<&Action>, on_pick: &PickFn, @@ -428,7 +506,7 @@ fn menu_row( } /// Small uppercase muted group header. -fn section_header(label: &str, pal: Palette) -> AnyElement { +pub(crate) fn section_header(label: &str, pal: Palette) -> AnyElement { div() .w_full() .px_2() diff --git a/crates/openlogi-gui/src/mouse_model/ring_editor.rs b/crates/openlogi-gui/src/mouse_model/ring_editor.rs new file mode 100644 index 00000000..fc27fa7c --- /dev/null +++ b/crates/openlogi-gui/src/mouse_model/ring_editor.rs @@ -0,0 +1,529 @@ +//! The Action Ring's full-page editor — the Options+ customization page +//! shape, not a popover: a back arrow, the ring drawn large with every +//! circle labelled by its bound action, and a persistent action panel on the +//! right editing the selected slot. +//! +//! Clicking the ring's hotspot or label card on the mouse diagram swaps the +//! diagram for this page (scratch state on [`MouseModelView`]); the back +//! arrow swaps back. Folders drill in: clicking an already-selected folder +//! circle (or the panel's "Open Folder" row) shows the folder's contents on +//! the same canvas — empty positions render as dashed "+" targets — and the +//! back arrow then pops to the top level first. + +use std::collections::BTreeMap; +use std::rc::Rc; + +use gpui::{ + AnyElement, BorrowAppContext as _, Context, Entity, InteractiveElement, IntoElement, + ParentElement, SharedString, StatefulInteractiveElement as _, Styled, div, + prelude::FluentBuilder as _, px, rgb, svg, +}; +use gpui_component::{h_flex, v_flex}; +use openlogi_core::binding::{Action, RingSlot, default_ring_binding}; + +use crate::mouse_model::picker::{PickFn, action_icon_path, action_rows, payload_rows}; +use crate::mouse_model::view::{MouseModelView, localized_action_label}; +use crate::state::AppState; +use crate::theme::{ACCENT_BLUE, Palette, Typography as _}; +use crate::windows::ring_action_editor::EditTarget; + +/// Radius of the circle the editor's slot buttons sit on. +const EDIT_RADIUS: f32 = 110.; +/// Diameter of one slot circle on the canvas. +const EDIT_CIRCLE: f32 = 48.; +/// Diameter of the decorative centre circle. +const EDIT_CENTER: f32 = 36.; +/// Width reserved for a floating label pill column beside a circle. +const PILL_W: f32 = 140.; +/// Gap between a circle and its label pill. +const PILL_GAP: f32 = 10.; +/// Vertical room above / below the ring for the North / South pills. +const PILL_V: f32 = 44.; +/// The canvas is a wide, short rectangle — pills extend sideways, so the +/// height only needs the ring plus the North/South pill rows. A square at +/// pill width was taller than the content area and clipped. +const CANVAS_W: f32 = 2. * (EDIT_RADIUS + EDIT_CIRCLE / 2. + PILL_GAP + PILL_W); +const CANVAS_H: f32 = 2. * (EDIT_RADIUS + EDIT_CIRCLE / 2. + PILL_V); +/// Fixed width of the right-hand action panel. +const PANEL_W: f32 = 260.; +/// Height cap for the action panel's scrolling list. +const PANEL_LIST_H: f32 = 360.; + +/// One canvas position: the slot, what's bound there (`None` = an empty +/// folder position rendered as a dashed add target), and whether it is the +/// active selection. +struct CanvasSlot { + slot: RingSlot, + action: Option, + selected: bool, +} + +/// Build the full-page editor. Rendered by [`MouseModelView`] in place of +/// the mouse diagram while its `ring_editor_open` scratch flag is set. +/// +/// `selected` / `folder_open` come from the caller's `&self` — this runs +/// inside the view's own `render`, where `view.read(cx)` would panic +/// ("cannot read … while it is already being updated"); `view` is only +/// cloned into event closures. +pub(crate) fn page( + selected: Option, + folder_open: Option, + view: &Entity, + pal: Palette, + cx: &mut Context, +) -> AnyElement { + let selected = selected.unwrap_or(RingSlot::North); + let actions: BTreeMap = cx + .try_global::() + .map(|s| s.ring_slots_for_current().into_iter().collect()) + .unwrap_or_default(); + + // Drilled-in state survives the folder being replaced from elsewhere + // (another window, a config reload): fall back to the top level unless + // the slot still holds a folder. + let folder_open = + folder_open.filter(|slot| matches!(actions.get(slot), Some(Action::Folder(_)))); + let folder_items: Option<&BTreeMap> = + folder_open.and_then(|slot| match actions.get(&slot) { + Some(Action::Folder(items)) => Some(items), + _ => None, + }); + + let canvas_slots: Vec = RingSlot::ALL + .into_iter() + .map(|slot| CanvasSlot { + slot, + action: match folder_items { + Some(items) => items + .get(&slot) + .filter(|action| !matches!(action, Action::None)) + .cloned(), + None => Some( + actions + .get(&slot) + .cloned() + .unwrap_or_else(|| default_ring_binding(slot)), + ), + }, + selected: slot == selected, + }) + .collect(); + + let title: SharedString = match folder_open { + Some(slot) => format!( + "{} {} › {}", + tr!("Action Ring"), + slot.glyph(), + tr!("Folder") + ) + .into(), + None => tr!("Action Ring"), + }; + + let view_back = view.clone(); + let back = h_flex() + .items_center() + .gap_3() + .child( + div() + .id("ring-editor-back") + .p_1p5() + .rounded(pal.control_radius) + .cursor_pointer() + .hover(|s| s.bg(pal.surface)) + .on_click(move |_, _, cx| { + view_back.update(cx, |v, vcx| { + // Pop the folder first; only a top-level back leaves + // the editor. + if folder_open.is_some() { + v.set_ring_folder_open(None); + v.set_ring_selected_slot(folder_open); + } else { + v.set_ring_editor_open(false); + v.set_ring_selected_slot(None); + } + vcx.notify(); + }); + }) + .child( + svg() + .path("action-icons/arrow-left.svg") + .size_5() + .text_color(pal.text_primary), + ), + ) + .child(div().text_heading().child(title)) + .child( + div() + .text_caption() + .text_color(pal.text_muted) + .child(tr!("8 actions")), + ); + + // Header on top; below it the canvas and panel side by side, the pair + // centred as one block so the page reads composed at any window size. + v_flex() + .size_full() + .gap_2() + .child(back) + .child( + div().flex_1().flex().items_center().justify_center().child( + h_flex() + .items_center() + .gap_6() + .child(canvas(&canvas_slots, folder_open, view, pal)) + .child(action_panel(selected, folder_open, &actions, view, pal)), + ), + ) + .into_any_element() +} + +/// The ring canvas: eight slot circles on a ring plus the decorative centre. +/// Empty folder positions are dashed "+" add targets; the selected slot (and +/// its pill) is accented. +fn canvas( + slots: &[CanvasSlot], + folder_open: Option, + view: &Entity, + pal: Palette, +) -> AnyElement { + let (cw, ch) = (CANVAS_W / 2., CANVAS_H / 2.); + let mut layer = div().relative().flex_none().w(px(CANVAS_W)).h(px(CANVAS_H)); + + // Decorative centre — the popup's ✕ (or the folder's ← back) is only in + // the on-screen ring; here it is orientation. + layer = layer.child( + div() + .absolute() + .left(px(cw - EDIT_CENTER / 2.)) + .top(px(ch - EDIT_CENTER / 2.)) + .w(px(EDIT_CENTER)) + .h(px(EDIT_CENTER)) + .rounded_full() + .bg(pal.surface) + .border_1() + .border_color(pal.border) + .flex() + .items_center() + .justify_center() + .text_color(pal.text_muted) + .text_body() + .child(if folder_open.is_some() { "←" } else { "✕" }), + ); + + for (idx, canvas_slot) in slots.iter().enumerate() { + let slot = canvas_slot.slot; + let is_selected = canvas_slot.selected; + let angle = slot.angle_degrees().to_radians(); + let bx = cw + EDIT_RADIUS * angle.sin() - EDIT_CIRCLE / 2.; + let by = ch - EDIT_RADIUS * angle.cos() - EDIT_CIRCLE / 2.; + + // Clicking selects; clicking an already-selected folder drills in. + let drills = folder_open.is_none() + && is_selected + && matches!(canvas_slot.action, Some(Action::Folder(_))); + let view_pick = view.clone(); + let on_activate = move |cx: &mut gpui::App| { + view_pick.update(cx, |v, vcx| { + if drills { + v.set_ring_folder_open(Some(slot)); + v.set_ring_selected_slot(Some(RingSlot::North)); + } else { + v.set_ring_selected_slot(Some(slot)); + } + vcx.notify(); + }); + }; + + let circle = div() + .id(("ring-editor-slot", idx)) + .absolute() + .left(px(bx)) + .top(px(by)) + .w(px(EDIT_CIRCLE)) + .h(px(EDIT_CIRCLE)) + .rounded_full() + .cursor_pointer() + .flex() + .items_center() + .justify_center() + .on_click({ + let on_activate = on_activate.clone(); + move |_, _, cx| on_activate(cx) + }); + let circle = match &canvas_slot.action { + Some(action) => circle + .bg(pal.surface) + .border_2() + .border_color(if is_selected { + rgb(ACCENT_BLUE).into() + } else { + pal.border + }) + .hover(|s| s.border_color(rgb(ACCENT_BLUE))) + .child( + svg() + .path(action_icon_path(action)) + .size_6() + .text_color(pal.text_primary), + ), + // An empty folder position: a dashed add target. + None => circle + .border_2() + .border_dashed() + .border_color(if is_selected { + rgb(ACCENT_BLUE).into() + } else { + pal.border + }) + .hover(|s| s.border_color(rgb(ACCENT_BLUE))) + .child(div().text_heading().text_color(pal.text_muted).child("+")), + }; + layer = layer.child(circle); + + if let Some(action) = &canvas_slot.action { + layer = layer.child(label_pill( + slot, + action, + (bx, by), + is_selected, + on_activate, + pal, + )); + } + } + layer.into_any_element() +} + +/// The floating label pill beside a slot circle, placed outward from the +/// ring: east-side slots label to the right, west-side to the left, North +/// above and South below — matching the Options+ canvas. Clicking the pill +/// selects (or drills, same as its circle). +fn label_pill( + slot: RingSlot, + action: &Action, + (bx, by): (f32, f32), + selected: bool, + on_activate: impl Fn(&mut gpui::App) + Clone + 'static, + pal: Palette, +) -> AnyElement { + let idx = RingSlot::ALL + .iter() + .position(|s| *s == slot) + .unwrap_or_default(); + let pill = div() + .id(("ring-editor-pill", idx)) + .px_3() + .py_1() + .rounded(pal.control_radius) + .bg(pal.surface) + .border_1() + .border_color(if selected { + rgb(ACCENT_BLUE).into() + } else { + pal.border + }) + .cursor_pointer() + .hover(|s| s.border_color(rgb(ACCENT_BLUE))) + .text_body() + .text_color(pal.text_primary) + .whitespace_nowrap() + .overflow_hidden() + .text_ellipsis() + .max_w(px(PILL_W)) + .child(localized_action_label(action)) + .on_click(move |_, _, cx| on_activate(cx)); + + let holder = div().absolute().w(px(PILL_W)).flex(); + let mid_y = by + EDIT_CIRCLE / 2. - 13.; + match slot { + RingSlot::NorthEast | RingSlot::East | RingSlot::SouthEast => holder + .left(px(bx + EDIT_CIRCLE + PILL_GAP)) + .top(px(mid_y)) + .justify_start(), + RingSlot::SouthWest | RingSlot::West | RingSlot::NorthWest => holder + .left(px(bx - PILL_GAP - PILL_W)) + .top(px(mid_y)) + .justify_end(), + RingSlot::North => holder + .left(px(bx + EDIT_CIRCLE / 2. - PILL_W / 2.)) + .top(px(by - 34.)) + .justify_center(), + RingSlot::South => holder + .left(px(bx + EDIT_CIRCLE / 2. - PILL_W / 2.)) + .top(px(by + EDIT_CIRCLE + PILL_GAP)) + .justify_center(), + } + .child(pill) + .into_any_element() +} + +/// The right-hand action panel for the selected slot: its compass name on +/// top, then the full categorized catalog plus the CUSTOM editor rows. At +/// the top level a selected folder gains an "Open Folder" row and a +/// "Folder…" row converts a plain slot; inside a folder the rows commit to +/// the folder's sub-slot (no nesting offered). +fn action_panel( + selected: RingSlot, + folder_open: Option, + actions: &BTreeMap, + view: &Entity, + pal: Palette, +) -> AnyElement { + let target = match folder_open { + Some(folder) => EditTarget::FolderSlot { + folder, + sub: selected, + }, + None => EditTarget::Slot(selected), + }; + let current = match folder_open { + Some(folder) => match actions.get(&folder) { + Some(Action::Folder(items)) => items.get(&selected).cloned().unwrap_or(Action::None), + _ => Action::None, + }, + None => actions + .get(&selected) + .cloned() + .unwrap_or_else(|| default_ring_binding(selected)), + }; + + let view_pick = view.clone(); + let on_pick: PickFn = Rc::new(move |action, _window, cx| { + target.commit(action, cx); + view_pick.update(cx, |_, vcx| vcx.notify()); + }); + + let mut rows: Vec = Vec::new(); + // A selected top-level folder: entering it is the panel's first offer. + if folder_open.is_none() && matches!(current, Action::Folder(_)) { + let view_open = view.clone(); + rows.push( + open_folder_row(pal, move |cx| { + view_open.update(cx, |v, vcx| { + v.set_ring_folder_open(Some(selected)); + v.set_ring_selected_slot(Some(RingSlot::North)); + vcx.notify(); + }); + }) + .into_any_element(), + ); + } + rows.extend(action_rows( + "ring-editor-action", + Some(¤t), + &on_pick, + pal, + )); + rows.extend(payload_rows(target, ¤t, pal)); + if folder_open.is_none() { + let view_convert = view.clone(); + let is_folder = matches!(current, Action::Folder(_)); + rows.push( + folder_convert_row(is_folder, pal, move |cx| { + cx.update_global::(|state, _| { + state.convert_ring_slot_to_folder(selected); + }); + view_convert.update(cx, |v, vcx| { + v.set_ring_folder_open(Some(selected)); + v.set_ring_selected_slot(Some(RingSlot::North)); + vcx.notify(); + }); + }) + .into_any_element(), + ); + } + + v_flex() + .w(px(PANEL_W)) + .flex_none() + .bg(pal.surface) + .border_1() + .border_color(pal.border) + .rounded(pal.card_radius) + .p_1p5() + .child(div().px_2().py_1p5().text_subheading().child(format!( + "{} {}", + selected.glyph(), + tr!(selected.label()) + ))) + .child( + div() + .id("ring-editor-panel-scroll") + .max_h(px(PANEL_LIST_H)) + .overflow_y_scroll() + .child(v_flex().children(rows)), + ) + .into_any_element() +} + +/// "Open Folder →" — the drill-in row shown while a folder is selected. +fn open_folder_row(pal: Palette, on_open: impl Fn(&mut gpui::App) + 'static) -> impl IntoElement { + h_flex() + .id("ring-editor-open-folder") + .w_full() + .items_center() + .justify_between() + .px_2() + .py_1p5() + .rounded(pal.control_radius) + .cursor_pointer() + .text_subheading() + .hover(move |s| s.bg(pal.surface_hover)) + .child( + h_flex() + .items_center() + .gap_2() + .child( + svg() + .path("action-icons/folder.svg") + .size_4() + .flex_none() + .text_color(rgb(ACCENT_BLUE)), + ) + .child(tr!("Open Folder")), + ) + .child(div().text_color(pal.text_muted).child("→")) + .on_click(move |_, _, cx| on_open(cx)) +} + +/// "Folder…" — converts the selected top-level slot into a folder (keeping +/// its action as the folder's North entry) and drills straight in. +fn folder_convert_row( + is_folder: bool, + pal: Palette, + on_convert: impl Fn(&mut gpui::App) + 'static, +) -> impl IntoElement { + h_flex() + .id("ring-editor-make-folder") + .w_full() + .items_center() + .justify_between() + .px_2() + .py_1p5() + .rounded(pal.control_radius) + .cursor_pointer() + .text_body() + .hover(move |s| s.bg(pal.surface_hover)) + .child( + h_flex() + .items_center() + .gap_2() + .child( + svg() + .path("action-icons/folder.svg") + .size_4() + .flex_none() + .text_color(pal.text_muted), + ) + .child(format!("{}…", tr!("Folder"))), + ) + .when(is_folder, |s| { + s.child( + gpui_component::Icon::new(gpui_component::IconName::Check) + .size_3() + .text_color(rgb(ACCENT_BLUE)), + ) + }) + .on_click(move |_, _, cx| on_convert(cx)) +} diff --git a/crates/openlogi-gui/src/mouse_model/view.rs b/crates/openlogi-gui/src/mouse_model/view.rs index 6acf28a2..8f12c8e2 100644 --- a/crates/openlogi-gui/src/mouse_model/view.rs +++ b/crates/openlogi-gui/src/mouse_model/view.rs @@ -22,10 +22,11 @@ use crate::mouse_model::leader_lines::{ Geometry as LeaderGeometry, Label, Side, paint as paint_leader_lines, }; use crate::mouse_model::picker::{ - GESTURE_BUTTON_ICON, action_icon_path, action_picker, gesture_overview, + GESTURE_BUTTON_ICON, RING_BUTTON_ICON, action_icon_path, action_picker, gesture_overview, }; use crate::state::AppState; use crate::theme::{self, ACCENT_BLUE, Palette, SelectableStyle, Typography as _}; +use openlogi_core::binding::RingSlot; const SIDE_W: f32 = 180.; const SIDE_GAP: f32 = 24.; @@ -62,6 +63,16 @@ pub struct MouseModelView { /// state, so the popover's `on_open_change` — which runs outside paint — can /// reset it without tripping gpui's render-only guard. gesture_active_dir: Option, + /// Whether the Action Ring's full-page editor is shown in place of the + /// mouse diagram (see [`crate::mouse_model::ring_editor`]). + ring_editor_open: bool, + /// The top-level ring slot whose folder the editor has drilled into, if + /// any — the editor then shows and edits that folder's contents. + ring_folder_open: Option, + /// Which ring slot the open Action Ring menu has activated (so its level-2 + /// flyout card shows) — the ring counterpart of + /// [`Self::gesture_active_dir`]. + ring_active_slot: Option, _state_obs: Subscription, } @@ -72,6 +83,9 @@ impl MouseModelView { Self { hovered: None, gesture_active_dir: None, + ring_editor_open: false, + ring_folder_open: None, + ring_active_slot: None, _state_obs: state_obs, } } @@ -86,10 +100,53 @@ impl MouseModelView { pub(crate) fn set_gesture_selected_dir(&mut self, dir: Option) { self.gesture_active_dir = dir; } + + /// Set (or clear, with `None`) the activated ring slot. Callers must + /// `cx.notify()` to re-render. + pub(crate) fn set_ring_selected_slot(&mut self, slot: Option) { + self.ring_active_slot = slot; + } + + /// Show or hide the Action Ring's full-page editor. Callers must + /// `cx.notify()` to re-render. Closing also pops any open folder. + pub(crate) fn set_ring_editor_open(&mut self, open: bool) { + self.ring_editor_open = open; + if !open { + self.ring_folder_open = None; + } + } + + /// Drill into (or, with `None`, back out of) a ring folder in the + /// editor. Callers must `cx.notify()` to re-render. + pub(crate) fn set_ring_folder_open(&mut self, slot: Option) { + self.ring_folder_open = slot; + } + + /// The Action Ring's full-page editor, while its scratch flag is set — + /// rendered in place of the mouse diagram (the Options+ customization-page + /// shape, entered from the ring's hotspot / label card, left via its back + /// arrow). + fn ring_editor_page(&self, cx: &mut Context) -> Option { + self.ring_editor_open.then(|| { + let view = cx.entity(); + let pal = theme::palette(cx); + crate::mouse_model::ring_editor::page( + self.ring_active_slot, + self.ring_folder_open, + &view, + pal, + cx, + ) + }) + } } impl Render for MouseModelView { fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { + if let Some(page) = self.ring_editor_page(cx) { + return page; + } + let (asset, active, bindings, gesture_owner, glow) = cx .try_global::() .map(|s| { @@ -162,6 +219,15 @@ impl Render for MouseModelView { is_default: false, icon: Some(GESTURE_BUTTON_ICON), } + } else if label.id == ButtonId::ActionRing { + // The ring's card summarizes its slot map — its single- + // action projection is deliberately `None` and would + // mislabel the pad as "Do Nothing". + BindingLabel { + text: tr!("8 actions"), + is_default: false, + icon: Some(RING_BUTTON_ICON), + } } else { // `bindings` is seeded for every `ButtonId::ALL` (agent-core // `bindings_for`), so a rendered non-gesture button always @@ -204,6 +270,7 @@ impl Render for MouseModelView { col.child(gesture_owner_selector(&capable, gesture_owner, &view, pal)) }) .child(canvas) + .into_any_element() } } @@ -498,6 +565,21 @@ fn label_popover( view.clone(), ) .into_any_element() + } else if label.id == ButtonId::ActionRing { + // The ring gets the full-page editor, not a popover: clicking the + // card swaps the diagram for it. + let view_open = view.clone(); + div() + .id(("label-ring-editor", idx)) + .cursor_pointer() + .on_click(move |_, _, cx| { + view_open.update(cx, |v, vcx| { + v.set_ring_editor_open(true); + vcx.notify(); + }); + }) + .child(trigger) + .into_any_element() } else { Popover::new(("label-popover", idx)) // `action_picker` draws its own `menu_card` surface, matching the @@ -647,7 +729,7 @@ impl RenderOnce for LabelTrigger { } } -fn localized_action_label(action: &Action) -> gpui::SharedString { +pub(crate) fn localized_action_label(action: &Action) -> gpui::SharedString { match action { Action::SetDpiPreset(index) => { tr!("DPI Preset %{index}", index => (index + 1).to_string()) @@ -731,6 +813,20 @@ fn hotspot_popover( view.clone(), ) .into_any_element() + } else if hotspot.id == ButtonId::ActionRing { + // Same full-page editor entry as the ring's label card. + let view_open = view.clone(); + div() + .id(("hotspot-ring-editor", idx)) + .cursor_pointer() + .on_click(move |_, _, cx| { + view_open.update(cx, |v, vcx| { + v.set_ring_editor_open(true); + vcx.notify(); + }); + }) + .child(trigger) + .into_any_element() } else { Popover::new(("hotspot-popover", idx)) // `action_picker` draws its own `menu_card` surface, matching the diff --git a/crates/openlogi-gui/src/ring.rs b/crates/openlogi-gui/src/ring.rs new file mode 100644 index 00000000..6ee321c3 --- /dev/null +++ b/crates/openlogi-gui/src/ring.rs @@ -0,0 +1,934 @@ +//! The on-screen Action Ring overlay. +//! +//! Interaction model (specified, not guessed): a pad tap opens the ring +//! centred at the cursor; the pointer then moves normally (never captured); +//! a second tap fires the sector the cursor points toward and closes the +//! ring. Cancel: the centre ✕ (click or second tap in the dead zone), `Esc`, +//! or a click outside the ring. +//! +//! The window is a borderless, transparent, always-on-top popup that never +//! takes focus — the action must land in the app the user was using, so +//! focus must not move. GPUI's `WindowKind::PopUp` provides the borderless +//! toolwindow; the no-activate + topmost bits and all show/hide/positioning +//! go through the raw HWND (see [`platform_win`]), because the pinned gpui +//! Windows backend exposes neither. The window is created once on first use +//! and then re-positioned and re-shown per open — no per-tap surface setup. +//! +//! Sector *selection* is plain cursor geometry: the angle from the ring's +//! centre to the global cursor picks the sector, the centre dead zone +//! cancels. The cursor may leave the little overlay window entirely ("move +//! toward" can overshoot) — that changes nothing, since the watcher reads the +//! global cursor, not window-local hover. + +use std::time::Duration; + +use gpui::{ + App, AppContext as _, Bounds, Context, InteractiveElement as _, IntoElement, + ParentElement as _, Point, Render, StatefulInteractiveElement as _, Styled as _, Window, + WindowBounds, WindowHandle, WindowKind, WindowOptions, div, point, px, size, +}; +use gpui_component::{ActiveTheme as _, Icon}; +use openlogi_core::binding::{Action, RingSlot}; +use tokio::sync::mpsc; +use tracing::{debug, info, warn}; + +use crate::ipc_client::Command; +use crate::mouse_model::picker::action_icon_path; +use crate::state::AppState; + +/// Logical size of the (square) overlay window — just big enough for the +/// button circle plus shadows. The popup carries no labels, so it stays +/// tight; near a screen edge [`platform_win::show_at`] clamps it into the +/// work area. +const RING_WINDOW: f32 = 240.; +/// Radius of the circle the eight sector buttons sit on, from the centre. +/// Matched to the real Options+ ring: adjacent circles nearly touch. +const SECTOR_RADIUS: f32 = 86.; +/// Diameter of one sector's circular icon button. +const SECTOR_BUTTON: f32 = 48.; +/// Diameter of the centre ✕ cancel button. +const CENTER_BUTTON: f32 = 36.; +/// Cursor distance (logical px) below which a confirm means "cancel" — the +/// dead zone around the centre ✕. +const DEADZONE: f32 = 34.; +/// How often the open-ring watcher samples the global cursor (highlight) and +/// the Esc / outside-click cancel signals. +const WATCH_TICK: Duration = Duration::from_millis(33); + +// The ring's fixed palette, deliberately theme-independent and light-on-dark +// — the inverse of the Options+ light-mode reference, because the ring floats +// over a desktop that lives in dark mode: bright circles, dark label pills. +/// Sector button fill. +const PLATE: u32 = 0x00f7_f7f9; +/// Icon strokes on an unaimed button. +const INK: u32 = 0x001c_1c1e; +/// Aimed icon strokes. +const WHITE: u32 = 0x00ff_ffff; +/// Centre ✕ fill — the Options+ crimson cancel button. +const CROSS_BG: u32 = 0x00b0_2a38; +/// Centre ✕ fill while the cursor aims at the dead zone. +const CROSS_BG_AIMED: u32 = 0x00c9_3a49; +/// Centre ✕ glyph. +const CROSS_TEXT: u32 = 0x00ff_ffff; + +/// What the cursor currently points at, driven from the global cursor by the +/// watcher so it works even when the pointer is outside the overlay window. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] +enum Aim { + /// Inside the dead zone (or no cursor data): a confirm cancels. + #[default] + Center, + /// Toward a sector: a confirm fires its action. + Sector(RingSlot), +} + +/// Pick the aim for a cursor at `cursor` when the ring is centred at +/// `center`, both in the same (physical) coordinate space, with the dead +/// zone scaled by `scale`. Pure, so the sector math is unit-testable. +fn aim_for(center: Point, cursor: Point, scale: f32) -> Aim { + let dx = cursor.x - center.x; + let dy = cursor.y - center.y; + if (dx * dx + dy * dy).sqrt() < DEADZONE * scale { + return Aim::Center; + } + // Angle clockwise from straight up, matching `RingSlot::angle_degrees`. + let degrees = dx.atan2(-dy).to_degrees().rem_euclid(360.); + #[expect( + clippy::cast_possible_truncation, + clippy::cast_sign_loss, + reason = "degrees is in [0, 360), so the sector index is in 0..=8" + )] + let index = (((degrees + 22.5) / 45.).floor() as usize) % 8; + Aim::Sector(RingSlot::ALL[index]) +} + +/// The overlay's app-global controller: the singleton window, whether it is +/// currently shown, and the plumbing to fire the selected action. +pub struct RingOverlay { + commands: mpsc::UnboundedSender, + window: Option>, + open: bool, + /// Physical-pixel centre of the open ring, for global-cursor hit tests. + center: Point, + /// Physical-per-logical scale of the display the ring opened on. + scale: f32, + /// Generation counter; bumping it retires the previous open's watcher. + epoch: u64, + /// Config key of the device whose pad opened this ring, carried on the + /// press. Slot lookups use it rather than the carousel selection — see + /// [`AppState::ring_slots_for_device`]. + device_key: Option, +} + +impl gpui::Global for RingOverlay {} + +/// Install the controller. Call once at startup, before the first press can +/// arrive. +pub fn init(commands: mpsc::UnboundedSender, cx: &mut App) { + cx.set_global(RingOverlay { + commands, + window: None, + open: false, + center: point(0., 0.), + scale: 1., + epoch: 0, + device_key: None, + }); + // Create the hidden overlay window eagerly rather than on the first tap: + // it removes window-construction latency from the first open, and — since + // it is never closed, only hidden — it keeps this on-demand GUI process + // alive past "quit when the last window closes", so the ring survives the + // user closing the settings window. Windows-only, like the overlay + // itself: elsewhere an invisible popup would still surface in window + // switchers. + #[cfg(target_os = "windows")] + if let Some(window) = create_window(Vec::new(), cx) { + cx.global_mut::().window = Some(window); + } +} + +/// Handle one Action Ring pad press from the agent: open the ring when it is +/// closed, confirm the aimed selection when it is open. +pub fn on_pad_press(device_key: Option, cx: &mut App) { + if cx.global::().open { + confirm(cx); + } else { + // The press names its own device; remember it for this open so the + // slots — and every re-read while the ring is up — come from the pad's + // mouse rather than whatever the carousel shows. + cx.global_mut::().device_key = device_key; + open(cx); + } +} + +/// The slots to render: always the pad's own device (carried on the press), +/// never the carousel selection. +fn ring_slots(cx: &App) -> Vec<(RingSlot, Action)> { + let key = cx.global::().device_key.clone(); + cx.global::() + .ring_slots_for_device(key.as_deref()) +} + +/// Open the ring centred at the cursor. +fn open(cx: &mut App) { + let Some(cursor) = platform_win::cursor_pos() else { + // Non-Windows builds have no overlay plumbing yet; the press is + // captured and bindable, the on-screen ring is Windows-first. + info!("action ring press ignored — no overlay support on this platform yet"); + return; + }; + + let slots = ring_slots(cx); + let window = match cx.global::().window { + Some(window) => { + let refreshed = window.update(cx, |view, _, cx| { + view.slots.clone_from(&slots); + view.in_folder = false; + view.aim = Aim::Center; + cx.notify(); + }); + if refreshed.is_err() { + // The window was closed out from under us (display change, + // gpui teardown) — recreate below. + cx.global_mut::().window = None; + } + match cx.global::().window { + Some(window) => window, + None => match create_window(slots, cx) { + Some(window) => window, + None => return, + }, + } + } + None => match create_window(slots, cx) { + Some(window) => window, + None => return, + }, + }; + + let Some(hwnd) = window_hwnd(&window, cx) else { + warn!("action ring window has no HWND — cannot show the overlay"); + return; + }; + // The app's theme plumbing re-stamps window background appearance across + // every window when a theme applies, flipping this overlay back to Opaque + // — whose clear colour is solid white, i.e. the "box behind the ring". + // Re-assert transparency on every open, then strip the DWM accent veil + // the Transparent path re-enables (see [`platform_win::clear_accent`]). + let _ = window.update(cx, |_, window, _| { + window.set_background_appearance(gpui::WindowBackgroundAppearance::Transparent); + }); + platform_win::clear_accent(hwnd); + + let scale = platform_win::window_scale(hwnd); + platform_win::apply_ring_region(hwnd, scale); + // The centre can differ from the cursor near a screen edge (work-area + // clamp) — the hit-test must aim from the ring's real centre. + let center = platform_win::show_at(hwnd, cursor, RING_WINDOW * scale, RING_WINDOW * scale); + + let overlay = cx.global_mut::(); + overlay.window = Some(window); + overlay.open = true; + overlay.center = center; + overlay.scale = scale; + overlay.epoch += 1; + let epoch = overlay.epoch; + debug!(x = center.x, y = center.y, "action ring opened"); + + // While open: track the global cursor for the sector highlight, and close + // on Esc or a click outside the window — inputs a no-activate window + // never receives as messages. + cx.spawn(async move |cx| { + loop { + cx.background_executor().timer(WATCH_TICK).await; + if cx.update(|cx| watch_tick(epoch, hwnd, cx)) { + break; + } + } + }) + .detach(); +} + +/// One watcher pass. Returns `true` when this watcher is done (ring closed or +/// superseded by a newer open). +fn watch_tick(epoch: u64, hwnd: isize, cx: &mut App) -> bool { + { + let overlay = cx.global::(); + if !overlay.open || overlay.epoch != epoch { + return true; + } + } + if platform_win::escape_pressed() || platform_win::clicked_outside(hwnd) { + debug!("action ring cancelled (esc / outside click)"); + close(cx); + return true; + } + let (center, scale) = { + let overlay = cx.global::(); + (overlay.center, overlay.scale) + }; + let aim = + platform_win::cursor_pos().map_or(Aim::Center, |cursor| aim_for(center, cursor, scale)); + let window = cx.global::().window; + if let Some(window) = window { + let _ = window.update(cx, |view, _, cx| { + if view.aim != aim { + view.aim = aim; + cx.notify(); + } + }); + } + false +} + +/// Confirm the current aim: fire the aimed sector, or — from the dead zone — +/// step back out of an open folder / cancel from the main ring. +fn confirm(cx: &mut App) { + let (center, scale) = { + let overlay = cx.global::(); + (overlay.center, overlay.scale) + }; + let aim = + platform_win::cursor_pos().map_or(Aim::Center, |cursor| aim_for(center, cursor, scale)); + match aim { + Aim::Center => { + if view_in_folder(cx) { + back_to_main(cx); + } else { + debug!("action ring cancelled (centre tap)"); + close(cx); + } + } + Aim::Sector(slot) => activate(slot, cx), + } +} + +/// Fire `slot`: a folder swaps the ring to its contents (staying open); a +/// leaf action goes to the agent and closes the ring; an empty sector — a +/// sparse folder position — does nothing. +fn activate(slot: RingSlot, cx: &mut App) { + let Some(window) = cx.global::().window else { + return; + }; + let Ok((action, in_folder)) = + window.update(cx, |view, _, _| (view.action_for(slot), view.in_folder)) + else { + return; + }; + let Some(action) = action else { + return; + }; + // A user label is presentation only: resolve folders and dispatch by + // what the action actually is. + match action.inner().clone() { + Action::Folder(items) if !in_folder => { + let items: Vec<(RingSlot, Action)> = items + .into_iter() + .filter(|(_, action)| !matches!(action, Action::None)) + .collect(); + if items.is_empty() { + debug!("empty folder — ignored"); + return; + } + info!(slot = %slot, "action ring → folder"); + let _ = window.update(cx, |view, _, cx| { + view.slots = items; + view.in_folder = true; + view.aim = Aim::Center; + cx.notify(); + }); + } + // One level deep by convention — a folder nested inside a folder is + // ignored rather than dispatched (the injector would only warn). + Action::Folder(_) => warn!("nested folder ignored"), + action => { + info!(slot = %slot, action = %action.label(), "action ring → action"); + if cx + .global::() + .commands + .send(Command::ExecuteAction(action)) + .is_err() + { + warn!("IPC client is gone — ring action dropped"); + } + close(cx); + } + } +} + +/// Whether the open ring currently shows a folder's contents. +fn view_in_folder(cx: &mut App) -> bool { + cx.global::() + .window + .and_then(|window| window.update(cx, |view, _, _| view.in_folder).ok()) + .unwrap_or(false) +} + +/// Swap an open folder back to the main ring. +fn back_to_main(cx: &mut App) { + let slots = ring_slots(cx); + if let Some(window) = cx.global::().window { + let _ = window.update(cx, |view, _, cx| { + view.slots.clone_from(&slots); + view.in_folder = false; + view.aim = Aim::Center; + cx.notify(); + }); + } + debug!("action ring folder closed — back to the main ring"); +} + +/// Hide the ring. +fn close(cx: &mut App) { + let overlay = cx.global_mut::(); + overlay.open = false; + overlay.epoch += 1; + let window = overlay.window; + if let Some(window) = window + && let Some(hwnd) = window_hwnd(&window, cx) + { + platform_win::hide(hwnd); + } +} + +/// Create the overlay window (hidden — [`platform_win::show_at`] reveals it). +fn create_window(slots: Vec<(RingSlot, Action)>, cx: &mut App) -> Option> { + let bounds = Bounds { + origin: point(px(0.), px(0.)), + size: size(px(RING_WINDOW), px(RING_WINDOW)), + }; + let options = WindowOptions { + window_bounds: Some(WindowBounds::Windowed(bounds)), + titlebar: None, + app_id: Some("openlogi".to_string()), + kind: WindowKind::PopUp, + is_movable: false, + focus: false, + show: false, + window_background: gpui::WindowBackgroundAppearance::Transparent, + ..WindowOptions::default() + }; + let opened = cx.open_window(options, |_, cx| { + cx.new(|_| RingView { + slots, + in_folder: false, + aim: Aim::Center, + }) + }); + match opened { + Ok(window) => { + if let Some(hwnd) = window_hwnd(&window, cx) { + platform_win::apply_overlay_style(hwnd); + platform_win::clear_accent(hwnd); + } + Some(window) + } + Err(e) => { + warn!(error = %e, "could not open the action ring window"); + None + } + } +} + +/// The raw Win32 handle of a gpui window (`None` off Windows). +fn window_hwnd(window: &WindowHandle, cx: &mut App) -> Option { + window + .update(cx, |_, window, _| { + use raw_window_handle::{HasWindowHandle as _, RawWindowHandle}; + match window.window_handle().ok()?.as_raw() { + RawWindowHandle::Win32(handle) => Some(isize::from(handle.hwnd)), + _ => None, + } + }) + .ok() + .flatten() +} + +/// The ring's root view: sector buttons on a circle and the centre ✕ — or, +/// while a folder is open, the folder's (possibly sparse) contents with a +/// centre ← that steps back to the main ring. +pub struct RingView { + slots: Vec<(RingSlot, Action)>, + in_folder: bool, + aim: Aim, +} + +impl RingView { + fn action_for(&self, slot: RingSlot) -> Option { + self.slots + .iter() + .find(|(s, _)| *s == slot) + .map(|(_, action)| action.clone()) + } +} + +impl Render for RingView { + fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { + // The popup is just the eight circles and the centre ✕ — no labels + // (those belong to the customization page) and no panel behind + // anything. Fixed bright-on-dark identity in both themes; the theme's + // primary marks the aimed sector. + let accent = cx.theme().primary; + let (cx0, cy0) = (RING_WINDOW / 2., RING_WINDOW / 2.); + + let sectors = self.slots.iter().map(|(slot, action)| { + let angle = slot.angle_degrees().to_radians(); + let bx = cx0 + SECTOR_RADIUS * angle.sin() - SECTOR_BUTTON / 2.; + let by = cy0 - SECTOR_RADIUS * angle.cos() - SECTOR_BUTTON / 2.; + let aimed = self.aim == Aim::Sector(*slot); + let slot_for_click = *slot; + div().absolute().left(px(bx)).top(px(by)).child( + div() + .id(SharedStringId(slot.label())) + .size(px(SECTOR_BUTTON)) + .rounded_full() + .flex() + .items_center() + .justify_center() + .bg(if aimed { + accent + } else { + gpui::rgb(PLATE).into() + }) + .shadow_md() + .child( + Icon::empty() + .path(action_icon_path(action)) + .size_5() + .text_color(if aimed { + gpui::rgb(WHITE) + } else { + gpui::rgb(INK) + }), + ) + .on_click(cx.listener(move |_, _, _, cx| { + cx.defer(move |cx| activate(slot_for_click, cx)); + })), + ) + }); + + div().size_full().relative().children(sectors).child( + // Centre ✕ — click (or a second pad tap in the dead zone) cancels. + div() + .id("ring-cancel") + .absolute() + .left(px(cx0 - CENTER_BUTTON / 2.)) + .top(px(cy0 - CENTER_BUTTON / 2.)) + .size(px(CENTER_BUTTON)) + .rounded_full() + .flex() + .items_center() + .justify_center() + .bg(if self.aim == Aim::Center { + gpui::rgb(CROSS_BG_AIMED) + } else { + gpui::rgb(CROSS_BG) + }) + .shadow_sm() + .text_xs() + .text_color(gpui::rgb(CROSS_TEXT)) + .child(if self.in_folder { "←" } else { "✕" }) + .on_click(cx.listener(|view, _, _, cx| { + if view.in_folder { + cx.defer(back_to_main); + } else { + cx.defer(close); + } + })), + ) + } +} + +/// Ad-hoc `ElementId` source for per-slot stateful divs. +#[derive(Clone)] +struct SharedStringId(&'static str); + +impl From for gpui::ElementId { + fn from(id: SharedStringId) -> Self { + gpui::ElementId::Name(id.0.into()) + } +} + +/// Raw Win32 plumbing for the overlay: the style bits gpui doesn't expose +/// (no-activate, topmost), show/hide without activation, physical-pixel +/// positioning, the global cursor, and the Esc / outside-click cancel +/// signals a focusless window can't observe as messages. +#[cfg(target_os = "windows")] +#[expect( + unsafe_code, + reason = "raw Win32 window-style and cursor FFI — the pinned gpui backend exposes none of it" +)] +mod platform_win { + use gpui::Point; + use gpui::point; + use windows_sys::Win32::Foundation::{POINT, RECT}; + use windows_sys::Win32::Graphics::Gdi::{ + CombineRgn, CreateEllipticRgn, DeleteObject, GetMonitorInfoW, MONITOR_DEFAULTTONEAREST, + MONITORINFO, MonitorFromPoint, RGN_OR, SetWindowRgn, + }; + use windows_sys::Win32::System::LibraryLoader::{GetModuleHandleW, GetProcAddress}; + use windows_sys::Win32::UI::HiDpi::GetDpiForWindow; + use windows_sys::Win32::UI::Input::KeyboardAndMouse::{ + GetAsyncKeyState, VK_ESCAPE, VK_LBUTTON, + }; + use windows_sys::Win32::UI::WindowsAndMessaging::{ + GWL_EXSTYLE, GetCursorPos, GetWindowLongPtrW, GetWindowRect, HWND_TOPMOST, SW_HIDE, + SWP_NOACTIVATE, SetWindowLongPtrW, SetWindowPos, ShowWindow, WS_EX_NOACTIVATE, + WS_EX_TOOLWINDOW, + }; + + /// Add the no-activate + toolwindow ex-style bits. Topmost is applied on + /// every [`show_at`] (a style bit alone does not raise the window). + pub fn apply_overlay_style(hwnd: isize) { + // SAFETY: plain style read-modify-write on a window this process owns. + unsafe { + let hwnd = hwnd as _; + let ex = GetWindowLongPtrW(hwnd, GWL_EXSTYLE); + SetWindowLongPtrW( + hwnd, + GWL_EXSTYLE, + ex | isize::from_ne_bytes( + ((WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW) as usize).to_ne_bytes(), + ), + ); + } + } + + /// Physical-per-logical scale of the display the window is on. + #[expect( + clippy::cast_precision_loss, + reason = "display DPI values are small integers — exact in f32" + )] + pub fn window_scale(hwnd: isize) -> f32 { + // SAFETY: DPI read on a window this process owns. + let dpi = unsafe { GetDpiForWindow(hwnd as _) }; + if dpi == 0 { 1. } else { dpi as f32 / 96. } + } + + /// Centre the window (physical size `w`×`h`) at `cursor` (physical), + /// clamped into the cursor's monitor **work area** so the ring never + /// hangs off a screen edge, and show it topmost without activating it. + /// Returns the window's actual centre — near an edge it differs from the + /// cursor, and the sector hit-test must aim from where the ring really is. + pub fn show_at(hwnd: isize, cursor: Point, w: f32, h: f32) -> Point { + #[expect( + clippy::cast_possible_truncation, + reason = "screen coordinates are far inside i32 range" + )] + let (cx, cy, w, h) = (cursor.x as i32, cursor.y as i32, w as i32, h as i32); + let mut x = cx - w / 2; + let mut y = cy - h / 2; + // SAFETY: monitor lookup for the cursor's point, then position + show + // of a window this process owns; SWP_NOACTIVATE keeps focus where the + // user is working. + unsafe { + let monitor = MonitorFromPoint(POINT { x: cx, y: cy }, MONITOR_DEFAULTTONEAREST); + let zero = RECT { + left: 0, + top: 0, + right: 0, + bottom: 0, + }; + #[expect( + clippy::cast_possible_truncation, + reason = "a fixed struct size is far below u32::MAX" + )] + let mut info = MONITORINFO { + cbSize: size_of::() as u32, + rcMonitor: zero, + rcWork: zero, + dwFlags: 0, + }; + if GetMonitorInfoW(monitor, &raw mut info) != 0 { + let work = info.rcWork; + x = x.max(work.left).min(work.right - w); + y = y.max(work.top).min(work.bottom - h); + } + SetWindowPos( + hwnd as _, + HWND_TOPMOST, + x, + y, + w, + h, + SWP_NOACTIVATE | windows_sys::Win32::UI::WindowsAndMessaging::SWP_SHOWWINDOW, + ); + } + #[expect( + clippy::cast_precision_loss, + reason = "screen coordinates are far inside f32's exact-integer range" + )] + point((x + w / 2) as f32, (y + h / 2) as f32) + } + + /// Clip the window to just the ring's circles — the eight sector buttons + /// and the centre ✕. Whatever the compositor decides about the surface's + /// alpha, no window rectangle exists to show a backdrop (the same region + /// trick other overlay apps use on Windows), and clicks between the + /// circles fall through to whatever is underneath. Coordinates are + /// physical pixels; rebuilt per open because the display scale can change + /// between monitors. + pub fn apply_ring_region(hwnd: isize, scale: f32) { + use openlogi_core::binding::RingSlot; + + let c = super::RING_WINDOW / 2.; + // A little margin keeps each button's shadow from clipping flat. + let sector_r = super::SECTOR_BUTTON / 2. + 4.; + let center_r = super::CENTER_BUTTON / 2. + 3.; + #[expect( + clippy::cast_possible_truncation, + reason = "window-local coordinates are far inside i32 range" + )] + let p = |v: f32| (v * scale).round() as i32; + // SAFETY: plain GDI region construction on a window this process + // owns; SetWindowRgn takes ownership of the combined region on + // success, and each per-circle scratch region is deleted after it is + // OR-ed in. + unsafe { + let region = CreateEllipticRgn( + p(c - center_r), + p(c - center_r), + p(c + center_r), + p(c + center_r), + ); + if region.is_null() { + return; + } + for slot in RingSlot::ALL { + let angle = slot.angle_degrees().to_radians(); + let bx = c + super::SECTOR_RADIUS * angle.sin(); + let by = c - super::SECTOR_RADIUS * angle.cos(); + let circle = CreateEllipticRgn( + p(bx - sector_r), + p(by - sector_r), + p(bx + sector_r), + p(by + sector_r), + ); + if circle.is_null() { + continue; + } + CombineRgn(region, region, circle, RGN_OR); + DeleteObject(circle.cast()); + } + SetWindowRgn(hwnd as _, region, 1); + } + } + + /// Disable the window's DWM "accent" effect. gpui's `Transparent` + /// background enables `ACCENT_ENABLE_TRANSPARENTGRADIENT`, which paints a + /// faint veil over the whole window rect; DirectComposition already + /// composites the surface with per-pixel alpha, so the veil is pure + /// artifact — the visible "box" behind the floating ring. This calls the + /// same undocumented user32 API gpui itself uses, with the accent off. + pub fn clear_accent(hwnd: isize) { + #[repr(C)] + struct AccentPolicy { + state: u32, + flags: u32, + gradient_color: u32, + animation_id: u32, + } + #[repr(C)] + struct CompositionAttribData { + attrib: u32, + data: *mut core::ffi::c_void, + size: u32, + } + const WCA_ACCENT_POLICY: u32 = 19; + type SetWca = + unsafe extern "system" fn(hwnd: isize, data: *mut CompositionAttribData) -> i32; + + // SAFETY: resolve the export from user32 (it is not in the import + // library), then call it with a stack-valid attribute payload. + unsafe { + let user32: Vec = "user32.dll\0".encode_utf16().collect(); + let module = GetModuleHandleW(user32.as_ptr()); + if module.is_null() { + return; + } + let Some(addr) = + GetProcAddress(module, c"SetWindowCompositionAttribute".as_ptr().cast()) + else { + return; + }; + let set_wca: SetWca = core::mem::transmute(addr); + let mut policy = AccentPolicy { + state: 0, // ACCENT_DISABLED + flags: 0, + gradient_color: 0, + animation_id: 0, + }; + #[expect( + clippy::cast_possible_truncation, + reason = "a fixed struct size is far below u32::MAX" + )] + let mut data = CompositionAttribData { + attrib: WCA_ACCENT_POLICY, + data: (&raw mut policy).cast(), + size: size_of::() as u32, + }; + set_wca(hwnd, &raw mut data); + } + } + + /// Hide the window (kept alive for the next open). + pub fn hide(hwnd: isize) { + // SAFETY: hide of a window this process owns. + unsafe { + ShowWindow(hwnd as _, SW_HIDE); + } + } + + /// Global cursor position in physical pixels. + pub fn cursor_pos() -> Option> { + let mut p = POINT { x: 0, y: 0 }; + // SAFETY: out-pointer to a stack POINT. + #[expect( + clippy::cast_precision_loss, + reason = "screen coordinates are far inside f32's exact-integer range" + )] + if unsafe { GetCursorPos(&raw mut p) } != 0 { + Some(point(p.x as f32, p.y as f32)) + } else { + None + } + } + + /// Whether Esc is down right now (edge behaviour handled by the caller's + /// close-once state machine — the ring is gone before a repeat matters). + pub fn escape_pressed() -> bool { + // SAFETY: stateless key query. + unsafe { GetAsyncKeyState(i32::from(VK_ESCAPE)).cast_unsigned() & 0x8000 != 0 } + } + + /// Whether the left button is down with the cursor outside the window — + /// the "click outside cancels" signal, observed by polling because a + /// no-activate window receives no messages for clicks elsewhere. + pub fn clicked_outside(hwnd: isize) -> bool { + // SAFETY: stateless key query + window-rect read on an owned window. + unsafe { + if GetAsyncKeyState(i32::from(VK_LBUTTON)).cast_unsigned() & 0x8000 == 0 { + return false; + } + let mut rect = RECT { + left: 0, + top: 0, + right: 0, + bottom: 0, + }; + if GetWindowRect(hwnd as _, &raw mut rect) == 0 { + return false; + } + let mut p = POINT { x: 0, y: 0 }; + if GetCursorPos(&raw mut p) == 0 { + return false; + } + p.x < rect.left || p.x > rect.right || p.y < rect.top || p.y > rect.bottom + } + } +} + +/// Non-Windows stubs: the ring is captured and bindable everywhere, but the +/// overlay window itself is Windows-first (macOS/Linux land with their own +/// platform plumbing). +#[cfg(not(target_os = "windows"))] +mod platform_win { + use gpui::Point; + + pub fn apply_overlay_style(_hwnd: isize) {} + pub fn window_scale(_hwnd: isize) -> f32 { + 1. + } + pub fn show_at(_hwnd: isize, cursor: Point, _w: f32, _h: f32) -> Point { + cursor + } + pub fn apply_ring_region(_hwnd: isize, _scale: f32) {} + pub fn clear_accent(_hwnd: isize) {} + pub fn hide(_hwnd: isize) {} + pub fn cursor_pos() -> Option> { + None + } + pub fn escape_pressed() -> bool { + false + } + pub fn clicked_outside(_hwnd: isize) -> bool { + false + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn sector(center: Point, dx: f32, dy: f32) -> Aim { + aim_for(center, point(center.x + dx, center.y + dy), 1.) + } + + #[test] + fn dead_zone_aims_center() { + let c = point(500., 500.); + assert_eq!(sector(c, 0., 0.), Aim::Center); + // Just inside the zone boundary, on a diagonal — const-relative so a + // DEADZONE retune doesn't silently rot this case. + let inside = (DEADZONE - 1.) / 2_f32.sqrt(); + assert_eq!( + sector(c, inside, -inside), + Aim::Center, + "inside the dead zone" + ); + let outside = (DEADZONE + 1.) / 2_f32.sqrt(); + assert_eq!( + sector(c, outside, -outside), + Aim::Sector(RingSlot::NorthEast), + "just past the dead zone" + ); + } + + #[test] + fn cardinal_directions_pick_their_slots() { + let c = point(500., 500.); + assert_eq!(sector(c, 0., -200.), Aim::Sector(RingSlot::North)); + assert_eq!(sector(c, 200., 0.), Aim::Sector(RingSlot::East)); + assert_eq!(sector(c, 0., 200.), Aim::Sector(RingSlot::South)); + assert_eq!(sector(c, -200., 0.), Aim::Sector(RingSlot::West)); + } + + #[test] + fn diagonals_and_sector_boundaries_route_clockwise() { + let c = point(0., 0.); + assert_eq!(sector(c, 100., -100.), Aim::Sector(RingSlot::NorthEast)); + assert_eq!(sector(c, 100., 100.), Aim::Sector(RingSlot::SouthEast)); + assert_eq!(sector(c, -100., 100.), Aim::Sector(RingSlot::SouthWest)); + assert_eq!(sector(c, -100., -100.), Aim::Sector(RingSlot::NorthWest)); + // 22.4° off vertical still rounds to North; 22.6° tips into NorthEast. + let west_of_boundary = (22.4_f32).to_radians(); + let east_of_boundary = (22.6_f32).to_radians(); + assert_eq!( + sector( + c, + 200. * west_of_boundary.sin(), + -200. * west_of_boundary.cos() + ), + Aim::Sector(RingSlot::North) + ); + assert_eq!( + sector( + c, + 200. * east_of_boundary.sin(), + -200. * east_of_boundary.cos() + ), + Aim::Sector(RingSlot::NorthEast) + ); + } + + #[test] + fn scale_grows_the_dead_zone() { + let c = point(0., 0.); + // 60 px out: a sector at 1×, still the dead zone at 2×. + assert_eq!( + aim_for(c, point(0., -60.), 1.), + Aim::Sector(RingSlot::North) + ); + assert_eq!(aim_for(c, point(0., -60.), 2.), Aim::Center); + } +} diff --git a/crates/openlogi-gui/src/state.rs b/crates/openlogi-gui/src/state.rs index c6a74711..28b3914a 100644 --- a/crates/openlogi-gui/src/state.rs +++ b/crates/openlogi-gui/src/state.rs @@ -388,9 +388,23 @@ impl AppState { } let previous_key = self.current_record().map(|r| r.config_key.clone()); + // Keep the live selection; if it is gone — or there is none yet — + // restore the persisted one before falling back to "first device". + // + // The GUI launches before enumeration finishes, so its first device + // list is empty and `with_runtime` has nothing to match + // `selected_device` against. Without this second chance the saved + // choice is silently lost the moment devices actually arrive, and the + // carousel lands on whichever device sorts first — for a mouse+keyboard + // pair, the keyboard. That is not cosmetic: the agent points its + // control-capture session at the selected device, so a mouse demoted + // this way stops having its buttons captured at all. + let saved_key = self.config.selected_device().map(str::to_owned); + let find = |key: &str| merged_list.iter().position(|r| r.config_key == key); let new_index = previous_key .as_deref() - .and_then(|k| merged_list.iter().position(|r| r.config_key == k)) + .and_then(find) + .or_else(|| saved_key.as_deref().and_then(find)) .unwrap_or(0); let connected_keys = merged_list .iter() @@ -1130,6 +1144,45 @@ impl AppState { ) } + /// The eight Action Ring sector actions for the selected device, defaults + /// filled — what the ring overlay renders and fires. A non-ring stored + /// binding (the pad demoted to a single action) still yields the default + /// map: the agent only routes presses to the overlay while the binding is + /// ring-shaped, so this is display data, never dispatch policy. + #[must_use] + pub fn ring_slots_for_current(&self) -> Vec<(openlogi_core::binding::RingSlot, Action)> { + let key = self.current_record().map(|r| r.config_key.clone()); + self.ring_slots_for_device(key.as_deref()) + } + + /// The Action Ring sector actions stored for `device_key` — what the + /// on-screen ring renders for the pad that fired. + /// + /// The overlay must pass the *pressing* device's key rather than relying + /// on [`Self::ring_slots_for_current`]: the carousel often shows another + /// device (a keyboard, or a second mouse), and since defaults are filled + /// in below, resolving against it would render a ring the user never + /// configured instead of theirs. + #[must_use] + pub fn ring_slots_for_device( + &self, + device_key: Option<&str>, + ) -> Vec<(openlogi_core::binding::RingSlot, Action)> { + use openlogi_core::binding::{RingSlot, default_binding_for}; + let stored = device_key + .and_then(|key| self.config.bindings_for(key).remove(&ButtonId::ActionRing)) + .filter(Binding::is_ring); + let mut binding = stored.unwrap_or_else(|| default_binding_for(ButtonId::ActionRing)); + binding.fill_ring_defaults(); + RingSlot::ALL + .into_iter() + .map(|slot| { + let action = binding.ring_action(slot).cloned().unwrap_or(Action::None); + (slot, action) + }) + .collect() + } + fn gesture_bindings_for_current(&self) -> BTreeMap { let Some(key) = self.current_record().map(|r| r.config_key.as_str()) else { return BTreeMap::new(); @@ -1180,6 +1233,46 @@ impl AppState { /// Update a single gesture-button sub-binding in memory, on disk, and in the /// shared gesture map the watcher thread reads. + /// Persist one Action Ring slot for the selected device and have the + /// agent reload. The overlay reads its slots from this config on every + /// open, so the next ring already shows the change. + pub fn commit_ring_binding(&mut self, slot: openlogi_core::binding::RingSlot, action: Action) { + let Some(key) = self.current_record().map(|r| r.config_key.clone()) else { + debug!(?slot, "no active device key — ring binding edit ignored"); + return; + }; + self.config.set_ring_slot(&key, slot, action); + self.persist_and_reload("ring binding"); + } + + /// Persist one sub-slot inside the folder at ring `slot` (converting the + /// slot into a folder first when needed) and have the agent reload. + pub fn commit_ring_folder_binding( + &mut self, + slot: openlogi_core::binding::RingSlot, + sub_slot: openlogi_core::binding::RingSlot, + action: Action, + ) { + let Some(key) = self.current_record().map(|r| r.config_key.clone()) else { + debug!(?slot, "no active device key — ring folder edit ignored"); + return; + }; + self.config + .set_ring_folder_slot(&key, slot, sub_slot, action); + self.persist_and_reload("ring folder binding"); + } + + /// Convert ring `slot` into a folder (its plain action kept as the + /// folder's North entry) and have the agent reload. + pub fn convert_ring_slot_to_folder(&mut self, slot: openlogi_core::binding::RingSlot) { + let Some(key) = self.current_record().map(|r| r.config_key.clone()) else { + debug!(?slot, "no active device key — folder conversion ignored"); + return; + }; + self.config.convert_ring_slot_to_folder(&key, slot); + self.persist_and_reload("ring folder conversion"); + } + pub fn commit_gesture_binding(&mut self, direction: GestureDirection, action: Action) { let Some(key) = self.current_record().map(|r| r.config_key.clone()) else { debug!( @@ -1318,6 +1411,75 @@ mod tests { ); } + /// The launch sequence that silently dropped a user's device choice: the + /// GUI starts before enumeration, so its first list is empty and there is + /// nothing to match `selected_device` against; when devices finally + /// arrive, the saved key must still win over "first in the list". + /// + /// This is load-bearing beyond the carousel — the agent aims its + /// control-capture session at the selected device, so landing on the + /// keyboard leaves the mouse's buttons (Action Ring included) uncaptured. + #[test] + fn a_late_arriving_inventory_restores_the_saved_device() { + use openlogi_core::device::{DeviceInventory, PairedDevice, ReceiverInfo}; + + let paired = |slot: u8, name: &str, kind: DeviceKind| PairedDevice { + slot, + codename: Some(name.to_string()), + wpid: Some(u16::from(slot)), + kind, + online: true, + battery: None, + model_info: None, + capabilities: None, + }; + let inventory = DeviceInventory { + receiver: ReceiverInfo { + name: "Logi Bolt Receiver".to_string(), + vendor_id: 0x046d, + product_id: 0xc548, + unique_id: Some("DEADBEEF".to_string()), + }, + // The saved choice is deliberately NOT the first listed. + paired: vec![ + paired(1, "Keyboard", DeviceKind::Keyboard), + paired(2, "Mouse", DeviceKind::Mouse), + ], + }; + let cache = AssetResolver::new(); + let (commands, _receiver) = tokio::sync::mpsc::unbounded_channel(); + + // Config keys are derived from route + slot, so read the real ones + // out of a throwaway state rather than restating the formula here. + let probe = AppState::with_runtime( + Config::default(), + std::slice::from_ref(&inventory), + &cache, + commands.clone(), + ); + let keys: Vec = probe + .device_list + .iter() + .map(|r| r.config_key.clone()) + .collect(); + assert_eq!(keys.len(), 2, "both devices enumerate"); + let wanted = keys[1].clone(); + + let mut config = Config::default(); + config.set_selected_device(Some(wanted.clone())); + // Launch with nothing enumerated yet — the real startup order. + let mut state = AppState::with_runtime(config, &[], &cache, commands); + assert!(state.current_record().is_none(), "no devices at launch"); + + state.refresh_inventories(std::slice::from_ref(&inventory), &cache, false); + + assert_eq!( + state.current_record().map(|r| r.config_key.as_str()), + Some(wanted.as_str()), + "the persisted selection must win over the first-listed device" + ); + } + #[test] fn gui_state_saves_and_clears_supported_wheel_resolution() { let mut config = Config::default(); diff --git a/crates/openlogi-gui/src/windows.rs b/crates/openlogi-gui/src/windows.rs index 19c68149..7fa5b14a 100644 --- a/crates/openlogi-gui/src/windows.rs +++ b/crates/openlogi-gui/src/windows.rs @@ -10,6 +10,7 @@ //! [`crate::theme::apply_from_settings`]. pub mod add_device; +pub mod ring_action_editor; pub mod settings; pub mod update_consent; @@ -33,6 +34,7 @@ pub struct WindowRegistry { pub settings: Option>, pub add_device: Option>, pub update_consent: Option>, + pub ring_action_editor: Option>, } impl Global for WindowRegistry {} diff --git a/crates/openlogi-gui/src/windows/ring_action_editor.rs b/crates/openlogi-gui/src/windows/ring_action_editor.rs new file mode 100644 index 00000000..65b059b5 --- /dev/null +++ b/crates/openlogi-gui/src/windows/ring_action_editor.rs @@ -0,0 +1,562 @@ +//! Payload editor for the Action Ring's parameterized actions. +//! +//! `Run` and `PasteText` carry free text a picker row can't capture, so the +//! ring flyout's "Run Command…" / "Paste Text…" rows open this small dialog — +//! the same shape as the Options+ Run editor: one input, a hint line, Cancel +//! / Save. Saving commits the action to the slot through the same +//! [`AppState::commit_ring_binding`] path the plain rows use. + +use gpui::{ + App, AppContext as _, BorrowAppContext as _, Context, Entity, FocusHandle, InteractiveElement, + IntoElement, ParentElement as _, Render, Size, Styled as _, Subscription, Window, div, + prelude::FluentBuilder as _, px, +}; +use gpui_component::{ + // Named (not `as _`) because the record button selects its variant with + // `.when(cond, ButtonVariants::danger)`, which needs the trait's path. + button::{Button, ButtonVariants}, + h_flex, + input::{Input, InputState}, + v_flex, +}; +use openlogi_core::binding::{Action, ButtonId, GestureDirection, KeyCombo, RingSlot}; + +use crate::app_menu::{CloseWindow, Minimize, Zoom}; +use crate::chord_recorder::{ChordRecorder, Poll}; +use crate::state::AppState; +use crate::theme::{self, Typography as _}; +use crate::windows::{self, AuxWindow, WindowRegistry}; + +/// How often the chord recorder samples the keyboard while listening. +const RECORD_TICK: std::time::Duration = std::time::Duration::from_millis(30); +/// Give up listening after this long with nothing pressed, so an abandoned +/// dialog doesn't leave a timer running forever. +const RECORD_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(15); + +/// Where a ring edit lands: a top-level slot, or a sub-slot inside the +/// folder at `folder`. Carried by the payload dialog and the editor's +/// action panel so both commit through the right path. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum EditTarget { + /// A top-level Action Ring slot. + Slot(RingSlot), + /// A position inside the folder at the top-level slot `folder`. + FolderSlot { + /// The top-level slot holding the folder. + folder: RingSlot, + /// The position inside that folder. + sub: RingSlot, + }, + /// One direction of the gesture button (hold + swipe). + Gesture(GestureDirection), + /// A plain button's single action — the DPI toggle, Middle, Back, … + Button(ButtonId), +} + +impl EditTarget { + /// The action currently at this target, resolved against the selected + /// device's ring. + pub fn current_action(self, state: &AppState) -> Option { + match self { + EditTarget::Slot(slot) => state + .ring_slots_for_current() + .into_iter() + .find(|(candidate, _)| *candidate == slot) + .map(|(_, action)| action), + EditTarget::FolderSlot { folder, sub } => state + .ring_slots_for_current() + .into_iter() + .find(|(candidate, _)| *candidate == folder) + .and_then(|(_, action)| match action { + Action::Folder(items) => items.get(&sub).cloned(), + _ => None, + }), + EditTarget::Gesture(direction) => state.gesture_bindings.get(&direction).cloned(), + EditTarget::Button(button) => state.button_bindings.get(&button).cloned(), + } + } + + /// Commit `action` to this target through the matching [`AppState`] + /// path. + pub fn commit(self, action: Action, cx: &mut App) { + cx.update_global::(|state, _| match self { + EditTarget::Slot(slot) => state.commit_ring_binding(slot, action), + EditTarget::FolderSlot { folder, sub } => { + state.commit_ring_folder_binding(folder, sub, action); + } + EditTarget::Gesture(direction) => state.commit_gesture_binding(direction, action), + EditTarget::Button(button) => state.commit_binding(button, action), + }); + } + + /// Compass caption for dialog subtitles: `↗ Top Right` or + /// `↗ Top Right › ↓ Bottom`. + pub fn caption(self) -> String { + match self { + EditTarget::Slot(slot) => format!("{} {}", slot.glyph(), tr!(slot.label())), + EditTarget::FolderSlot { folder, sub } => format!( + "{} {} › {} {}", + folder.glyph(), + tr!(folder.label()), + sub.glyph(), + tr!(sub.label()) + ), + EditTarget::Gesture(direction) => { + format!("{} {}", direction.glyph(), tr!(direction.label())) + } + EditTarget::Button(button) => tr!(button.label()).to_string(), + } + } +} + +/// Which payload action this editor edits. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum PayloadKind { + /// [`Action::Run`] — a URL, file, or program (`||` separates arguments). + Run, + /// [`Action::PasteText`] — a text snippet typed at the cursor. + PasteText, + /// [`Action::CustomShortcut`] — a chord entered as text + /// (`"Win+Ctrl+Space"`) and parsed by [`KeyCombo::parse`]. + Shortcut, +} + +impl PayloadKind { + /// The dialog / flyout-row title (an i18n key). + pub fn title_key(self) -> &'static str { + match self { + PayloadKind::Run => "Run Command", + PayloadKind::PasteText => "Paste Text", + PayloadKind::Shortcut => "Keyboard Shortcut", + } + } + + fn placeholder_key(self) -> &'static str { + match self { + PayloadKind::Run => "Command or URL", + PayloadKind::PasteText => "Text to paste", + PayloadKind::Shortcut => "e.g. Ctrl+Shift+P", + } + } + + fn hint_key(self) -> &'static str { + match self { + PayloadKind::Run => { + "A URL, file, or program. After a program path, use || to separate \ + arguments; %VAR% environment variables expand." + } + PayloadKind::PasteText => "Typed at the cursor exactly as written.", + PayloadKind::Shortcut => { + "Modifier names joined with +, then one key: Ctrl+Shift+P, \ + Win+Ctrl+Space, Alt+F4." + } + } + } + + /// Caption above this kind's payload input. + fn field_label_key(self) -> &'static str { + match self { + PayloadKind::Run => "Command", + PayloadKind::PasteText => "Text", + PayloadKind::Shortcut => "Shortcut", + } + } + + /// The vendored icon shown on this kind's editor row. + pub fn icon_path(self) -> &'static str { + match self { + PayloadKind::Run => "action-icons/square-arrow-right.svg", + PayloadKind::PasteText => "action-icons/clipboard-paste.svg", + PayloadKind::Shortcut => "action-icons/keyboard.svg", + } + } + + /// The editable payload of `action` when it already is this kind — the + /// editor seeds its input with it so reopening a configured slot edits + /// in place. + pub fn payload_of(self, action: &Action) -> Option { + // Look through a user label: naming a Run action doesn't stop it + // being the Run action this dialog edits. + match (self, action.inner()) { + (PayloadKind::Run, Action::Run(payload)) => Some(payload.clone()), + (PayloadKind::PasteText, Action::PasteText(text)) => Some(text.clone()), + (PayloadKind::Shortcut, Action::CustomShortcut(combo)) => Some(combo.rendered_label()), + _ => None, + } + } + + /// Parse `payload` into this kind's [`Action`]. `None` means the input + /// is not valid for this kind (only `Shortcut` can fail). + pub fn to_action(self, payload: String) -> Option { + match self { + PayloadKind::Run => Some(Action::Run(payload)), + PayloadKind::PasteText => Some(Action::PasteText(payload)), + PayloadKind::Shortcut => KeyCombo::parse(&payload).map(Action::CustomShortcut), + } + } +} + +/// Standalone payload-editor window root view. +pub struct RingActionEditorView { + focus_handle: FocusHandle, + #[allow(dead_code, reason = "held to keep the appearance observer alive")] + appearance_obs: Option, + target: EditTarget, + kind: PayloadKind, + input: Entity, + /// The user's label for this action ("Wispr Voice"), shown on the ring + /// instead of the raw payload. Empty means "use the payload's own + /// label". + name_input: Entity, + /// Set when Save could not parse the input (Shortcut only); renders an + /// inline error until the next attempt. + invalid: bool, + /// Live chord recording (Shortcut only): the chord held so far, or an + /// empty string right after "Press Keys" and before the first key. + listening: Option, +} + +impl AuxWindow for RingActionEditorView { + fn set_appearance_obs(&mut self, sub: Subscription) { + self.appearance_obs = Some(sub); + } +} + +/// Open the editor for `target`, seeded with its current payload when it +/// already holds an action of `kind`. An editor left open for another target +/// is closed first — focusing it would edit the wrong slot. +pub fn open(target: EditTarget, kind: PayloadKind, cx: &mut App) { + if let Some(handle) = cx + .default_global::() + .ring_action_editor + .take() + { + let _ = handle.update(cx, |_, window, _| window.remove_window()); + } + + let current = cx + .try_global::() + .and_then(|state| target.current_action(state)); + // Seed both fields from the slot, but only when it already holds this + // kind — a name belongs to the action it was given to. + let seed: String = current + .as_ref() + .and_then(|action| kind.payload_of(action)) + .unwrap_or_default(); + let name_seed: String = current + .as_ref() + .filter(|action| kind.payload_of(action).is_some()) + .and_then(|action| action.display_name().map(str::to_owned)) + .unwrap_or_default(); + + windows::open_or_focus( + |reg| &mut reg.ring_action_editor, + tr!(kind.title_key()), + Size::new(px(440.), px(320.)), + move |window, cx| { + let focus_handle = cx.focus_handle(); + let input = cx.new(|cx| { + InputState::new(window, cx) + .placeholder(tr!(kind.placeholder_key())) + .default_value(seed) + }); + let name_input = cx.new(|cx| { + InputState::new(window, cx) + .placeholder(tr!("Optional — shown on the ring")) + .default_value(name_seed) + }); + // Type straight away — the payload is the point of the dialog. + input.update(cx, |state, cx| state.focus(window, cx)); + RingActionEditorView { + focus_handle, + appearance_obs: None, + target, + kind, + input, + name_input, + invalid: false, + listening: None, + } + }, + cx, + ); +} + +/// Start listening for a physical chord on `editor`, sampling until the +/// user releases a real chord (committed straight to `target` — recording +/// *is* the save), presses Escape alone, or the timeout elapses. +fn start_listening(editor: &Entity, target: EditTarget, cx: &mut App) { + editor.update(cx, |view, vcx| { + view.invalid = false; + view.listening = Some(String::new()); + vcx.notify(); + }); + + let editor = editor.clone(); + cx.spawn(async move |cx| { + let mut recorder = ChordRecorder::default(); + let mut idle_ticks = 0_u32; + let max_idle = RECORD_TIMEOUT.as_millis() / RECORD_TICK.as_millis().max(1); + loop { + cx.background_executor().timer(RECORD_TICK).await; + let done = cx.update(|cx| { + // The dialog closed (or a different one opened) — stop. + let still_listening = editor.read_with(cx, |view, _| view.listening.is_some()); + if !still_listening { + return true; + } + match recorder.poll() { + Poll::Idle => { + idle_ticks += 1; + if u128::from(idle_ticks) >= max_idle { + stop_listening(&editor, cx); + return true; + } + false + } + Poll::Holding(chord) => { + idle_ticks = 0; + editor.update(cx, |view, vcx| { + view.listening = Some(chord); + vcx.notify(); + }); + false + } + Poll::Cancelled => { + stop_listening(&editor, cx); + true + } + Poll::Done(chord) => { + // The recorder emits canonical chord text, so this + // parse is the same one a typed chord takes. Any + // name already typed in the dialog rides along. + let name = editor.read_with(cx, |view, cx| { + view.name_input.read(cx).value().trim().to_owned() + }); + if let Some(action) = PayloadKind::Shortcut.to_action(chord) { + target.commit(action.with_name(&name), cx); + close_editor_window(cx); + } else { + stop_listening(&editor, cx); + } + true + } + } + }); + if done { + break; + } + } + }) + .detach(); +} + +/// The "Press Keys" button plus its live readout. While listening the row +/// shows the chord as it is held (or a prompt before the first key); the +/// captured chord commits and closes on release, so recording *is* saving. +fn record_row( + listening: Option<&str>, + editor: &Entity, + target: EditTarget, + pal: crate::theme::Palette, +) -> impl IntoElement { + let editor_click = editor.clone(); + let is_listening = listening.is_some(); + let readout: gpui::SharedString = match listening { + Some("") => tr!("Press a shortcut…"), + Some(chord) => chord.to_owned().into(), + None => tr!("Or record it: hold the keys, then let go."), + }; + + h_flex() + .items_center() + .gap_3() + .child( + Button::new("ring-editor-record") + .when(is_listening, ButtonVariants::danger) + .when(!is_listening, Button::outline) + .label(if is_listening { + tr!("Listening…") + } else { + tr!("Press Keys") + }) + .on_click(move |_, _, cx| { + let listening = editor_click.read_with(cx, |view, _| view.listening.is_some()); + if listening { + stop_listening(&editor_click, cx); + } else { + start_listening(&editor_click, target, cx); + } + }), + ) + .child( + div() + // The live chord reads as a value while listening, and as + // helper text otherwise. + .map(|s| { + if is_listening { + s.text_subheading() + } else { + s.text_caption() + } + }) + .text_color(if is_listening { + pal.text_primary + } else { + pal.text_muted + }) + .child(readout), + ) +} + +/// Leave listening mode without committing. +fn stop_listening(editor: &Entity, cx: &mut App) { + editor.update(cx, |view, vcx| { + view.listening = None; + vcx.notify(); + }); +} + +/// Close the payload dialog from outside its own event handlers (the +/// recorder's timer has no `&mut Window`), via the registry handle. +fn close_editor_window(cx: &mut App) { + if let Some(handle) = cx + .default_global::() + .ring_action_editor + .take() + { + let _ = handle.update(cx, |_, window, _| window.remove_window()); + } +} + +impl Render for RingActionEditorView { + fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { + let pal = theme::palette(cx); + let (target, kind, input) = (self.target, self.kind, self.input.clone()); + let editor = cx.entity(); + + v_flex() + .size_full() + .bg(pal.bg) + .text_color(pal.text_primary) + .track_focus(&self.focus_handle) + .on_action(|_: &CloseWindow, window, _| window.remove_window()) + .on_action(|_: &Minimize, window, _| window.minimize_window()) + .on_action(|_: &Zoom, window, _| window.zoom_window()) + .when(cfg!(target_os = "linux"), |this| { + this.child(windows::aux_title_bar(tr!(self.kind.title_key()), cx)) + }) + .child( + v_flex() + .flex_1() + .w_full() + .gap_3() + .p_5() + .child( + h_flex() + .items_center() + .gap_2() + .child(div().text_heading().child(tr!(self.kind.title_key()))) + .child( + div() + .text_caption() + .text_color(pal.text_muted) + .child(self.target.caption()), + ), + ) + // Recording is the primary path for a shortcut; the + // text field stays as the editable / accessible form. + .when( + kind == PayloadKind::Shortcut && crate::chord_recorder::is_supported(), + |this| { + this.child(record_row( + self.listening.as_deref(), + &editor, + target, + pal, + )) + }, + ) + .child(field_label(tr!(self.kind.field_label_key()), pal)) + .child(Input::new(&self.input)) + .child( + div() + .text_caption() + .text_color(pal.text_muted) + .child(tr!(self.kind.hint_key())), + ) + .child(field_label(tr!("Name"), pal)) + .child(Input::new(&self.name_input)) + .when(self.invalid, |this| { + this.child( + div() + .text_caption() + .text_color(gpui::rgb(0x00d6_4541)) + .child(tr!( + "That shortcut could not be read — use the Ctrl+Shift+P shape." + )), + ) + }) + .child(button_row( + &input, + &self.name_input, + &editor, + target, + kind, + )), + ) + } +} + +/// Small uppercase caption above an input. +fn field_label(text: gpui::SharedString, pal: crate::theme::Palette) -> impl IntoElement { + div().text_caption().text_color(pal.text_muted).child(text) +} + +/// Cancel / Save. An emptied input closes without committing — clearing a +/// slot is what the plain rows ("Do Nothing") are for — and input this kind +/// can't parse (Shortcut) keeps the dialog open with an inline error +/// instead of dropping the edit. +fn button_row( + input: &Entity, + name_input: &Entity, + editor: &Entity, + target: EditTarget, + kind: PayloadKind, +) -> impl IntoElement { + let (input, name_input, editor) = (input.clone(), name_input.clone(), editor.clone()); + h_flex() + .w_full() + .justify_end() + .gap_3() + .pt_1() + .child( + Button::new("ring-editor-cancel") + .outline() + .label(tr!("Cancel")) + .on_click(|_, window, _| window.remove_window()), + ) + .child( + Button::new("ring-editor-save") + .primary() + .label(tr!("Save")) + .on_click(move |_, window, cx| { + let payload = input.read(cx).value().trim().to_owned(); + if payload.is_empty() { + window.remove_window(); + return; + } + let name = name_input.read(cx).value().trim().to_owned(); + match kind.to_action(payload) { + Some(action) => { + target.commit(action.with_name(&name), cx); + window.remove_window(); + } + None => editor.update(cx, |view, vcx| { + view.invalid = true; + vcx.notify(); + }), + } + }), + ) +} diff --git a/crates/openlogi-hid/Cargo.toml b/crates/openlogi-hid/Cargo.toml index 59b2b70b..d237ca1d 100644 --- a/crates/openlogi-hid/Cargo.toml +++ b/crates/openlogi-hid/Cargo.toml @@ -34,6 +34,9 @@ windows-sys = { workspace = true, features = [ # exposed when Win32_Security is also enabled. "Win32_Security", "Win32_Storage_FileSystem", + # WriteFile's signature references OVERLAPPED, so it is only exposed when + # Win32_System_IO is also enabled. + "Win32_System_IO", ] } [lints] diff --git a/crates/openlogi-hid/src/gesture.rs b/crates/openlogi-hid/src/gesture.rs index 1783494b..8384424f 100644 --- a/crates/openlogi-hid/src/gesture.rs +++ b/crates/openlogi-hid/src/gesture.rs @@ -1,12 +1,14 @@ -//! Live control capture for one device: divert the MX dedicated gesture button, the -//! DPI/ModeShift button, and the thumb wheel over HID++ and turn their events -//! into [`CapturedInput`] the GUI can dispatch. +//! Live control capture for one device: divert the MX dedicated gesture button, +//! the DPI/ModeShift button, and the thumb wheel over HID++ — and arm the MX +//! Master 4 Action Ring pad for `analyticsKeyEvents` reporting — turning their +//! events into [`CapturedInput`] the GUI can dispatch. //! //! [`run_capture_session`] holds a single HID++ channel open for one device, -//! enables diversion on whichever of those controls it exposes, registers one -//! message listener, and restores every control's default mapping on shutdown. -//! Using one channel matters: a second channel to the same device would split -//! its input-report stream, so all captured controls share this session. +//! enables capture on whichever of those controls it exposes, registers one +//! message listener, and restores every control's default reporting on +//! shutdown. Using one channel matters: a second channel to the same device +//! would split its input-report stream, so all captured controls share this +//! session. //! //! The session is transport-only — it has no opinion on what an input *does*. //! The GUI maps each [`CapturedInput`] to the user's bound action and dispatches @@ -16,18 +18,43 @@ //! is therefore only diverted when its click is actually bound. use std::sync::{Arc, Mutex, PoisonError, RwLock}; +use std::time::Duration; -use hidpp::{channel::HidppChannel, device::Device, protocol::v20}; +use hidpp::{ + channel::HidppChannel, + device::Device, + feature::{ + force_sensing_button::ForceSensingButtonFeature, reprog_controls::CidReportingChange, + }, + protocol::v20, +}; use openlogi_core::binding::{ButtonId, GestureDirection, SwipeAccumulator}; use serde::{Deserialize, Serialize}; use thiserror::Error; use tokio::sync::{mpsc, oneshot}; +use tokio::time::MissedTickBehavior; use tracing::{debug, info, warn}; use crate::reprog_controls::{self, RawControlEvent, ReprogControlsV4}; use crate::route::{DeviceRoute, open_route_channel}; use crate::thumbwheel::{self, Thumbwheel}; -use crate::write::SharedChannel; +use crate::write::{SharedChannel, open_feature}; + +/// Force-activation threshold Options+ writes to the Action Ring pad's button +/// `0` at startup — the magic constant that wakes the physically dormant pad +/// (`docs/mx-master-4-panel-captures/optionsplus-coldstart-full.txt`). +const ACTION_RING_FORCE_THRESHOLD: u16 = 0x15a3; + +/// Cadence for re-applying the Action Ring arming recipe. A single arm at +/// session start is lost when the BTLE link is asleep, and the configuration +/// does not survive the device sleeping mid-session, so the recipe is +/// re-applied continuously (the cadence the confirming hardware run used). +const PANEL_REARM_PERIOD: Duration = Duration::from_secs(3); + +/// Budget for one Action Ring arming pass. Channel reads have no intrinsic +/// timeout, so without a bound a cold link could hold an arming call — and +/// with it the session's shutdown path — indefinitely. +const PANEL_ARM_BUDGET: Duration = Duration::from_secs(2); /// Shared slot holding the active capture session's open channel, so DPI / /// SmartShift writes can reuse it instead of opening a fresh one. `None` @@ -69,12 +96,24 @@ pub enum GestureError { /// Movement + button state accumulated across messages. Lives behind a `Mutex` /// because the channel's read thread invokes the listener by shared reference. #[derive(Default)] +#[expect( + clippy::struct_excessive_bools, + reason = "independent rising-edge latches, one per captured control — not a state machine" +)] struct CaptureAccum { /// Mid-swipe state for the diverted dedicated gesture button (raw-XY). swipe: SwipeAccumulator, /// Whether any DPI/ModeShift control was held in the last event — for /// rising-edge press detection. dpi_down: bool, + /// Whether the Action Ring pad was down in the last analytics event — for + /// rising-edge press detection. + panel_down: bool, + /// Whether the diverted side "back" button was held in the last event — + /// rising-edge press detection, like [`Self::dpi_down`]. + back_down: bool, + /// Whether the diverted side "forward" button was held in the last event. + forward_down: bool, } /// Capture the gesture button, DPI/ModeShift button, and (when @@ -155,11 +194,41 @@ pub async fn run_capture_session( info!( index = device_index, gesture = armed.gesture_diverted, + action_ring = armed.panel.is_some(), dpi_buttons = armed.dpi_cids.len(), + nav_buttons = armed.nav_cids.len(), thumbwheel = armed.thumb.is_some(), "control capture active" ); - let _ = shutdown.await; + + // The Action Ring's arming does not survive the device sleeping, so a + // session with the pad re-applies the recipe on a cadence while waiting + // for shutdown. The interval's first tick fires immediately and doubles as + // the initial arm — deliberately after the listener above, so no event + // between arm and listen is lost. + match (&armed.panel, &armed.reprog) { + (Some(panel), Some((rc, _))) => { + let mut shutdown = shutdown; + let mut cadence = tokio::time::interval(PANEL_REARM_PERIOD); + cadence.set_missed_tick_behavior(MissedTickBehavior::Delay); + loop { + tokio::select! { + _ = &mut shutdown => break, + _ = cadence.tick() => { + if tokio::time::timeout(PANEL_ARM_BUDGET, panel.apply(rc)) + .await + .is_err() + { + debug!("action ring re-arm timed out (link cold?)"); + } + } + } + } + } + _ => { + let _ = shutdown.await; + } + } drop(listener); if let Ok(mut slot) = channel_slot.write() { @@ -177,15 +246,20 @@ struct ArmedControls { reprog: Option<(ReprogControlsV4, u8)>, /// Whether the gesture button is diverted with raw-XY reporting. gesture_diverted: bool, + /// Present when the device has the Action Ring pad — the arming recipe + /// [`run_capture_session`] re-applies on a cadence. + panel: Option, /// DPI/ModeShift CIDs diverted as plain buttons. dpi_cids: Vec, + /// Side Back/Forward CIDs diverted as plain buttons. + nav_cids: Vec, /// `0x2150` accessor + feature index, present when the thumb wheel is /// diverted. thumb: Option<(Thumbwheel, u8)>, } impl ArmedControls { - /// Restore every diverted control. Failures are logged, not propagated. + /// Restore every captured control. Failures are logged, not propagated. async fn disarm(&self) { if let Some((rc, _)) = self.reprog.as_ref() { if self.gesture_diverted { @@ -194,9 +268,26 @@ impl ArmedControls { .await; restore(r, "gesture button"); } + if self.panel.is_some() { + let off = CidReportingChange { + analytics_key_events: Some(false), + ..CidReportingChange::default() + }; + let r = rc + .set_cid_reporting_full(reprog_controls::ACTION_RING_CID, off) + .await + .map(|_| ()); + restore(r, "action ring pad"); + } for &cid in &self.dpi_cids { restore(rc.set_cid_reporting(cid, false, false).await, "DPI button"); } + for &cid in &self.nav_cids { + restore( + rc.set_cid_reporting(cid, false, false).await, + "side nav button", + ); + } } if let Some((tw, _)) = self.thumb.as_ref() { restore(tw.set_reporting(false, false).await, "thumb wheel"); @@ -204,24 +295,66 @@ impl ArmedControls { } } -/// Resolve features off the device's root and divert the controls we capture: -/// the gesture button (raw-XY) and DPI/ModeShift buttons over `0x1b04`, and — -/// when `capture_thumbwheel` and the wheel reports a single tap — the thumb -/// wheel over `0x2150`. The root-feature lookup mirrors `write::open_feature`, -/// since hidpp 0.2's registry doesn't carry the features OpenLogi reimplements. +/// The Action Ring pad's arming recipe: write the pad's force threshold (the +/// pad is physically dormant without one), then enable `analyticsKeyEvents` +/// reporting on [`reprog_controls::ACTION_RING_CID`] **only** — no diversion, +/// no raw-XY, and deliberately NOT the click-telemetry CIDs Options+ also +/// arms (see [`reprog_controls::LEFT_BUTTON_CID`]: arming those turns every +/// physical click into a ring press). Re-applied on [`PANEL_REARM_PERIOD`] +/// because neither write survives the device sleeping. +struct PanelArming { + /// `0x19c0` accessor for the force-threshold write; `None` when the device + /// does not expose it (analytics reporting is still armed). + fsb: Option>, +} + +impl PanelArming { + /// One arming pass. Failures are logged at debug and retried on the next + /// cadence tick — transient misses are expected while the BTLE link is + /// asleep. + async fn apply(&self, rc: &ReprogControlsV4) { + if let Some(fsb) = &self.fsb + && let Err(e) = fsb + .set_force_threshold(0, ACTION_RING_FORCE_THRESHOLD) + .await + { + debug!(error = ?e, "action ring force-threshold write failed"); + } + let on = CidReportingChange { + analytics_key_events: Some(true), + ..CidReportingChange::default() + }; + if let Err(e) = rc + .set_cid_reporting_full(reprog_controls::ACTION_RING_CID, on) + .await + { + debug!(error = ?e, "action ring analytics arm failed"); + } + } +} + +/// Resolve features off the device's root and capture the controls we handle: +/// divert the gesture button (raw-XY) and DPI/ModeShift buttons over `0x1b04`, +/// resolve the Action Ring pad's arming recipe when the control table +/// advertises the pad, and — when `capture_thumbwheel` and the wheel reports a +/// single tap — divert the thumb wheel over `0x2150`. The root-feature lookup +/// mirrors `write::open_feature`, since hidpp 0.2's registry doesn't carry the +/// features OpenLogi reimplements. async fn arm_controls( chan: &Arc, slot: u8, capture_thumbwheel: bool, divert_gesture_button: bool, ) -> Result { - let device = Device::new(Arc::clone(chan), slot) + let mut device = Device::new(Arc::clone(chan), slot) .await .map_err(|_| GestureError::DeviceUnreachable(slot))?; let mut reprog: Option<(ReprogControlsV4, u8)> = None; let mut gesture_diverted = false; + let mut panel: Option = None; let mut dpi_cids: Vec = Vec::new(); + let mut nav_cids: Vec = Vec::new(); if let Some(info) = device .root() .get_feature(reprog_controls::FEATURE_ID) @@ -243,14 +376,41 @@ async fn arm_controls( .map_err(|e| GestureError::Hidpp(format!("{e:?}")))?; gesture_diverted = true; } - for &cid in &reprog_controls::DPI_MODE_SHIFT_CIDS { - if controls.iter().any(|c| c.cid == cid && c.is_divertable()) { - rc.set_cid_reporting(cid, true, false) - .await - .map_err(|e| GestureError::Hidpp(format!("{e:?}")))?; - dpi_cids.push(cid); - } + + // The Action Ring pad advertises `analytics-events` in the control + // table — never divert it (and never touch 0x00d7; see + // [`reprog_controls::HAPTIC_PANEL_CID`]). Only resolve the recipe + // here: the actual arming runs on the session's cadence, after the + // message listener is registered. + if controls + .iter() + .any(|c| c.cid == reprog_controls::ACTION_RING_CID && c.supports_analytics_events()) + { + // 0x19c0 wakes the physical pad. Its absence is tolerated in case + // another device family reports analytics-capable controls + // without a force pad — analytics reporting is still armed. + let fsb = match open_feature::(&mut device).await { + Ok(fsb) => Some(fsb), + Err(e) => { + warn!(error = %e, "action ring: 0x19c0 unavailable, arming analytics only"); + None + } + }; + panel = Some(PanelArming { fsb }); + info!("action ring pad present — analytics capture arming on cadence"); } + dpi_cids = + divert_plain_buttons(&rc, &controls, &reprog_controls::DPI_MODE_SHIFT_CIDS).await?; + // The side Back/Forward buttons are diverted like the DPI button and + // dispatched through their bindings. On the MX Master 4 they emit no + // native HID events at all, so without this they are dead buttons — + // the job Options+ quietly does on this device. + nav_cids = divert_plain_buttons( + &rc, + &controls, + &[reprog_controls::BACK_CID, reprog_controls::FORWARD_CID], + ) + .await?; reprog = Some((rc, info.index)); } @@ -283,17 +443,43 @@ async fn arm_controls( } } - if !gesture_diverted && dpi_cids.is_empty() && thumb.is_none() { + if !gesture_diverted + && panel.is_none() + && dpi_cids.is_empty() + && nav_cids.is_empty() + && thumb.is_none() + { debug!(slot, "no capturable controls — idle session"); } Ok(ArmedControls { reprog, gesture_diverted, + panel, dpi_cids, + nav_cids, thumb, }) } +/// Divert each of `candidates` that the control table lists as divertable, +/// as a plain button (no raw-XY); returns the CIDs actually diverted. +async fn divert_plain_buttons( + rc: &ReprogControlsV4, + controls: &[reprog_controls::CtrlIdInfo], + candidates: &[u16], +) -> Result, GestureError> { + let mut diverted = Vec::new(); + for &cid in candidates { + if controls.iter().any(|c| c.cid == cid && c.is_divertable()) { + rc.set_cid_reporting(cid, true, false) + .await + .map_err(|e| GestureError::Hidpp(format!("{e:?}")))?; + diverted.push(cid); + } + } + Ok(diverted) +} + /// Log (don't propagate) a failure to hand a control back to the firmware. fn restore(result: Result<(), E>, what: &str) { if let Err(e) = result { @@ -323,8 +509,9 @@ async fn enumerate_controls( /// Update `acc` and emit on a decoded `0x1b04` event: commit a gesture swipe the /// instant it crosses the threshold (mid-swipe, like Options+) rather than on -/// release, and emit a [`ButtonId::DpiToggle`] press on the rising edge of any -/// diverted DPI/ModeShift control. +/// release, emit a [`ButtonId::DpiToggle`] press on the rising edge of any +/// diverted DPI/ModeShift control, and track Action Ring taps from analytics +/// entries. fn handle_reprog( acc: &mut CaptureAccum, event: RawControlEvent, @@ -349,6 +536,19 @@ fn handle_reprog( let _ = sink.send(CapturedInput::ButtonPressed(ButtonId::DpiToggle)); } acc.dpi_down = dpi_down; + + // The diverted side buttons dispatch through their bindings on + // the rising edge, like the DPI button. + let back_down = cids.contains(&reprog_controls::BACK_CID); + if back_down && !acc.back_down { + let _ = sink.send(CapturedInput::ButtonPressed(ButtonId::Back)); + } + acc.back_down = back_down; + let forward_down = cids.contains(&reprog_controls::FORWARD_CID); + if forward_down && !acc.forward_down { + let _ = sink.send(CapturedInput::ButtonPressed(ButtonId::Forward)); + } + acc.forward_down = forward_down; } RawControlEvent::RawXy { dx, dy } => { // Commit the instant a clean direction emerges (mid-swipe, once per @@ -359,6 +559,44 @@ fn handle_reprog( let _ = sink.send(CapturedInput::Gesture(direction)); } } + RawControlEvent::AnalyticsKeys(entries) => { + // The Action Ring pad reports each tap as an analytics + // press/release pair on ACTION_RING_CID — and ONLY that CID may + // drive the ring. Analytics for any other control (notably the + // left/right click-telemetry CIDs, if something else armed them) + // must be ignored, or every physical click opens the ring + // (hardware-confirmed failure mode, 2026-07-20). Rising-edge + // tracking makes one physical tap exactly one press; the release + // is deliberately unused (the ring UI is a toggle, not + // press-and-hold). + let mut pressed = false; + let mut released = false; + for entry in entries { + let cid: u16 = entry.cid.into(); + if cid == 0 { + continue; + } + if cid == reprog_controls::ACTION_RING_CID { + if entry.event == 0 { + released = true; + } else { + pressed = true; + } + } else { + debug!( + cid, + entry.event, "analytics event from a non-ring control — ignored" + ); + } + } + if pressed && !acc.panel_down { + acc.panel_down = true; + debug!("action ring pressed"); + let _ = sink.send(CapturedInput::ButtonPressed(ButtonId::ActionRing)); + } else if released && !pressed { + acc.panel_down = false; + } + } } } #[cfg(test)] diff --git a/crates/openlogi-hid/src/gesture/tests.rs b/crates/openlogi-hid/src/gesture/tests.rs index 035f2cda..e09d4bd9 100644 --- a/crates/openlogi-hid/src/gesture/tests.rs +++ b/crates/openlogi-hid/src/gesture/tests.rs @@ -1,4 +1,5 @@ use super::*; +use crate::reprog_controls::{AnalyticsKeyEvent, ControlId}; fn press() -> RawControlEvent { RawControlEvent::DivertedButtons([reprog_controls::GESTURE_BUTTON_CID, 0, 0, 0]) @@ -8,6 +9,17 @@ fn release() -> RawControlEvent { RawControlEvent::DivertedButtons([0, 0, 0, 0]) } +/// One analytics batch with a single populated entry (the observed hardware +/// shape: one entry per message, four empty slots). +fn ring(cid: u16, event: u8) -> RawControlEvent { + let mut entries = [AnalyticsKeyEvent::default(); 5]; + entries[0] = AnalyticsKeyEvent { + cid: ControlId(cid), + event, + }; + RawControlEvent::AnalyticsKeys(entries) +} + #[test] fn quick_tap_is_a_click_even_while_the_cursor_moves() { let (tx, mut rx) = mpsc::unbounded_channel(); @@ -76,6 +88,200 @@ fn a_held_dpi_button_presses_once_on_the_rising_edge() { assert!(rx.try_recv().is_err(), "a held DPI button presses once"); } +#[test] +fn a_ring_tap_is_one_rising_edge_and_one_press() { + let (tx, mut rx) = mpsc::unbounded_channel(); + let mut acc = CaptureAccum::default(); + + handle_reprog( + &mut acc, + ring(reprog_controls::ACTION_RING_CID, 0x01), + &[], + &tx, + ); + assert!(acc.panel_down, "a press entry arms the edge"); + handle_reprog( + &mut acc, + ring(reprog_controls::ACTION_RING_CID, 0x00), + &[], + &tx, + ); + assert!(!acc.panel_down, "a release entry clears the edge"); + assert_eq!( + rx.try_recv(), + Ok(CapturedInput::ButtonPressed(ButtonId::ActionRing)) + ); + assert!( + rx.try_recv().is_err(), + "one physical tap must emit exactly one press" + ); +} + +#[test] +fn a_ring_tap_re_arms_after_release() { + let (tx, mut rx) = mpsc::unbounded_channel(); + let mut acc = CaptureAccum::default(); + + handle_reprog( + &mut acc, + ring(reprog_controls::ACTION_RING_CID, 0x01), + &[], + &tx, + ); + handle_reprog( + &mut acc, + ring(reprog_controls::ACTION_RING_CID, 0x00), + &[], + &tx, + ); + assert!(!acc.panel_down); + handle_reprog( + &mut acc, + ring(reprog_controls::ACTION_RING_CID, 0x01), + &[], + &tx, + ); + assert!(acc.panel_down, "a release re-arms the rising edge"); + assert_eq!( + rx.try_recv(), + Ok(CapturedInput::ButtonPressed(ButtonId::ActionRing)) + ); + assert_eq!( + rx.try_recv(), + Ok(CapturedInput::ButtonPressed(ButtonId::ActionRing)), + "a release re-arms: the second tap presses again" + ); + assert!(rx.try_recv().is_err()); +} + +#[test] +fn diverted_side_buttons_press_on_the_rising_edge() { + // The MX Master 4's Back/Forward emit no native HID events; the session + // diverts them, so each hold must dispatch exactly one press. + let (tx, mut rx) = mpsc::unbounded_channel(); + let mut acc = CaptureAccum::default(); + let back = RawControlEvent::DivertedButtons([reprog_controls::BACK_CID, 0, 0, 0]); + let up = RawControlEvent::DivertedButtons([0, 0, 0, 0]); + + handle_reprog(&mut acc, back, &[], &tx); + handle_reprog(&mut acc, back, &[], &tx); // still held — no repeat + handle_reprog(&mut acc, up, &[], &tx); + handle_reprog( + &mut acc, + RawControlEvent::DivertedButtons([reprog_controls::FORWARD_CID, 0, 0, 0]), + &[], + &tx, + ); + + assert_eq!( + rx.try_recv(), + Ok(CapturedInput::ButtonPressed(ButtonId::Back)) + ); + assert_eq!( + rx.try_recv(), + Ok(CapturedInput::ButtonPressed(ButtonId::Forward)), + "a release re-arms; the other button has its own edge" + ); + assert!(rx.try_recv().is_err(), "a held button presses once"); +} + +#[test] +fn both_side_buttons_in_one_frame_press_both() { + let (tx, mut rx) = mpsc::unbounded_channel(); + let mut acc = CaptureAccum::default(); + handle_reprog( + &mut acc, + RawControlEvent::DivertedButtons([ + reprog_controls::BACK_CID, + reprog_controls::FORWARD_CID, + 0, + 0, + ]), + &[], + &tx, + ); + assert_eq!( + rx.try_recv(), + Ok(CapturedInput::ButtonPressed(ButtonId::Back)) + ); + assert_eq!( + rx.try_recv(), + Ok(CapturedInput::ButtonPressed(ButtonId::Forward)) + ); + assert!(rx.try_recv().is_err()); +} + +#[test] +fn click_telemetry_cids_never_open_the_ring() { + // 0x0050/0x0051 are the LEFT/RIGHT mouse buttons' analytics CIDs, not the + // pad. If anything arms them (Options+ does, for telemetry), every + // physical click would arrive here — and must be ignored, or clicking + // anywhere opens the ring (hardware-confirmed failure, 2026-07-20). + let (tx, mut rx) = mpsc::unbounded_channel(); + let mut acc = CaptureAccum::default(); + + for cid in [ + reprog_controls::LEFT_BUTTON_CID, + reprog_controls::RIGHT_BUTTON_CID, + ] { + handle_reprog(&mut acc, ring(cid, 0x01), &[], &tx); + assert!(!acc.panel_down, "a click press must not arm the ring edge"); + handle_reprog(&mut acc, ring(cid, 0x00), &[], &tx); + } + assert!(rx.try_recv().is_err(), "clicks must emit nothing"); +} + +#[test] +fn analytics_from_foreign_controls_do_not_touch_the_ring_edge() { + let (tx, mut rx) = mpsc::unbounded_channel(); + let mut acc = CaptureAccum::default(); + + handle_reprog( + &mut acc, + ring(reprog_controls::GESTURE_BUTTON_CID, 0x01), + &[], + &tx, + ); + assert!( + !acc.panel_down, + "a non-ring CID in an analytics batch is not the pad" + ); + assert!(rx.try_recv().is_err()); + assert!( + !acc.swipe.is_holding(), + "and it must not start a swipe either" + ); +} + +#[test] +fn a_batch_with_press_and_release_entries_arms_the_edge() { + // The wire format carries five entries per message: a pad press plus an + // unrelated click-CID entry in the same batch must arm the edge off the + // pad entry alone, with the click entry ignored. + let (tx, mut rx) = mpsc::unbounded_channel(); + let mut acc = CaptureAccum::default(); + + let mut entries = [AnalyticsKeyEvent::default(); 5]; + entries[0] = AnalyticsKeyEvent { + cid: ControlId(reprog_controls::ACTION_RING_CID), + event: 0x01, + }; + entries[1] = AnalyticsKeyEvent { + cid: ControlId(reprog_controls::LEFT_BUTTON_CID), + event: 0x00, + }; + handle_reprog(&mut acc, RawControlEvent::AnalyticsKeys(entries), &[], &tx); + assert!( + acc.panel_down, + "the press entry wins over the release entry" + ); + assert_eq!( + rx.try_recv(), + Ok(CapturedInput::ButtonPressed(ButtonId::ActionRing)) + ); + assert!(rx.try_recv().is_err(), "exactly one press for the batch"); +} + #[test] fn a_dpi_button_re_presses_after_a_release() { // Rising-edge detection must re-arm: press → release → press is two diff --git a/crates/openlogi-hid/src/hidden_features.rs b/crates/openlogi-hid/src/hidden_features.rs new file mode 100644 index 00000000..cc05dc2d --- /dev/null +++ b/crates/openlogi-hid/src/hidden_features.rs @@ -0,0 +1,256 @@ +//! Route-level diagnostics for `0x1e00 EnableHiddenFeatures` and the +//! `0x19c0 ForceSensingButton` probe surface (MX Master 4 Action Ring panel). +//! +//! Diag-only plumbing for the CLI: errors stay in a local type and never +//! cross the agent↔GUI IPC, so [`crate::write::WriteError`] (wire format) +//! stays untouched. + +use std::future::Future; +use std::sync::Arc; +use std::time::Duration; + +use hidpp::device::Device; +use hidpp::feature::enable_hidden_features::EnableHiddenFeaturesFeature; +use hidpp::feature::force_sensing_button::ForceSensingButtonFeature; +use hidpp::feature::reprog_controls::{ + CidReportingChange, ReprogControlsEvent, decode_event as decode_reprog_event, +}; +use hidpp::protocol::v20; +use thiserror::Error; + +use crate::reprog_controls::{FEATURE_ID as REPROG_FEATURE_ID, ReprogControlsV4}; +use crate::route::{DeviceRoute, open_route_channel}; +use crate::write::open_feature; + +pub use crate::reprog_controls::PANEL_DIAG_ANALYTICS_CIDS as PANEL_ANALYTICS_CIDS; + +/// Hard wall-clock budget for one whole diagnostic (open + calls). A cold +/// BTLE link can swallow a request without ever answering, and the underlying +/// channel read has no timeout of its own — without this bound a single call +/// can hang a diagnostic process forever (observed on real hardware). +const DIAG_BUDGET: Duration = Duration::from_secs(8); + +async fn bounded( + fut: impl Future>, +) -> Result { + tokio::time::timeout(DIAG_BUDGET, fut) + .await + .map_err(|_| HiddenDiagError::Hidpp("call timed out (link cold?)".into()))? +} + +/// Failure modes for the hidden-features / force-button diagnostics. +#[derive(Debug, Error)] +pub enum HiddenDiagError { + /// No HID node matched the route. + #[error("no connected device matched the route")] + DeviceNotFound, + /// Transport-level failure opening the route. + #[error("HID transport error: {0}")] + Hid(String), + /// The node opened but the HID++ device index did not answer. + #[error("device at index {index:#04x} did not respond to HID++")] + DeviceUnreachable { + /// HID++ device index that failed to answer. + index: u8, + }, + /// A feature lookup or call failed. + #[error("HID++ error: {0}")] + Hidpp(String), +} + +async fn open_device(route: &DeviceRoute) -> Result { + let chan = open_route_channel(route) + .await + .map_err(|e| HiddenDiagError::Hid(format!("{e:?}")))? + .ok_or(HiddenDiagError::DeviceNotFound)?; + let index = route.device_index(); + Device::new(Arc::clone(&chan), index) + .await + .map_err(|_| HiddenDiagError::DeviceUnreachable { index }) +} + +/// Reads the current `0x1e00` enabled state. +pub async fn hidden_features_enabled(route: &DeviceRoute) -> Result { + bounded(async { + let mut device = open_device(route).await?; + let feature = open_feature::(&mut device) + .await + .map_err(|e| HiddenDiagError::Hidpp(e.to_string()))?; + feature + .get_enabled() + .await + .map_err(|e| HiddenDiagError::Hidpp(format!("{e:?}"))) + }) + .await +} + +/// Writes the `0x1e00` enabled state and returns the read-back value. +pub async fn set_hidden_features_enabled( + route: &DeviceRoute, + enabled: bool, +) -> Result { + bounded(async { + let mut device = open_device(route).await?; + let feature = open_feature::(&mut device) + .await + .map_err(|e| HiddenDiagError::Hidpp(e.to_string()))?; + feature + .set_enabled(enabled) + .await + .map_err(|e| HiddenDiagError::Hidpp(format!("{e:?}")))?; + feature + .get_enabled() + .await + .map_err(|e| HiddenDiagError::Hidpp(format!("{e:?}"))) + }) + .await +} + +/// Arm the Action Ring panel with the Options+ recipe — `analyticsKeyEvents` +/// reporting on [`PANEL_ANALYTICS_CIDS`], no diversion — then listen for +/// `seconds` and invoke `on_event(cid, event_code)` for each analytics entry +/// (`event_code`: non-zero = press, `0` = release). Restores reporting on exit. +/// +/// This is the reverse-engineered path that makes the panel emit at all; the +/// production ring in `gesture.rs` should adopt the same config + decode. +pub async fn watch_panel( + route: &DeviceRoute, + seconds: u64, + on_event: impl Fn(u16, u8) + Send + Sync + 'static, +) -> Result<(), HiddenDiagError> { + let chan = open_route_channel(route) + .await + .map_err(|e| HiddenDiagError::Hid(format!("{e:?}")))? + .ok_or(HiddenDiagError::DeviceNotFound)?; + let device_index = route.device_index(); + let mut device = Device::new(Arc::clone(&chan), device_index) + .await + .map_err(|_| HiddenDiagError::DeviceUnreachable { + index: device_index, + })?; + let info = device + .root() + .get_feature(REPROG_FEATURE_ID) + .await + .map_err(|e| HiddenDiagError::Hidpp(format!("{e:?}")))? + .ok_or_else(|| HiddenDiagError::Hidpp("device does not expose 0x1b04".into()))?; + let feature_index = info.index; + eprintln!("[watch_panel] 0x1b04 feature index = {feature_index}"); + let rc = ReprogControlsV4::new(Arc::clone(&chan), device_index, feature_index); + + // The physical force pad is dormant until its threshold is written. Options+ + // sends 0x19c0 (ForceSensingButton) fn3 with `00 15 a3` at init; without it + // the pad generates no 0x0050 control events for analytics to report. + let fsb = open_feature::(&mut device) + .await + .ok(); + eprintln!( + "[watch_panel] force-sensing feature present = {}", + fsb.is_some() + ); + + // Listen before arming so nothing is missed once the config lands. + let on_event = Arc::new(on_event); + let listener = chan.add_msg_listener_guarded({ + let on_event = Arc::clone(&on_event); + move |raw, matched| { + if matched { + return; + } + let msg = v20::Message::from(raw); + if let Some(ReprogControlsEvent::AnalyticsKeyEvents(entries)) = + decode_reprog_event(&msg, device_index, feature_index) + { + for entry in entries { + let cid: u16 = entry.cid.into(); + if cid != 0 { + on_event(cid, entry.event); + } + } + } + } + }); + + // Re-arm on a short cadence: a single arm at t=0 is lost if the BTLE link + // is asleep, and the config does not survive the device sleeping mid-run. + // Re-applying every few seconds guarantees it lands once the link is hot. + let arm_on = CidReportingChange { + analytics_key_events: Some(true), + ..CidReportingChange::default() + }; + let ticks = seconds.div_ceil(3).max(1); + for tick in 0..ticks { + // Arm the force pad (threshold 0x15a3, button 0), then enable analytics + // reporting on its control IDs — the full Options+ activation order. + if let Some(fsb) = &fsb { + match fsb.raw_call(3, [0x00, 0x15, 0xa3]).await { + Ok(r) if tick == 0 => { + eprintln!("[watch_panel] force threshold set -> {:02x?}", &r[..4]); + } + Err(e) if tick == 0 => eprintln!("[watch_panel] force threshold set failed: {e:?}"), + _ => {} + } + } + for cid in PANEL_ANALYTICS_CIDS { + match rc.set_cid_reporting_full(cid, arm_on).await { + Ok(_) if tick == 0 => eprintln!("[watch_panel] analytics armed on 0x{cid:04x}"), + Err(e) if tick == 0 => eprintln!("[watch_panel] arm 0x{cid:04x} failed: {e:?}"), + _ => {} + } + } + tokio::time::sleep(Duration::from_secs(3)).await; + } + + drop(listener); + for cid in PANEL_ANALYTICS_CIDS { + let _ = rc + .set_cid_reporting_full( + cid, + CidReportingChange { + analytics_key_events: Some(false), + ..CidReportingChange::default() + }, + ) + .await; + } + Ok(()) +} + +/// Sends one raw short-form call to ANY HID++ 2.0 feature by ID. Returns +/// `Ok(None)` when the device does not expose the feature. +/// Reverse-engineering aid; interpretation is the caller's. +pub async fn raw_feature_call( + route: &DeviceRoute, + feature_id: u16, + function: u8, + args: [u8; 3], +) -> Result, HiddenDiagError> { + bounded(async { + let device = open_device(route).await?; + device + .raw_feature_call(feature_id, function, args) + .await + .map_err(|e| HiddenDiagError::Hidpp(format!("{e:?}"))) + }) + .await +} + +/// Sends one raw `0x19c0 ForceSensingButton` call and returns the 16-byte +/// response payload. Reverse-engineering aid; interpretation is the caller's. +pub async fn force_button_raw_call( + route: &DeviceRoute, + function: u8, + args: [u8; 3], +) -> Result<[u8; 16], HiddenDiagError> { + bounded(async { + let mut device = open_device(route).await?; + let feature = open_feature::(&mut device) + .await + .map_err(|e| HiddenDiagError::Hidpp(e.to_string()))?; + feature + .raw_call(function, args) + .await + .map_err(|e| HiddenDiagError::Hidpp(format!("{e:?}"))) + }) + .await +} diff --git a/crates/openlogi-hid/src/inventory.rs b/crates/openlogi-hid/src/inventory.rs index a95294e4..aeabc963 100644 --- a/crates/openlogi-hid/src/inventory.rs +++ b/crates/openlogi-hid/src/inventory.rs @@ -74,7 +74,12 @@ const UNIFYING_SLOT_PROBE: Duration = Duration::from_millis(3500); /// headroom for a healthy walk: a feature-rich device enumerates a large table /// one round-trip per feature, and the MX Master 4 (45 features over Bolt) takes /// ~1–1.6 s even awake. The previous 1 s cap cut that walk off every tick, so -/// the device surfaced permanently with no capabilities or battery. +/// the device surfaced permanently with no capabilities or battery. The +/// *first* walk is slower still on the Windows BLE stack — 1–3 s measured on +/// an MX Master 4 in active use — and it is the gateway to the device being +/// usable at all: while it keeps timing out the cache never fills, so nothing +/// that keys off the device list (capture, DPI, the Action Ring) ever sees the +/// device. const BOLT_SLOT_PROBE: Duration = Duration::from_secs(3); /// Errors raised while enumerating HID++ devices. diff --git a/crates/openlogi-hid/src/inventory/cache.rs b/crates/openlogi-hid/src/inventory/cache.rs index 8899d502..be867445 100644 --- a/crates/openlogi-hid/src/inventory/cache.rs +++ b/crates/openlogi-hid/src/inventory/cache.rs @@ -21,6 +21,23 @@ pub(super) const REFRESH_TICKS: u64 = 15; pub(super) enum CacheKey { /// Bolt: the unit id from the pairing register (cheap, read every tick). Bolt { unit_id: [u8; 4] }, + /// Bolt fallback for a device whose pairing register reports an all-zero + /// unit id — real firmware does this (an MX Master 4 over Bolt, for one). + /// Without a key such a device is re-probed every tick forever: a full + /// feature walk (tens of HID++ round-trips) every couple of seconds, on + /// the radio link its own input shares, for as long as the agent runs. + /// + /// Keyed on receiver + slot + model rather than the device's own + /// identity, so it is weaker than [`Self::Bolt`]: a *different* model + /// paired into the same slot yields a different key, and the same model + /// re-paired there would have the same feature table anyway. Volatile + /// state (battery) is re-read per tick regardless, and `REFRESH_TICKS` + /// still forces a periodic self-healing re-walk. + BoltSlot { + receiver_uid: String, + slot: u8, + wpid: Option, + }, /// Unifying: keyed on the full receiver serial number + pairing slot. /// Using the complete serial (not just a prefix) avoids collisions between /// two receivers whose serials share a common prefix (e.g. "DA2699E1" and diff --git a/crates/openlogi-hid/src/inventory/probe.rs b/crates/openlogi-hid/src/inventory/probe.rs index 8e2b717d..f8f15be6 100644 --- a/crates/openlogi-hid/src/inventory/probe.rs +++ b/crates/openlogi-hid/src/inventory/probe.rs @@ -95,8 +95,14 @@ async fn probe_bolt_receiver( // serializing them costs little. let mut identities = Vec::new(); for slot in 1u8..=MAX_BOLT_SLOTS { - if let Some(identity) = - read_bolt_slot_identity(&bolt, &channel, by_slot.get(&slot), slot).await + if let Some(identity) = read_bolt_slot_identity( + &bolt, + &channel, + by_slot.get(&slot), + slot, + unique_id.as_deref(), + ) + .await { identities.push(identity); } @@ -266,6 +272,34 @@ async fn probe_unifying_receiver( } } +/// Cache identity for one Bolt slot. +/// +/// The pairing register gives the device's own unit id cheaply every tick and +/// is the preferred key. Some firmware reports it as all zeros, though (an MX +/// Master 4 over Bolt does), and treating that as "unidentifiable, re-probe +/// every tick" means a full feature walk — tens of HID++ round-trips — every +/// couple of seconds forever, over the same radio link the device sends its +/// input on. Those devices fall back to receiver + slot + model +/// ([`CacheKey::BoltSlot`]). +/// +/// `None` only when the receiver's own id is also unknown; that slot is +/// re-probed every tick, as before. +fn bolt_cache_key( + unit_id: [u8; 4], + receiver_uid: Option<&str>, + slot: u8, + wpid: Option, +) -> Option { + if unit_id != [0u8; 4] { + return Some(CacheKey::Bolt { unit_id }); + } + receiver_uid.map(|uid| CacheKey::BoltSlot { + receiver_uid: uid.to_string(), + slot, + wpid, + }) +} + /// Identity read from the receiver's registers for one occupied Bolt slot /// (phase 1). Both reads address the receiver at index `0xff`, and the channel /// correlates responses by register — not by the slot encoded in the request @@ -290,6 +324,7 @@ async fn read_bolt_slot_identity( channel: &Arc, event: Option<&BoltDeviceConnection>, slot: u8, + receiver_uid: Option<&str>, ) -> Option { let pairing = match bolt.get_device_pairing_information(slot).await { Ok(p) => p, @@ -314,12 +349,7 @@ async fn read_bolt_slot_identity( "paired slot" ); - // The pairing register gives the device's unit id cheaply every tick — its - // stable cache identity. An all-zero id is treated as unidentifiable (don't - // cache; always probe when online). - let id = (pairing.unit_id != [0u8; 4]).then_some(CacheKey::Bolt { - unit_id: pairing.unit_id, - }); + let id = bolt_cache_key(pairing.unit_id, receiver_uid, slot, wpid); Some(BoltSlotIdentity { slot, codename, @@ -363,8 +393,11 @@ async fn walk_bolt_slot( let (probe, outcome) = if let Ok(r) = probe_result { r } else { - debug!(slot, budget = ?BOLT_SLOT_PROBE, - "Bolt slot probe timed out; using cached data if available"); + debug!( + slot, + budget = ?BOLT_SLOT_PROBE, + "Bolt slot probe timed out; using cached data if available" + ); let probe = cached.map_or_else(ProbedFeatures::default, |c| c.probe.clone()); (probe, seen(id)) }; @@ -652,3 +685,63 @@ async fn read_codename(channel: &HidppChannel, slot: u8) -> Option { .ok() .map(str::to_string) } + +#[cfg(test)] +mod tests { + use super::{CacheKey, bolt_cache_key}; + + /// A device that reports a real unit id keys on it — the strongest + /// identity, independent of which slot it sits in. + #[test] + fn a_real_unit_id_keys_on_the_device_itself() { + assert_eq!( + bolt_cache_key([1, 2, 3, 4], Some("F00DCAFE"), 2, Some(0xb042)), + Some(CacheKey::Bolt { + unit_id: [1, 2, 3, 4] + }) + ); + } + + /// The regression this fixes: an all-zero unit id used to yield no key at + /// all, so the device was re-walked (tens of HID++ round-trips) on every + /// enumeration tick for as long as the agent ran. + #[test] + fn a_zero_unit_id_still_gets_a_cache_key() { + let key = bolt_cache_key([0; 4], Some("F00DCAFE"), 2, Some(0xb042)); + assert_eq!( + key, + Some(CacheKey::BoltSlot { + receiver_uid: "F00DCAFE".into(), + slot: 2, + wpid: Some(0xb042), + }), + "a zero unit id must not mean 'never cache'" + ); + } + + /// The fallback stays scoped: a different model, slot, or receiver is a + /// different key, so no device can inherit another's cached feature walk. + #[test] + fn the_fallback_key_does_not_collide_across_slots_models_or_receivers() { + let base = bolt_cache_key([0; 4], Some("F00DCAFE"), 2, Some(0xb042)); + assert_ne!( + base, + bolt_cache_key([0; 4], Some("F00DCAFE"), 3, Some(0xb042)) + ); + assert_ne!( + base, + bolt_cache_key([0; 4], Some("F00DCAFE"), 2, Some(0xc548)) + ); + assert_ne!( + base, + bolt_cache_key([0; 4], Some("0BADBEEF"), 2, Some(0xb042)) + ); + } + + /// With no receiver id there is nothing stable to key on, so the old + /// re-probe-every-tick behaviour is kept rather than risking a collision. + #[test] + fn no_receiver_id_means_no_key() { + assert_eq!(bolt_cache_key([0; 4], None, 2, Some(0xb042)), None); + } +} diff --git a/crates/openlogi-hid/src/lib.rs b/crates/openlogi-hid/src/lib.rs index b6cf1547..88bd7647 100644 --- a/crates/openlogi-hid/src/lib.rs +++ b/crates/openlogi-hid/src/lib.rs @@ -20,6 +20,7 @@ mod transport; mod windows_hid; pub mod gesture; +pub mod hidden_features; mod hires_wheel; pub mod hotplug; pub mod inventory; diff --git a/crates/openlogi-hid/src/reprog_controls.rs b/crates/openlogi-hid/src/reprog_controls.rs index c25d4e3b..c81115a5 100644 --- a/crates/openlogi-hid/src/reprog_controls.rs +++ b/crates/openlogi-hid/src/reprog_controls.rs @@ -37,12 +37,66 @@ pub const FEATURE_ID: u16 = 0x1b04; /// Control ID of the MX-line dedicated gesture button (`Mouse_Gesture_Button`, /// Logitech "App_Switch_Gesture"). /// -/// MX Master 4 also has a separate Haptic Sense Panel in the thumb area. That -/// panel is not this CID; it must be discovered from the device's `0x1b04` -/// control table and supported explicitly before OpenLogi treats it as a -/// bindable/capturable input. +/// The MX Master 4's force-sensitive thumb pad (the Action Ring) is a separate +/// control — see [`ACTION_RING_CID`]. pub const GESTURE_BUTTON_CID: u16 = 0x00c3; +/// Control ID `0x00d7` ("Virtual Gesture Button") on the MX Master 4 — +/// historically mistaken for the Action Ring pad's event path. **Do not divert +/// it.** +/// +/// It is the only control on the device advertising `force-raw-xy`, which made +/// it look like the force pad. On real hardware (`wpid=b042`), diverting it +/// with `force_raw_xy` hijacks the mouse's entire sensor stream and freezes +/// the cursor, and a plain divert + raw-XY produces no pad events at all. The +/// pad's real event path is `analyticsKeyEvents` on +/// [`ACTION_RING_CID`]. Kept documented so the dead end is not +/// rediscovered. +pub const HAPTIC_PANEL_CID: u16 = 0x00d7; + +/// Control ID of the MX Master 4 Action Ring pad — the force-sensitive ridged +/// thumb pad (eight dots in a ring) that drives the Actions Ring in Options+. +/// +/// The only control in the device's `0x1b04` table advertising +/// `analytics-events`; its presence there is how a capture session detects the +/// pad. The pad is dormant until its `0x19c0` force threshold is written and +/// silent until `analyticsKeyEvents` reporting is enabled — see +/// `gesture::arm_controls`. Pad taps arrive on **this CID only**; see +/// [`LEFT_BUTTON_CID`] for why the "companion" CIDs must never be armed in +/// production. +pub const ACTION_RING_CID: u16 = 0x01a0; + +/// Left mouse button control ID. With `analyticsKeyEvents` reporting enabled +/// it reports **every physical left click** as a press/release pair — which is +/// why Options+ arms it (click telemetry) and why OpenLogi's ring arming must +/// not: with it armed, every click on the desktop opened the ring +/// (hardware-confirmed 2026-07-20). Earlier discovery notes calling +/// `0x0050`/`0x0051` "companions of the pad" were a misread of stray real +/// clicks in those captures. +pub const LEFT_BUTTON_CID: u16 = 0x0050; + +/// Right mouse button control ID — see [`LEFT_BUTTON_CID`]; same telemetry +/// behaviour for right clicks. +pub const RIGHT_BUTTON_CID: u16 = 0x0051; + +/// CIDs the *diagnostic* panel watcher arms — the pad plus the click-telemetry +/// CIDs Options+ also arms, so `openlogi diag panel` shows the full analytics +/// stream (pad taps AND clicks, each labeled by CID). Production ring capture +/// arms [`ACTION_RING_CID`] alone. +pub const PANEL_DIAG_ANALYTICS_CIDS: [u16; 3] = + [ACTION_RING_CID, LEFT_BUTTON_CID, RIGHT_BUTTON_CID]; + +/// Control ID of the thumb-side "back" button (Logi's decimal `_c83` in the +/// asset metadata). On the MX Master 4 the side buttons emit **no native +/// HID button events at all** — hardware-confirmed 2026-07-20: with no +/// Logitech software running they do nothing in any app — so the capture +/// session diverts them and dispatches their bindings, the same job +/// Options+ quietly does on this device. +pub const BACK_CID: u16 = 0x0053; + +/// Control ID of the thumb-side "forward" button (`_c86`) — see [`BACK_CID`]. +pub const FORWARD_CID: u16 = 0x0056; + /// Control IDs of the "DPI / ModeShift" button family. Whichever a device /// exposes (and can divert) is captured and mapped to /// [`ButtonId::DpiToggle`](openlogi_core::binding::ButtonId::DpiToggle): the MX diff --git a/crates/openlogi-hid/src/reprog_controls/event.rs b/crates/openlogi-hid/src/reprog_controls/event.rs index ed0e3970..376efd62 100644 --- a/crates/openlogi-hid/src/reprog_controls/event.rs +++ b/crates/openlogi-hid/src/reprog_controls/event.rs @@ -1,6 +1,6 @@ use hidpp::protocol::v20; -use super::{ControlId, ReprogControlsEvent, decode_full_event}; +use super::{AnalyticsKeyEvent, ControlId, ReprogControlsEvent, decode_full_event}; /// An unsolicited `0x1b04` event decoded for OpenLogi's gesture pipeline. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -17,6 +17,11 @@ pub enum RawControlEvent { /// Vertical delta (`+` = down, in the device's raw units). dy: i16, }, + /// `analyticsKeyEvents`: up to five `(cid, event)` entries from controls + /// armed for analytics reporting — the MX Master 4 Action Ring pad's event + /// path (`event` `0x01` = press, `0x00` = release). A zero CID is an empty + /// slot. + AnalyticsKeys([AnalyticsKeyEvent; 5]), } impl RawControlEvent { @@ -36,8 +41,8 @@ impl TryFrom for RawControlEvent { Ok(Self::DivertedButtons(cids.map(ControlId::into))) } ReprogControlsEvent::DivertedRawMouseXy { dx, dy } => Ok(Self::RawXy { dx, dy }), - ReprogControlsEvent::AnalyticsKeyEvents(_) - | ReprogControlsEvent::DivertedRawWheel { .. } => Err(event), + ReprogControlsEvent::AnalyticsKeyEvents(entries) => Ok(Self::AnalyticsKeys(entries)), + ReprogControlsEvent::DivertedRawWheel { .. } => Err(event), } } } @@ -106,13 +111,49 @@ mod tests { ); } + #[test] + fn decodes_analytics_press_and_release_entries() { + let mut p = [0u8; 16]; + // Entry 0: Action Ring pad press; entry 1: companion CID release. + p[0..2].copy_from_slice(&crate::reprog_controls::ACTION_RING_CID.to_be_bytes()); + p[2] = 0x01; + p[3..5].copy_from_slice(&0x0050u16.to_be_bytes()); + p[5] = 0x00; + let decoded = decode_event(&event(2, 0, p), 2, 7); + let Some(RawControlEvent::AnalyticsKeys(entries)) = decoded else { + panic!("analytics key events should decode, got {decoded:?}"); + }; + assert_eq!( + entries[0], + AnalyticsKeyEvent { + cid: ControlId(crate::reprog_controls::ACTION_RING_CID), + event: 0x01, + }, + "press entries carry event 0x01" + ); + assert_eq!( + entries[1], + AnalyticsKeyEvent { + cid: ControlId(0x0050), + event: 0x00, + }, + "release entries carry event 0x00" + ); + assert_eq!( + entries[2], + AnalyticsKeyEvent::default(), + "unused slots decode as zero CIDs" + ); + } + #[test] fn ignores_responses_and_foreign_messages() { let p = [0u8; 16]; // software_id != 0 marks a request response, not an event. assert_eq!(decode_event(&event(0, 5, p), 2, 7), None); - // Right device + feature, but an event outside the gesture-control path. - assert_eq!(decode_event(&event(2, 0, p), 2, 7), None); + // Right device + feature, but an event outside the gesture-control + // path (function 4 = raw wheel, which OpenLogi discards). + assert_eq!(decode_event(&event(4, 0, p), 2, 7), None); // Wrong feature index. assert_eq!(decode_event(&event(0, 0, p), 2, 9), None); } diff --git a/crates/openlogi-hidpp/src/device.rs b/crates/openlogi-hidpp/src/device.rs index 1de9fd6f..81dac932 100755 --- a/crates/openlogi-hidpp/src/device.rs +++ b/crates/openlogi-hidpp/src/device.rs @@ -8,7 +8,7 @@ use tracing::trace; use crate::{ channel::{ChannelError, HidppChannel}, feature::{ - self, CreatableFeature, Feature, + self, CreatableFeature, Feature, FeatureEndpoint, feature_set::{FeatureInformation, FeatureSetFeature}, root::RootFeature, }, @@ -122,6 +122,26 @@ impl Device { .and_then(|feat| Arc::downcast::(feat).ok()) } + /// Resolves `feature_id` at runtime and sends one short-form call to it, + /// returning the 16-byte response payload, or `Ok(None)` if the device + /// does not expose the feature. + /// + /// Reverse-engineering aid for features without typed wrappers — the + /// caller owns interpretation of the payload. Typed wrappers remain the + /// path for anything shipping. + pub async fn raw_feature_call( + &self, + feature_id: u16, + function: u8, + args: [u8; 3], + ) -> Result, Hidpp20Error> { + let Some(info) = self.root().get_feature(feature_id).await? else { + return Ok(None); + }; + let endpoint = FeatureEndpoint::new(Arc::clone(&self.chan), self.device_index, info.index); + Ok(Some(endpoint.call(function, args).await?.extend_payload())) + } + /// Tries to detect all features supported by the device and add /// implementations for them using [`feature::registry::lookup_version`]. /// diff --git a/crates/openlogi-hidpp/src/feature/enable_hidden_features/mod.rs b/crates/openlogi-hidpp/src/feature/enable_hidden_features/mod.rs new file mode 100644 index 00000000..553757f7 --- /dev/null +++ b/crates/openlogi-hidpp/src/feature/enable_hidden_features/mod.rs @@ -0,0 +1,52 @@ +//! Implements the `EnableHiddenFeatures` feature (`0x1e00`). +//! +//! A one-byte gate for engineering/optional functionality: some devices keep +//! auxiliary event sources dormant until a host enables this feature. Vendor +//! software (Logi Options+) is believed to enable it at session start; the +//! function layout below (get = function 0, set = function 1, enabled flag in +//! byte 0) matches the de-facto layout used by Solaar and libratbag. + +use std::sync::Arc; + +use crate::{ + channel::HidppChannel, + feature::{CreatableFeature, Feature, FeatureEndpoint}, + protocol::v20::Hidpp20Error, +}; + +/// Implements `EnableHiddenFeatures` / `0x1e00`. +#[derive(Clone)] +pub struct EnableHiddenFeaturesFeature { + /// The endpoint this feature talks to. + endpoint: FeatureEndpoint, +} + +impl CreatableFeature for EnableHiddenFeaturesFeature { + const ID: u16 = 0x1e00; + const STARTING_VERSION: u8 = 0; + + fn new(chan: Arc, device_index: u8, feature_index: u8) -> Self { + Self { + endpoint: FeatureEndpoint::new(chan, device_index, feature_index), + } + } +} + +impl Feature for EnableHiddenFeaturesFeature {} + +impl EnableHiddenFeaturesFeature { + /// Reads whether hidden features are currently enabled (`getEnabled`, + /// function `0`). + pub async fn get_enabled(&self) -> Result { + let payload = self.endpoint.call(0, [0; 3]).await?.extend_payload(); + Ok(payload[0] != 0) + } + + /// Enables or disables hidden features (`setEnabled`, function `1`). + /// + /// The device does not persist this across power cycles. + pub async fn set_enabled(&self, enabled: bool) -> Result<(), Hidpp20Error> { + self.endpoint.call(1, [u8::from(enabled), 0, 0]).await?; + Ok(()) + } +} diff --git a/crates/openlogi-hidpp/src/feature/force_sensing_button/mod.rs b/crates/openlogi-hidpp/src/feature/force_sensing_button/mod.rs new file mode 100644 index 00000000..829e45e2 --- /dev/null +++ b/crates/openlogi-hidpp/src/feature/force_sensing_button/mod.rs @@ -0,0 +1,64 @@ +//! Implements the `ForceSensingButton` feature (`0x19c0`) — the +//! force-sensitive pad first seen as the MX Master 4's Action Ring button. +//! +//! The function map of this feature is NOT publicly documented. Everything +//! here is reverse-engineered against real hardware; this wrapper therefore +//! exposes a deliberately raw probe surface so callers can map the function +//! table, and typed accessors should replace [`Self::raw_call`] as layouts are +//! confirmed on hardware. Keep the reverse-engineering annotations honest. + +use std::sync::Arc; + +use crate::{ + channel::HidppChannel, + feature::{CreatableFeature, Feature, FeatureEndpoint}, + protocol::v20::Hidpp20Error, +}; + +/// Implements `ForceSensingButton` / `0x19c0`. +#[derive(Clone)] +pub struct ForceSensingButtonFeature { + /// The endpoint this feature talks to. + endpoint: FeatureEndpoint, +} + +impl CreatableFeature for ForceSensingButtonFeature { + const ID: u16 = 0x19c0; + const STARTING_VERSION: u8 = 0; + + fn new(chan: Arc, device_index: u8, feature_index: u8) -> Self { + Self { + endpoint: FeatureEndpoint::new(chan, device_index, feature_index), + } + } +} + +impl Feature for ForceSensingButtonFeature {} + +impl ForceSensingButtonFeature { + /// Raw short-form call: sends `function` with three argument bytes and + /// returns the 16-byte response payload verbatim. + /// + /// Reverse-engineering aid — the caller owns interpretation. A device + /// rejecting an unknown function returns the HID++ 2.0 `InvalidFunction` + /// error rather than garbage, so probing function IDs is safe. + pub async fn raw_call(&self, function: u8, args: [u8; 3]) -> Result<[u8; 16], Hidpp20Error> { + Ok(self.endpoint.call(function, args).await?.extend_payload()) + } + + /// Sets `button`'s force-activation threshold (function `3`). + /// + /// Reverse-engineered on a real MX Master 4 (`wpid=b042`): the pad is + /// dormant until a threshold is written, and Options+ writes `0x15a3` for + /// button `0` at startup — the call that arms the Action Ring pad. + /// Function `2` with the same button index reads the value back. + pub async fn set_force_threshold( + &self, + button: u8, + threshold: u16, + ) -> Result<(), Hidpp20Error> { + let [hi, lo] = threshold.to_be_bytes(); + self.endpoint.call(3, [button, hi, lo]).await?; + Ok(()) + } +} diff --git a/crates/openlogi-hidpp/src/feature/mod.rs b/crates/openlogi-hidpp/src/feature/mod.rs index ec39e990..fbf6ed16 100755 --- a/crates/openlogi-hidpp/src/feature/mod.rs +++ b/crates/openlogi-hidpp/src/feature/mod.rs @@ -20,11 +20,13 @@ pub mod device_type_and_name; pub mod disable_keys; pub mod disable_keys_by_usage; pub mod dual_platform; +pub mod enable_hidden_features; pub mod equalizer; pub mod extended_dpi; pub mod extended_report_rate; pub mod feature_set; pub mod fn_inversion; +pub mod force_sensing_button; pub mod hires_wheel; pub mod hosts_info; pub mod illumination; diff --git a/crates/openlogi-hidpp/src/feature/registry.rs b/crates/openlogi-hidpp/src/feature/registry.rs index 83897373..249016f5 100755 --- a/crates/openlogi-hidpp/src/feature/registry.rs +++ b/crates/openlogi-hidpp/src/feature/registry.rs @@ -24,11 +24,13 @@ use crate::{ disable_keys::DisableKeysFeature, disable_keys_by_usage::DisableKeysByUsageFeature, dual_platform::DualPlatformFeature, + enable_hidden_features::EnableHiddenFeaturesFeature, equalizer::EqualizerFeature, extended_dpi::ExtendedDpiFeature, extended_report_rate::ExtendedReportRateFeature, feature_set::FeatureSetFeature, fn_inversion::{FnInversionMultiHostFeature, FnInversionWithDefaultStateFeature}, + force_sensing_button::ForceSensingButtonFeature, hires_wheel::HiResWheelFeature, hosts_info::HostsInfoFeature, illumination::IlluminationFeature, @@ -169,7 +171,7 @@ static KNOWN_FEATURES: LazyLock> = LazyLock::new(|| { 0x1983 "Backlight3", 0x1990 "Illumination" => IlluminationFeature, 0x19b0 "HapticFeedback", - 0x19c0 "ForceSensingButton", + 0x19c0 "ForceSensingButton" => ForceSensingButtonFeature, 0x1a00 "PresenterControl", 0x1a01 "Sensor3D", 0x1b00 "ReprogControls", @@ -181,6 +183,7 @@ static KNOWN_FEATURES: LazyLock> = LazyLock::new(|| { 0x1c00 "PersistentRemappableAction" => PersistentRemappableActionFeature, 0x1d4b "WirelessDeviceStatus" => WirelessDeviceStatusFeature, 0x1df0 "RemainingPairings", + 0x1e00 "EnableHiddenFeatures" => EnableHiddenFeaturesFeature, 0x1f1f "FirmwareProperties", 0x1f20 "AdcMeasurement", 0x2001 "SwapLeftRightButton", diff --git a/crates/openlogi-inject/Cargo.toml b/crates/openlogi-inject/Cargo.toml index e3c5c105..8e611738 100644 --- a/crates/openlogi-inject/Cargo.toml +++ b/crates/openlogi-inject/Cargo.toml @@ -37,6 +37,14 @@ objc2-app-kit = { workspace = true, features = [ objc2-core-graphics = { version = "0.3.2", features = ["CGEvent"] } objc2-foundation = { workspace = true } -# SendInput-based action synthesis (execute_windows). +# SendInput-based action synthesis (execute_windows). `Run` calls +# ShellExecuteW, which windows-sys gates on Win32_UI_WindowsAndMessaging +# (its SHOW_WINDOW_CMD parameter) as well as Win32_UI_Shell — both are +# required here even though a workspace build would unify them in from +# another crate. [target.'cfg(target_os = "windows")'.dependencies] -windows-sys = { workspace = true, features = ["Win32_UI_Input_KeyboardAndMouse"] } +windows-sys = { workspace = true, features = [ + "Win32_UI_Input_KeyboardAndMouse", + "Win32_UI_Shell", + "Win32_UI_WindowsAndMessaging", +] } diff --git a/crates/openlogi-inject/src/inject/linux.rs b/crates/openlogi-inject/src/inject/linux.rs index 15216e20..403f2ec2 100644 --- a/crates/openlogi-inject/src/inject/linux.rs +++ b/crates/openlogi-inject/src/inject/linux.rs @@ -19,7 +19,8 @@ pub(super) fn execute(action: &Action) { let ctrl = KeyCode::KEY_LEFTCTRL; let shift = KeyCode::KEY_LEFTSHIFT; let alt = KeyCode::KEY_LEFTALT; - match action { + // A user-chosen label is presentation only — dispatch what it wraps. + match action.inner() { // ── Mouse clicks ────────────────────────────────────────────────── Action::LeftClick => click(KeyCode::BTN_LEFT), Action::RightClick => click(KeyCode::BTN_RIGHT), @@ -108,6 +109,46 @@ pub(super) fn execute(action: &Action) { }; press_key(&modifiers_to_keycodes(combo.modifiers), key); } + // ── Run / Paste Text ────────────────────────────────────────────── + // `xdg-open` routes URLs and documents to the right handler; an + // explicit `||` argument string execs the target directly instead, + // since xdg-open takes no arguments. + Action::Run(payload) => run_target(payload), + // Typing arbitrary Unicode through uinput needs a keymap round-trip + // (evdev codes are layout-relative); not wired up yet. + Action::PasteText(_) => { + tracing::warn!("PasteText is not implemented on Linux yet — press ignored"); + } + Action::Folder(_) => { + tracing::warn!("folder reached the injector — containers are resolved by the ring"); + } + // `inner()` already stripped every label. + Action::Named { .. } => {} + } +} + +/// Open a [`Action::Run`] target (see the match arm above for the split). +/// The child is reaped on a detached thread so short-lived openers don't +/// linger as zombies. +fn run_target(payload: &str) { + let (target, args) = openlogi_core::binding::split_run_target(payload); + if target.is_empty() { + tracing::warn!("Run action with an empty target; ignored"); + return; + } + let spawned = match args { + Some(args) => std::process::Command::new(target) + .args(args.split_whitespace()) + .spawn(), + None => std::process::Command::new("xdg-open").arg(target).spawn(), + }; + match spawned { + Ok(mut child) => { + std::thread::spawn(move || { + let _ = child.wait(); + }); + } + Err(e) => tracing::warn!(run_target = target, "Run target failed to spawn: {e}"), } } @@ -285,6 +326,9 @@ fn modifiers_to_keycodes(modifiers: u8) -> Vec { if modifiers & KeyCombo::MOD_OPTION != 0 { mods.push(KeyCode::KEY_LEFTALT); } + if modifiers & KeyCombo::MOD_WIN != 0 { + mods.push(KeyCode::KEY_LEFTMETA); + } mods } diff --git a/crates/openlogi-inject/src/inject/macos.rs b/crates/openlogi-inject/src/inject/macos.rs index a492d62a..d26c7087 100644 --- a/crates/openlogi-inject/src/inject/macos.rs +++ b/crates/openlogi-inject/src/inject/macos.rs @@ -41,9 +41,11 @@ pub(super) fn execute(action: &Action) { let shift = CGEventFlags::CGEventFlagShift; let ctrl = CGEventFlags::CGEventFlagControl; - match action { - // Suppressed input: captured but deliberately produces no event. - Action::None => {} + // A user-chosen label is presentation only — dispatch what it wraps. + match action.inner() { + // Suppressed input: captured but deliberately produces no event; + // `inner()` already stripped every label. + Action::None | Action::Named { .. } => {} // ── Mouse clicks: synthesise a click at the cursor ──────────────── // Remapping a *different* button to a click lands here (e.g. Back → // MiddleClick). A button left on its own native click never reaches @@ -144,8 +146,49 @@ pub(super) fn execute(action: &Action) { if combo.modifiers & KeyCombo::MOD_OPTION != 0 { flags |= CGEventFlags::CGEventFlagAlternate; } + // ⊞ has no macOS key; ⌘ is the conventional stand-in. + if combo.modifiers & KeyCombo::MOD_WIN != 0 { + flags |= CGEventFlags::CGEventFlagCommand; + } post_key(combo.key_code, flags); } + // ── Run / Paste Text ────────────────────────────────────────────── + // `open` routes URLs, apps and documents through Launch Services; an + // explicit `||` argument string execs the target directly instead. + Action::Run(payload) => run_target(payload), + // Unicode typing (CGEvent keyboardSetUnicodeString) is not wired up + // yet. + Action::PasteText(_) => { + tracing::warn!("PasteText is not implemented on macOS yet — press ignored"); + } + Action::Folder(_) => { + tracing::warn!("folder reached the injector — containers are resolved by the ring"); + } + } +} + +/// Open a [`Action::Run`] target (see the match arm above for the split). +/// The child is reaped on a detached thread so short-lived openers don't +/// linger as zombies. +fn run_target(payload: &str) { + let (target, args) = openlogi_core::binding::split_run_target(payload); + if target.is_empty() { + tracing::warn!("Run action with an empty target; ignored"); + return; + } + let spawned = match args { + Some(args) => std::process::Command::new(target) + .args(args.split_whitespace()) + .spawn(), + None => std::process::Command::new("open").arg(target).spawn(), + }; + match spawned { + Ok(mut child) => { + std::thread::spawn(move || { + let _ = child.wait(); + }); + } + Err(e) => tracing::warn!(run_target = target, "Run target failed to spawn: {e}"), } } diff --git a/crates/openlogi-inject/src/inject/windows.rs b/crates/openlogi-inject/src/inject/windows.rs index 74c74536..bae0f1b8 100644 --- a/crates/openlogi-inject/src/inject/windows.rs +++ b/crates/openlogi-inject/src/inject/windows.rs @@ -4,16 +4,31 @@ use std::mem::size_of; use windows_sys::Win32::UI::Input::KeyboardAndMouse::{ - INPUT, INPUT_0, INPUT_KEYBOARD, INPUT_MOUSE, KEYBDINPUT, KEYEVENTF_KEYUP, MOUSEEVENTF_HWHEEL, - MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP, - MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, - MOUSEEVENTF_XUP, MOUSEINPUT, SendInput, + INPUT, INPUT_0, INPUT_KEYBOARD, INPUT_MOUSE, KEYBDINPUT, KEYEVENTF_KEYUP, KEYEVENTF_UNICODE, + MAPVK_VK_TO_VSC, MOUSEEVENTF_HWHEEL, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, + MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, + MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP, MOUSEINPUT, MapVirtualKeyW, SendInput, }; +use windows_sys::Win32::UI::Shell::ShellExecuteW; +use windows_sys::Win32::UI::WindowsAndMessaging::SW_SHOWNORMAL; -use openlogi_core::binding::{Action, KeyCombo}; +use openlogi_core::binding::{Action, KeyCombo, split_run_target}; const WHEEL_DELTA: i32 = 120; +/// How long a [`Action::CustomShortcut`] holds its keys down. +/// +/// A whole chord delivered in one `SendInput` batch is physically down for +/// microseconds. That is invisible to any hotkey listener that **polls** +/// key state (`GetAsyncKeyState`) instead of handling key messages — the +/// press falls between two samples and the app never fires. Polling is +/// common precisely for chords like Ctrl+Space, where `RegisterHotKey`'s +/// modifier-order rules are awkward. A real keypress lasts ~100 ms, so the +/// synthetic one dwells too: long enough for any sane poll interval (a +/// 60 fps frame loop is 16 ms) to sample it, short enough to feel instant +/// and never auto-repeat. +const CHORD_HOLD: std::time::Duration = std::time::Duration::from_millis(120); + const VK_A: u16 = 0x41; const VK_C: u16 = 0x43; const VK_D: u16 = 0x44; @@ -28,6 +43,7 @@ const VK_X: u16 = 0x58; const VK_Y: u16 = 0x59; const VK_Z: u16 = 0x5A; const VK_TAB: u16 = 0x09; +const VK_RETURN: u16 = 0x0D; const VK_LEFT: u16 = 0x25; const VK_RIGHT: u16 = 0x27; const VK_SHIFT: u16 = 0x10; @@ -64,7 +80,8 @@ const XBUTTON2: i32 = 2; /// window-manager actions map to their Windows equivalents; `CustomShortcut` /// maps macOS `kVK_*` codes to Windows virtual-key codes (Cmd → Ctrl). pub(super) fn execute(action: &Action) { - match action { + // A user-chosen label is presentation only — dispatch what it wraps. + match action.inner() { Action::LeftClick => post_click(MouseButton::Left), Action::RightClick => post_click(MouseButton::Right), Action::MiddleClick => post_click(MouseButton::Middle), @@ -124,7 +141,137 @@ pub(super) fn execute(action: &Action) { | Action::HorizontalScrollLeft | Action::HorizontalScrollRight => post_scroll(action), Action::CustomShortcut(combo) => post_custom_shortcut(combo), - Action::None => {} + Action::Run(payload) => run_target(payload), + Action::PasteText(text) => post_text(text), + Action::Folder(_) => { + tracing::warn!("folder reached the injector — containers are resolved by the ring"); + } + // `inner()` already stripped every label. + Action::Named { .. } | Action::None => {} + } +} + +/// Open a [`Action::Run`] target through the shell: URLs launch the default +/// browser, documents open their association, executables run with the `||` +/// argument string. `%VAR%` environment references expand in both halves. +fn run_target(payload: &str) { + let (target, args) = split_run_target(payload); + if target.is_empty() { + tracing::warn!("Run action with an empty target; ignored"); + return; + } + let target = expand_env(target); + let params = args.map(expand_env); + + let wide_target = wide(&target); + let wide_params = params.as_deref().map(wide); + let wide_verb = wide("open"); + // SAFETY: all pointers are NUL-terminated UTF-16 buffers that outlive the + // call; ShellExecuteW copies what it needs before returning. + let result = unsafe { + ShellExecuteW( + std::ptr::null_mut(), + wide_verb.as_ptr(), + wide_target.as_ptr(), + wide_params.as_ref().map_or(std::ptr::null(), Vec::as_ptr), + std::ptr::null(), + SW_SHOWNORMAL, + ) + }; + // ShellExecuteW's documented error contract: values ≤ 32 are error codes. + if result as usize <= 32 { + tracing::warn!(target = %target, code = result as usize, "Run target failed to open"); + } else { + tracing::debug!(target = %target, "Run target opened"); + } +} + +/// NUL-terminated UTF-16 for Win32 `W` APIs. +fn wide(text: &str) -> Vec { + text.encode_utf16().chain(std::iter::once(0)).collect() +} + +/// Expand `%NAME%` environment references: `%%` escapes a literal `%`, and +/// unknown names keep their literal spelling (cmd.exe behavior). +fn expand_env(value: &str) -> String { + expand_env_with(value, |name| std::env::var(name).ok()) +} + +/// [`expand_env`] with the variable source injected, so the parse is +/// deterministic under test. +fn expand_env_with(value: &str, lookup: impl Fn(&str) -> Option) -> String { + let mut out = String::with_capacity(value.len()); + let mut rest = value; + while let Some(start) = rest.find('%') { + out.push_str(&rest[..start]); + let after = &rest[start + 1..]; + if let Some(end) = after.find('%') { + let name = &after[..end]; + if name.is_empty() { + out.push('%'); + } else if let Some(resolved) = lookup(name) { + out.push_str(&resolved); + } else { + out.push('%'); + out.push_str(name); + out.push('%'); + } + rest = &after[end + 1..]; + } else { + // A lone trailing % is literal. + out.push('%'); + rest = after; + } + } + out.push_str(rest); + out +} + +/// Type [`Action::PasteText`]'s snippet as `KEYEVENTF_UNICODE` events — no +/// clipboard involvement, so the user's clipboard survives. Line breaks +/// become Enter and tabs become Tab presses so multi-line snippets land the +/// way they read; astral-plane characters ride as surrogate halves, which is +/// the documented `KEYEVENTF_UNICODE` convention. +fn post_text(text: &str) { + let mut inputs = Vec::with_capacity(text.len() * 2); + for ch in text.replace("\r\n", "\n").chars() { + match ch { + '\n' => { + inputs.push(key_input(VK_RETURN, false)); + inputs.push(key_input(VK_RETURN, true)); + } + '\t' => { + inputs.push(key_input(VK_TAB, false)); + inputs.push(key_input(VK_TAB, true)); + } + _ => { + let mut units = [0u16; 2]; + for unit in ch.encode_utf16(&mut units) { + inputs.push(unicode_input(*unit, false)); + inputs.push(unicode_input(*unit, true)); + } + } + } + } + send_inputs(&inputs); +} + +fn unicode_input(unit: u16, key_up: bool) -> INPUT { + let mut flags = KEYEVENTF_UNICODE; + if key_up { + flags |= KEYEVENTF_KEYUP; + } + INPUT { + r#type: INPUT_KEYBOARD, + Anonymous: INPUT_0 { + ki: KEYBDINPUT { + wVk: 0, + wScan: unit, + dwFlags: flags, + time: 0, + dwExtraInfo: 0, + }, + }, } } @@ -204,7 +351,36 @@ fn post_custom_shortcut(combo: &KeyCombo) { if combo.modifiers & KeyCombo::MOD_OPTION != 0 { modifiers.push(VK_MENU); } - post_key(vk, &modifiers); + if combo.modifiers & KeyCombo::MOD_WIN != 0 { + modifiers.push(VK_LWIN); + } + post_held_chord(vk, modifiers); +} + +/// Press `modifiers` + `vk`, hold for [`CHORD_HOLD`], then release in +/// reverse order — the shape of a real keypress rather than an +/// instantaneous blip (see [`CHORD_HOLD`]). +/// +/// Runs on its own thread: the caller is a hook callback or an IPC handler +/// that must not stall for the hold. +fn post_held_chord(vk: u16, modifiers: Vec) { + std::thread::spawn(move || { + let mut press = Vec::with_capacity(modifiers.len() + 1); + for modifier in &modifiers { + press.push(key_input(*modifier, false)); + } + press.push(key_input(vk, false)); + send_inputs(&press); + + std::thread::sleep(CHORD_HOLD); + + let mut release = Vec::with_capacity(modifiers.len() + 1); + release.push(key_input(vk, true)); + for modifier in modifiers.iter().rev() { + release.push(key_input(*modifier, true)); + } + send_inputs(&release); + }); } fn send_inputs(inputs: &[INPUT]) { @@ -235,12 +411,19 @@ fn key_input(vk: u16, key_up: bool) -> INPUT { if key_up { flags |= KEYEVENTF_KEYUP; } + // Carry the hardware scan code alongside the virtual key. Windows + // forwards it to low-level hooks as `KBDLLHOOKSTRUCT::scanCode`, and + // listeners that read that field (rather than the virtual key) ignore + // events where it is zero. + // SAFETY: MapVirtualKeyW is a pure lookup over the active layout; it + // takes no pointers and returns 0 for codes with no mapping. + let scan = unsafe { MapVirtualKeyW(u32::from(vk), MAPVK_VK_TO_VSC) }; INPUT { r#type: INPUT_KEYBOARD, Anonymous: INPUT_0 { ki: KEYBDINPUT { wVk: vk, - wScan: 0, + wScan: u16::try_from(scan).unwrap_or(0), dwFlags: flags, time: 0, dwExtraInfo: 0, @@ -264,3 +447,85 @@ fn mouse_input(flags: u32, data: i32) -> INPUT { }, } } + +#[cfg(test)] +mod tests { + use super::expand_env_with; + + /// The [`CHORD_HOLD`] contract, tested against the mechanism it exists + /// for: a listener that samples physical key state on a timer (the + /// common shape for global chords) must observe the synthetic chord + /// down. Before the hold, the whole chord went out in one `SendInput` + /// batch and every such listener missed it. + /// + /// Ignored by default: it needs an interactive desktop session (CI has + /// none, and `SendInput` is a no-op in session 0) and it briefly + /// presses real keys. Run with: + /// `cargo test -p openlogi-inject -- --ignored held_chord` + #[test] + #[ignore = "injects real key events; needs an interactive desktop"] + fn held_chord_is_visible_to_a_polling_listener() { + use openlogi_core::binding::{Action, KeyCombo}; + use std::sync::Arc; + use std::sync::atomic::{AtomicBool, Ordering}; + use std::time::{Duration, Instant}; + use windows_sys::Win32::UI::Input::KeyboardAndMouse::GetAsyncKeyState; + + // kVK 0x69 → VK_F13: bound by essentially nothing, so the test + // can't trip a real hotkey on the machine running it. + const VK_CONTROL: i32 = 0x11; + const VK_F13: i32 = 0x7C; + + let seen = Arc::new(AtomicBool::new(false)); + let poller = { + let seen = Arc::clone(&seen); + std::thread::spawn(move || { + let deadline = Instant::now() + Duration::from_millis(600); + while Instant::now() < deadline { + // SAFETY: same pure state read as the production path. + let down = + |vk: i32| unsafe { GetAsyncKeyState(vk) }.cast_unsigned() & 0x8000 != 0; + if down(VK_CONTROL) && down(VK_F13) { + seen.store(true, Ordering::SeqCst); + return; + } + std::thread::sleep(Duration::from_millis(15)); + } + }) + }; + + super::execute(&Action::CustomShortcut(KeyCombo { + modifiers: KeyCombo::MOD_CTRL, + key_code: 0x69, + display: "Ctrl+F13".into(), + })); + + drop(poller.join()); + assert!( + seen.load(Ordering::SeqCst), + "a 15 ms poller never saw the chord down — CHORD_HOLD is too short or the press is instantaneous" + ); + } + + #[test] + fn expand_env_substitutes_known_and_keeps_unknown_names() { + let lookup = |name: &str| match name { + "USERPROFILE" => Some(r"C:\Users\demo".to_string()), + _ => None, + }; + assert_eq!( + expand_env_with(r"%USERPROFILE%\notes.txt", lookup), + r"C:\Users\demo\notes.txt" + ); + // Unknown names keep their literal spelling, cmd.exe style. + assert_eq!(expand_env_with(r"%UNSET%\x", lookup), r"%UNSET%\x"); + } + + #[test] + fn expand_env_treats_doubled_and_lone_percent_as_literals() { + let lookup = |_: &str| None; + assert_eq!(expand_env_with("100%% done", lookup), "100% done"); + assert_eq!(expand_env_with("50% off", lookup), "50% off"); + assert_eq!(expand_env_with("", lookup), ""); + } +} diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 555d169d..decfb26b 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -11,15 +11,21 @@ Config is a TOML file, read on startup and written atomically on change: Most settings below are managed by the GUI (Settings window, action picker, DPI / SmartShift / lighting panels), but the file stays hand-editable; per-application overlays and custom shortcuts are currently authored there. -OpenLogi reloads it on startup. Older `schema_version = 1` files (separate -`button_bindings` / `gesture_bindings` tables) are migrated to the unified -`bindings` map on first load. +OpenLogi reloads it on startup. Older files migrate on first load: +`schema_version = 1` (separate `button_bindings` / `gesture_bindings` tables) +into the unified `bindings` map, and pre-v3 model-keyed device tables into +route-keyed ones. -Per-device settings are keyed by the HID++ identifier (e.g. `2b042` for an -MX Master 4): +The current schema is `schema_version = 3`. Per-device settings are keyed by +the device's **route identity** — `receiver::slot:` for a device +behind a Bolt/Unifying receiver, `direct:::unit:` for USB / +Bluetooth-direct — so two identical models never share settings. Each device +table also carries an `identity` block (model info and capabilities) that +OpenLogi maintains automatically; leave it alone when hand-editing. -- `bindings` — one entry per rebindable button: either a single action, or a - per-direction table for the gesture button. +- `bindings` — one entry per rebindable button: a single action, a + per-direction table for the gesture button, or a per-sector table for the + MX Master 4's Action Ring pad. - `per_app_bindings` — overlays keyed by application id (bundle id such as `com.microsoft.VSCode` on macOS, `WM_CLASS` on Linux/X11, or a lower-cased executable path on Windows) that take precedence while that app is @@ -42,8 +48,8 @@ the system locale); `thumbwheel_sensitivity` (default `14`); and the presentation settings. The theme and radius overrides are absent by default. ```toml -schema_version = 2 -selected_device = "2b042" +schema_version = 3 +selected_device = "receiver:97b76948a846c55a:slot:2" [app_settings] launch_at_login = true @@ -59,26 +65,45 @@ appearance = "system" # theme_dark = "OpenLogi Dark" # ui_radius = 6 -[devices.2b042] +[devices."receiver:97b76948a846c55a:slot:2"] dpi_presets = [800, 1600, 3200] -[devices.2b042.bindings] +[devices."receiver:97b76948a846c55a:slot:2".bindings] Back = "BrowserBack" Forward = "BrowserForward" # Gesture button: one action per swipe direction; Click = plain press. -[devices.2b042.bindings.GestureButton] +[devices."receiver:97b76948a846c55a:slot:2".bindings.GestureButton] Click = "MissionControl" Up = "MissionControl" Down = "AppExpose" Left = "PreviousDesktop" Right = "NextDesktop" +# Action Ring pad (MX Master 4): one action per ring sector, compass-named +# clockwise from the top. With this table a tap opens the on-screen ring; +# replace the whole table with a single action (ActionRing = "Copy") to make +# a tap fire that action directly instead. +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing] +North = "PlayPause" +NorthEast = "CaptureRegion" +# `Run` opens a URL, file, or program (`||` separates a program's arguments; +# %VAR% environment variables expand). `PasteText` types a snippet at the +# cursor. `Folder` nests a sub-ring (one level; sparse maps fine) that the +# on-screen ring opens in place. All are editable from the ring editor in +# the app. +East = { Folder = { North = { Run = "https://gemini.google.com/" }, South = "Copy" } } +SouthEast = "LockScreen" +South = { Run = 'C:\Windows\notepad.exe||%USERPROFILE%\notes.txt' } +SouthWest = "ShowDesktop" +West = { PasteText = "Reviewed — looks good to me." } +NorthWest = "MissionControl" + # Per-app overlay: Back becomes Undo only while VS Code is frontmost. -[devices.2b042.per_app_bindings."com.microsoft.VSCode"] +[devices."receiver:97b76948a846c55a:slot:2".per_app_bindings."com.microsoft.VSCode"] Back = "Undo" -[devices.2b042.lighting] +[devices."receiver:97b76948a846c55a:slot:2".lighting] enabled = true color = "ff0000" brightness = 80 diff --git a/docs/action-ring-example.toml b/docs/action-ring-example.toml new file mode 100644 index 00000000..a0d3cda1 --- /dev/null +++ b/docs/action-ring-example.toml @@ -0,0 +1,129 @@ +# Action Ring — working example configuration +# +# This is the live ring from the first machine, kept as a starting point. +# Copy the `ActionRing` sections into +# `%USERPROFILE%\.config\openlogi\config.toml` and adapt. +# +# ───────────────────────────────────────────────────────────────────────────── +# BEFORE YOU COPY — replace the device key +# +# receiver:97b76948a846c55a:slot:2 +# +# is the *first machine's* Bolt receiver UID + pairing slot. Yours is different. +# Launch OpenLogi once so it writes its device blocks, then read yours: +# +# Select-String -Path "$env:USERPROFILE\.config\openlogi\config.toml" ` +# -Pattern '^\[devices\.' | ForEach-Object { $_.Line } +# +# Use the key whose identity block says `display_name = "MX Master 4"`, and +# substitute it everywhere below. Edit with the app CLOSED, or it will +# overwrite your changes on its next save. +# ───────────────────────────────────────────────────────────────────────────── +# +# Slots are compass-named clockwise from the top: +# North · NorthEast · East · SouthEast · South · SouthWest · West · NorthWest +# +# Any slot may hold: +# "PlayPause" a built-in action (see the catalog in-app) +# { Run = "…" } URL, file, or program; `||` separates args, +# %VAR% expands +# { PasteText = "…" } typed at the cursor as Unicode +# { CustomShortcut = { … } } a key chord — RECORD THIS IN THE APP +# { Folder = { … } } a nested ring, one level deep +# { Named = { name = "…", any of the above with your own label, +# action = { … } } } shown on the ring instead of the payload + +schema_version = 4 + +# ── Top-level ring ─────────────────────────────────────────────────────────── +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing] +North = "PlayPause" +SouthEast = "LockScreen" +SouthWest = "CaptureRegion" # Win+Shift+S region snip + +# ── East: a folder of AI sites ─────────────────────────────────────────────── +# Firing this slot swaps the on-screen ring to these four; the centre button +# becomes ← to step back out. Empty positions simply don't render. +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing.East.Folder.North] +Run = "https://chatgpt.com/" + +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing.East.Folder.NorthEast] +Run = "https://www.perplexity.ai/" + +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing.East.Folder.East] +Run = "https://gemini.google.com/" + +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing.East.Folder.SouthEast] +Run = "https://copilot.microsoft.com/" + +# ── NorthEast: a folder of prompt snippets ─────────────────────────────────── +# PasteText types the snippet wherever the caret is — no clipboard involvement, +# so whatever you had copied survives. +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing.NorthEast.Folder.North] +PasteText = "Okay, then it's time to start making the four-track documents, all .md files. Include a preview for phase two, phase three, and phase four in each of the documents so I can hand them off and have them continue autonomously." + +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing.NorthEast.Folder.NorthEast] +PasteText = "We're working on a multiphase coding round. We've just completed phase one. Read the previews of the phases, then build phase two as a .md document I can hand back to the coding agent." + +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing.NorthEast.Folder.East] +PasteText = "Ok, please make the phase three document. Here's the report." + +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing.NorthEast.Folder.SouthEast] +PasteText = "Okay, great, phase three is complete. Now please write phase four." + +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing.NorthEast.Folder.South] +PasteText = "Please write a quick summary here in the chat, referencing any important components, backlogged items, and cross-messages between tracks, so I can send it to the master orchestrator." + +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing.NorthEast.Folder.SouthWest] +PasteText = "Let's do a master document I can paste from one agent to the next for an audit, ending with a release on the server. Make sure they all know to get, add, commit, and push." + +# ── South: launch a program ────────────────────────────────────────────────── +# Opens OpenLogi itself. Use `||` for arguments, e.g. +# Run = 'C:\Windows\notepad.exe||%USERPROFILE%\notes.txt' +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing.South] +Run = 'C:\Users\ultra\AppData\Local\Programs\OpenLogi\OpenLogi.exe' + +# ── West / NorthWest: key chords ───────────────────────────────────────────── +# PREFER RECORDING THESE IN THE APP: +# ring editor → slot → "Keyboard Shortcut…" → "Press Keys" → press → release. +# It writes this block for you and gets the codes right, including chords another +# app already owns globally (the recorder reads physical key state, so a hotkey +# owner swallowing the message doesn't matter). +# +# If you must hand-write: `modifiers` is a bitmask — +# 1 = Cmd/Meta 2 = Shift 4 = Ctrl 8 = Alt/Option 16 = Win +# and `key_code` is a macOS kVK virtual-key code (the cross-platform storage +# format; the injector maps it to a Windows VK). 49 = Space, 6 = Z, 0 = A. +# +# Note: chords are injected with a ~120 ms hold, so apps that detect their +# hotkey by polling key state (common) actually observe the press. + +# Ctrl+Space — dictation toggle on the first machine (Voice Node). +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing.West.CustomShortcut] +modifiers = 4 +key_code = 49 +display = "Ctrl+Space" + +# Win+Ctrl+Space +[devices."receiver:97b76948a846c55a:slot:2".bindings.ActionRing.NorthWest.CustomShortcut] +modifiers = 20 +key_code = 49 +display = "Win+Ctrl+Space" + +# ───────────────────────────────────────────────────────────────────────────── +# Other buttons take the same rich actions — not just the ring. +# The gesture button (hold + swipe) and plain buttons (DPI toggle, Middle, +# Back, Forward) all offer Run / Paste Text / Keyboard Shortcut in their +# pickers. Example: the gesture button's five directions. +# ───────────────────────────────────────────────────────────────────────────── +[devices."receiver:97b76948a846c55a:slot:2".bindings.GestureButton] +Up = "MissionControl" +Down = "ShowDesktop" +Left = "PrevTab" +Right = "NextTab" +Click = "AppExpose" + +# The pad is only a ring while its binding is a slot map. Replacing the whole +# table with a single action makes a tap fire that action directly instead: +# [devices."".bindings] +# ActionRing = "Copy" diff --git a/docs/mx-master-4-panel-captures/elan-touchpad-positive-control.txt b/docs/mx-master-4-panel-captures/elan-touchpad-positive-control.txt new file mode 100644 index 00000000..1ec28e84 --- /dev/null +++ b/docs/mx-master-4-panel-captures/elan-touchpad-positive-control.txt @@ -0,0 +1,1015 @@ +raw-input tap live for 120 s — pages 0x0D digitizer, 0x0E haptics, 0xFF00/0xFF43 vendor +device hdev=1005e: \\?\HID#VEN_0488&Col02#5&2b581ffa&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030} +[ 15431ms] VEN_0488&Col02 len=20: 01 03 a3 02 49 03 00 00 00 00 00 00 00 00 00 00 31 31 01 00 +[ 15432ms] VEN_0488&Col02 len=20: 01 03 a3 02 49 03 00 00 00 00 00 00 00 00 00 00 77 31 01 00 +[ 15434ms] VEN_0488&Col02 len=20: 01 03 a3 02 49 03 07 a1 04 43 03 00 00 00 00 00 bd 31 02 00 +[ 15441ms] VEN_0488&Col02 len=20: 01 03 a3 02 49 03 07 a1 04 43 03 00 00 00 00 00 03 32 02 00 +[ 15449ms] VEN_0488&Col02 len=20: 01 03 a3 02 49 03 07 a1 04 43 03 0b 85 03 0e 03 49 32 03 00 +[ 15460ms] VEN_0488&Col02 len=20: 01 03 a3 02 49 03 07 a1 04 43 03 0b 85 03 0e 03 8f 32 03 00 +[ 15463ms] VEN_0488&Col02 len=20: 01 03 a3 02 46 03 07 a1 04 41 03 0b 85 03 0e 03 d5 32 03 00 +[ 15470ms] VEN_0488&Col02 len=20: 01 03 a4 02 3f 03 07 a2 04 3c 03 0b 85 03 0c 03 1b 33 03 00 +[ 15477ms] VEN_0488&Col02 len=20: 01 03 a5 02 31 03 07 a5 04 31 03 0b 85 03 05 03 61 33 03 00 +[ 15485ms] VEN_0488&Col02 len=20: 01 03 a9 02 1c 03 07 a9 04 1f 03 0b 86 03 fa 02 a7 33 03 00 +[ 15492ms] VEN_0488&Col02 len=20: 01 03 ab 02 0e 03 07 aa 04 13 03 0b 87 03 e0 02 ed 33 03 00 +[ 15499ms] VEN_0488&Col02 len=20: 01 03 ad 02 00 03 07 ab 04 09 03 0b 88 03 cc 02 33 34 03 00 +[ 15506ms] VEN_0488&Col02 len=20: 01 03 af 02 ef 02 07 ab 04 fe 02 0b 88 03 c1 02 79 34 03 00 +[ 15513ms] VEN_0488&Col02 len=20: 01 03 b2 02 e2 02 07 ab 04 f1 02 0b 8b 03 b0 02 bf 34 03 00 +[ 15520ms] VEN_0488&Col02 len=20: 01 03 b4 02 d4 02 07 ac 04 e4 02 0b 8c 03 a0 02 05 35 03 00 +[ 15527ms] VEN_0488&Col02 len=20: 01 03 b6 02 c7 02 07 ae 04 d9 02 0b 8c 03 92 02 4b 35 03 00 +[ 15535ms] VEN_0488&Col02 len=20: 01 03 b7 02 b9 02 07 ae 04 cd 02 0b 8e 03 86 02 91 35 03 00 +[ 15541ms] VEN_0488&Col02 len=20: 01 03 b9 02 a9 02 07 ae 04 c1 02 0b 91 03 77 02 d7 35 03 00 +[ 15549ms] VEN_0488&Col02 len=20: 01 03 bb 02 98 02 07 ae 04 b4 02 0b 94 03 67 02 1d 36 03 00 +[ 15557ms] VEN_0488&Col02 len=20: 01 03 bd 02 8b 02 07 ae 04 a5 02 0b 95 03 5a 02 63 36 03 00 +[ 15564ms] VEN_0488&Col02 len=20: 01 03 be 02 7c 02 07 af 04 97 02 0b 98 03 4b 02 a9 36 03 00 +[ 15571ms] VEN_0488&Col02 len=20: 01 03 bf 02 6f 02 07 af 04 8c 02 0b 99 03 3d 02 ef 36 03 00 +[ 15578ms] VEN_0488&Col02 len=20: 01 03 c0 02 5f 02 07 af 04 81 02 0b 9a 03 2f 02 35 37 03 00 +[ 15585ms] VEN_0488&Col02 len=20: 01 03 c1 02 55 02 07 af 04 74 02 0b 9c 03 22 02 7b 37 03 00 +[ 15592ms] VEN_0488&Col02 len=20: 01 03 c2 02 4b 02 07 af 04 67 02 0b 9e 03 14 02 c1 37 03 00 +[ 15599ms] VEN_0488&Col02 len=20: 01 03 c2 02 44 02 07 ae 04 5f 02 0b 9e 03 0c 02 07 38 03 00 +[ 15606ms] VEN_0488&Col02 len=20: 01 03 c2 02 3c 02 07 ae 04 55 02 0b 9f 03 02 02 4d 38 03 00 +[ 15613ms] VEN_0488&Col02 len=20: 01 03 c2 02 34 02 07 ae 04 4c 02 0b a0 03 f9 01 93 38 03 00 +[ 15620ms] VEN_0488&Col02 len=20: 01 03 c1 02 2c 02 07 ae 04 42 02 0b a0 03 ee 01 d9 38 03 00 +[ 15627ms] VEN_0488&Col02 len=20: 01 03 c1 02 23 02 07 ac 04 38 02 0b a1 03 e3 01 1f 39 03 00 +[ 15634ms] VEN_0488&Col02 len=20: 01 03 c1 02 19 02 07 ab 04 2e 02 0b a1 03 d8 01 65 39 03 00 +[ 15641ms] VEN_0488&Col02 len=20: 01 03 c1 02 0e 02 07 ab 04 21 02 0b a1 03 ce 01 ab 39 03 00 +[ 15649ms] VEN_0488&Col02 len=20: 01 03 c1 02 02 02 07 aa 04 16 02 0b a1 03 c3 01 f1 39 03 00 +[ 15655ms] VEN_0488&Col02 len=20: 01 03 c1 02 f6 01 07 a9 04 0c 02 0b a1 03 b8 01 37 3a 03 00 +[ 15662ms] VEN_0488&Col02 len=20: 01 03 c1 02 e8 01 07 a7 04 01 02 0b a1 03 ab 01 7d 3a 03 00 +[ 15669ms] VEN_0488&Col02 len=20: 01 03 c1 02 d7 01 07 a6 04 f4 01 0b a1 03 9c 01 c3 3a 03 00 +[ 15677ms] VEN_0488&Col02 len=20: 01 03 c2 02 c9 01 07 a5 04 e6 01 0b a2 03 8d 01 09 3b 03 00 +[ 15684ms] VEN_0488&Col02 len=20: 01 03 c4 02 bb 01 07 a5 04 da 01 0b a2 03 80 01 4f 3b 03 00 +[ 15692ms] VEN_0488&Col02 len=20: 01 03 c4 02 af 01 07 a4 04 d0 01 0b a2 03 72 01 95 3b 03 00 +[ 15701ms] VEN_0488&Col02 len=20: 01 03 c5 02 a1 01 07 a2 04 c5 01 0b a2 03 63 01 db 3b 03 00 +[ 15706ms] VEN_0488&Col02 len=20: 01 03 c6 02 96 01 07 a1 04 bc 01 0b a2 03 58 01 21 3c 03 00 +[ 15713ms] VEN_0488&Col02 len=20: 01 03 c7 02 8e 01 07 9f 04 b2 01 0b a2 03 4f 01 67 3c 03 00 +[ 15720ms] VEN_0488&Col02 len=20: 01 03 c7 02 84 01 07 9e 04 a8 01 0b a2 03 44 01 ad 3c 03 00 +[ 15727ms] VEN_0488&Col02 len=20: 01 03 c7 02 7a 01 07 9d 04 9e 01 0b a2 03 39 01 f3 3c 03 00 +[ 15734ms] VEN_0488&Col02 len=20: 01 03 c7 02 70 01 07 9a 04 93 01 0b a2 03 2e 01 39 3d 03 00 +[ 15741ms] VEN_0488&Col02 len=20: 01 03 c6 02 68 01 07 98 04 89 01 0b a2 03 24 01 7f 3d 03 00 +[ 15748ms] VEN_0488&Col02 len=20: 01 03 c6 02 61 01 07 96 04 81 01 0b a2 03 1b 01 c5 3d 03 00 +[ 15755ms] VEN_0488&Col02 len=20: 01 03 c5 02 58 01 07 93 04 77 01 0b a2 03 11 01 0b 3e 03 00 +[ 15762ms] VEN_0488&Col02 len=20: 01 03 c4 02 50 01 07 91 04 6b 01 0b a1 03 07 01 51 3e 03 00 +[ 15769ms] VEN_0488&Col02 len=20: 01 03 c2 02 48 01 07 90 04 60 01 0b a1 03 fe 00 97 3e 03 00 +[ 15776ms] VEN_0488&Col02 len=20: 01 03 c1 02 3f 01 07 8e 04 55 01 0b a0 03 f3 00 dd 3e 03 00 +[ 15783ms] VEN_0488&Col02 len=20: 01 03 bf 02 36 01 07 8c 04 4b 01 0b a0 03 e8 00 23 3f 03 00 +[ 15791ms] VEN_0488&Col02 len=20: 01 03 bf 02 2d 01 07 8b 04 42 01 0b a0 03 de 00 69 3f 03 00 +[ 15798ms] VEN_0488&Col02 len=20: 01 03 bf 02 22 01 07 8a 04 36 01 0b a0 03 d4 00 af 3f 03 00 +[ 15805ms] VEN_0488&Col02 len=20: 01 03 bf 02 1a 01 07 88 04 2c 01 0b 9f 03 cc 00 f5 3f 03 00 +[ 15812ms] VEN_0488&Col02 len=20: 01 03 bf 02 13 01 07 88 04 25 01 0b 9f 03 c5 00 3b 40 03 00 +[ 15819ms] VEN_0488&Col02 len=20: 01 03 bf 02 0c 01 07 88 04 1c 01 0b 9f 03 bd 00 81 40 03 00 +[ 15827ms] VEN_0488&Col02 len=20: 01 03 c0 02 04 01 07 89 04 14 01 0b a0 03 b3 00 c7 40 03 00 +[ 15833ms] VEN_0488&Col02 len=20: 01 03 c1 02 fe 00 07 89 04 0e 01 0b a1 03 ab 00 0d 41 03 00 +[ 15841ms] VEN_0488&Col02 len=20: 01 03 c1 02 f5 00 07 8a 04 05 01 0b a2 03 a3 00 53 41 03 00 +[ 15848ms] VEN_0488&Col02 len=20: 01 03 c2 02 ed 00 07 8a 04 fc 00 0b a2 03 9b 00 99 41 03 00 +[ 15855ms] VEN_0488&Col02 len=20: 01 03 c2 02 e7 00 07 8a 04 f5 00 0b a2 03 94 00 df 41 03 00 +[ 15862ms] VEN_0488&Col02 len=20: 01 03 c3 02 e0 00 07 8b 04 eb 00 0b a4 03 8c 00 25 42 03 00 +[ 15870ms] VEN_0488&Col02 len=20: 01 03 c3 02 da 00 07 8c 04 e1 00 0b a6 03 84 00 6b 42 03 00 +[ 15877ms] VEN_0488&Col02 len=20: 01 03 c3 02 d5 00 07 8d 04 d9 00 0b a7 03 7e 00 b1 42 03 00 +[ 15884ms] VEN_0488&Col02 len=20: 01 03 c4 02 d0 00 07 8e 04 d1 00 0b a7 03 77 00 f7 42 03 00 +[ 15892ms] VEN_0488&Col02 len=20: 01 03 c5 02 cb 00 07 90 04 ca 00 0b a8 03 6f 00 3d 43 03 00 +[ 15899ms] VEN_0488&Col02 len=20: 01 03 c7 02 c8 00 07 91 04 c3 00 0b aa 03 6a 00 83 43 03 00 +[ 15906ms] VEN_0488&Col02 len=20: 01 01 c7 02 c8 00 07 92 04 b9 00 0b ad 03 65 00 c9 43 03 00 +[ 15913ms] VEN_0488&Col02 len=20: 01 07 92 04 ba 00 09 ad 03 65 00 00 00 00 00 00 0f 44 02 00 +[ 15921ms] VEN_0488&Col02 len=20: 01 05 92 04 ba 00 00 00 00 00 00 00 00 00 00 00 55 44 01 00 +[ 16684ms] VEN_0488&Col02 len=20: 01 03 df 03 83 00 00 00 00 00 00 00 00 00 00 00 54 62 01 00 +[ 16691ms] VEN_0488&Col02 len=20: 01 03 df 03 83 00 07 f3 02 f0 00 00 00 00 00 00 9a 62 02 00 +[ 16698ms] VEN_0488&Col02 len=20: 01 03 df 03 83 00 07 f3 02 f0 00 00 00 00 00 00 e0 62 02 00 +[ 16706ms] VEN_0488&Col02 len=20: 01 03 df 03 83 00 07 f3 02 f0 00 00 00 00 00 00 26 63 02 00 +[ 16713ms] VEN_0488&Col02 len=20: 01 03 df 03 83 00 07 f3 02 f0 00 0b ce 04 c4 00 6c 63 03 00 +[ 16720ms] VEN_0488&Col02 len=20: 01 03 df 03 83 00 07 f3 02 f0 00 0b ce 04 c4 00 b2 63 03 00 +[ 16727ms] VEN_0488&Col02 len=20: 01 03 df 03 83 00 07 f3 02 f0 00 0b ce 04 c4 00 f8 63 03 00 +[ 16734ms] VEN_0488&Col02 len=20: 01 03 df 03 83 00 07 f3 02 f0 00 0b ce 04 c4 00 3e 64 03 00 +[ 16742ms] VEN_0488&Col02 len=20: 01 03 df 03 83 00 07 f3 02 f0 00 0b ce 04 c4 00 84 64 03 00 +[ 16748ms] VEN_0488&Col02 len=20: 01 03 df 03 84 00 07 f3 02 f1 00 0b ce 04 c4 00 ca 64 03 00 +[ 16756ms] VEN_0488&Col02 len=20: 01 03 df 03 86 00 07 f3 02 f4 00 0b ce 04 c4 00 10 65 03 00 +[ 16762ms] VEN_0488&Col02 len=20: 01 03 e0 03 8a 00 07 f5 02 f9 00 0b cf 04 c6 00 56 65 03 00 +[ 16770ms] VEN_0488&Col02 len=20: 01 03 e1 03 91 00 07 f7 02 01 01 0b d0 04 ca 00 9c 65 03 00 +[ 16777ms] VEN_0488&Col02 len=20: 01 03 e5 03 9d 00 07 fc 02 0e 01 0b d0 04 d0 00 e2 65 03 00 +[ 16784ms] VEN_0488&Col02 len=20: 01 03 e6 03 a6 00 07 fd 02 15 01 0b d2 04 dc 00 28 66 03 00 +[ 16791ms] VEN_0488&Col02 len=20: 01 03 e7 03 af 00 07 fe 02 1c 01 0b d2 04 ea 00 6e 66 03 00 +[ 16798ms] VEN_0488&Col02 len=20: 01 03 e8 03 bb 00 07 ff 02 24 01 0b d2 04 f4 00 b4 66 03 00 +[ 16805ms] VEN_0488&Col02 len=20: 01 03 ea 03 c5 00 07 01 03 2d 01 0b d1 04 fe 00 fa 66 03 00 +[ 16813ms] VEN_0488&Col02 len=20: 01 03 ec 03 ce 00 07 03 03 36 01 0b d1 04 08 01 40 67 03 00 +[ 16820ms] VEN_0488&Col02 len=20: 01 03 ed 03 d7 00 07 04 03 42 01 0b d0 04 12 01 86 67 03 00 +[ 16826ms] VEN_0488&Col02 len=20: 01 03 ed 03 e2 00 07 04 03 4d 01 0b cf 04 1b 01 cc 67 03 00 +[ 16834ms] VEN_0488&Col02 len=20: 01 03 eb 03 eb 00 07 04 03 56 01 0b ce 04 22 01 12 68 03 00 +[ 16840ms] VEN_0488&Col02 len=20: 01 03 ea 03 f9 00 07 04 03 60 01 0b cd 04 2e 01 58 68 03 00 +[ 16847ms] VEN_0488&Col02 len=20: 01 03 e9 03 05 01 07 04 03 6a 01 0b cc 04 3a 01 9e 68 03 00 +[ 16855ms] VEN_0488&Col02 len=20: 01 03 e7 03 11 01 07 03 03 73 01 0b ca 04 46 01 e4 68 03 00 +[ 16862ms] VEN_0488&Col02 len=20: 01 03 e6 03 1a 01 07 02 03 80 01 0b c7 04 51 01 2a 69 03 00 +[ 16869ms] VEN_0488&Col02 len=20: 01 03 e4 03 25 01 07 01 03 8d 01 0b c5 04 5c 01 70 69 03 00 +[ 16876ms] VEN_0488&Col02 len=20: 01 03 e1 03 31 01 07 ff 02 99 01 0b c3 04 65 01 b6 69 03 00 +[ 16883ms] VEN_0488&Col02 len=20: 01 03 de 03 3f 01 07 fd 02 a2 01 0b c1 04 70 01 fc 69 03 00 +[ 16890ms] VEN_0488&Col02 len=20: 01 03 dc 03 4a 01 07 fc 02 ab 01 0b bf 04 7b 01 42 6a 03 00 +[ 16897ms] VEN_0488&Col02 len=20: 01 03 d9 03 56 01 07 fa 02 b4 01 0b bd 04 88 01 88 6a 03 00 +[ 16904ms] VEN_0488&Col02 len=20: 01 03 d6 03 60 01 07 f8 02 c2 01 0b bb 04 93 01 ce 6a 03 00 +[ 16911ms] VEN_0488&Col02 len=20: 01 03 d4 03 69 01 07 f7 02 cd 01 0b b8 04 9d 01 14 6b 03 00 +[ 16918ms] VEN_0488&Col02 len=20: 01 03 d2 03 74 01 07 f5 02 d9 01 0b b7 04 a5 01 5a 6b 03 00 +[ 16925ms] VEN_0488&Col02 len=20: 01 03 d1 03 81 01 07 f3 02 e3 01 0b b5 04 af 01 a0 6b 03 00 +[ 16932ms] VEN_0488&Col02 len=20: 01 03 ce 03 8e 01 07 f2 02 ee 01 0b b4 04 ba 01 e6 6b 03 00 +[ 16939ms] VEN_0488&Col02 len=20: 01 03 cb 03 9a 01 07 ee 02 f9 01 0b b1 04 c7 01 2c 6c 03 00 +[ 16946ms] VEN_0488&Col02 len=20: 01 03 c9 03 a4 01 07 ec 02 06 02 0b b0 04 d3 01 72 6c 03 00 +[ 16953ms] VEN_0488&Col02 len=20: 01 03 c8 03 ad 01 07 e9 02 13 02 0b af 04 dd 01 b8 6c 03 00 +[ 16960ms] VEN_0488&Col02 len=20: 01 03 c6 03 ba 01 07 e8 02 20 02 0b ad 04 e7 01 fe 6c 03 00 +[ 16967ms] VEN_0488&Col02 len=20: 01 03 c4 03 c7 01 07 e4 02 2c 02 0b aa 04 f1 01 44 6d 03 00 +[ 16975ms] VEN_0488&Col02 len=20: 01 03 c2 03 d4 01 07 e1 02 36 02 0b a8 04 fc 01 8a 6d 03 00 +[ 16982ms] VEN_0488&Col02 len=20: 01 03 c0 03 df 01 07 df 02 42 02 0b a6 04 0b 02 d0 6d 03 00 +[ 16989ms] VEN_0488&Col02 len=20: 01 03 be 03 eb 01 07 db 02 51 02 0b a4 04 18 02 16 6e 03 00 +[ 16996ms] VEN_0488&Col02 len=20: 01 03 bc 03 f6 01 07 d8 02 5d 02 0b a2 04 23 02 5c 6e 03 00 +[ 17004ms] VEN_0488&Col02 len=20: 01 03 ba 03 05 02 07 d4 02 69 02 0b a0 04 2c 02 a2 6e 03 00 +[ 17010ms] VEN_0488&Col02 len=20: 01 03 b9 03 11 02 07 d2 02 72 02 0b 9e 04 36 02 e8 6e 03 00 +[ 17018ms] VEN_0488&Col02 len=20: 01 03 b9 03 1c 02 07 d1 02 7a 02 0b 9c 04 41 02 2e 6f 03 00 +[ 17024ms] VEN_0488&Col02 len=20: 01 03 b8 03 25 02 07 d0 02 86 02 0b 9b 04 4c 02 74 6f 03 00 +[ 17032ms] VEN_0488&Col02 len=20: 01 03 b7 03 2d 02 07 ce 02 90 02 0b 99 04 56 02 ba 6f 03 00 +[ 17039ms] VEN_0488&Col02 len=20: 01 03 b5 03 36 02 07 cd 02 9a 02 0b 98 04 5f 02 00 70 03 00 +[ 17046ms] VEN_0488&Col02 len=20: 01 03 b4 03 3f 02 07 cc 02 a3 02 0b 98 04 66 02 46 70 03 00 +[ 17053ms] VEN_0488&Col02 len=20: 01 03 b3 03 49 02 07 ca 02 ab 02 0b 97 04 6d 02 8c 70 03 00 +[ 17060ms] VEN_0488&Col02 len=20: 01 03 b3 03 53 02 07 ca 02 b3 02 0b 95 04 73 02 d2 70 03 00 +[ 17067ms] VEN_0488&Col02 len=20: 01 03 b2 03 5c 02 07 ca 02 ba 02 0b 95 04 7c 02 18 71 03 00 +[ 17075ms] VEN_0488&Col02 len=20: 01 03 b1 03 64 02 07 ca 02 c3 02 0b 94 04 85 02 5e 71 03 00 +[ 17081ms] VEN_0488&Col02 len=20: 01 03 b0 03 6b 02 07 ca 02 cd 02 0b 92 04 8d 02 a4 71 03 00 +[ 17089ms] VEN_0488&Col02 len=20: 01 03 af 03 74 02 07 ca 02 d8 02 0b 90 04 97 02 ea 71 03 00 +[ 17096ms] VEN_0488&Col02 len=20: 01 03 ac 03 7d 02 07 c9 02 e1 02 0b 8d 04 9f 02 30 72 03 00 +[ 17103ms] VEN_0488&Col02 len=20: 01 03 aa 03 85 02 07 c8 02 e9 02 0b 8b 04 a6 02 76 72 03 00 +[ 17110ms] VEN_0488&Col02 len=20: 01 03 a8 03 91 02 07 c6 02 f2 02 0b 8a 04 ae 02 bc 72 03 00 +[ 17117ms] VEN_0488&Col02 len=20: 01 03 a6 03 9b 02 07 c4 02 f9 02 0b 88 04 b5 02 02 73 03 00 +[ 17124ms] VEN_0488&Col02 len=20: 01 03 a5 03 a2 02 07 c3 02 fe 02 0b 86 04 bb 02 48 73 03 00 +[ 17131ms] VEN_0488&Col02 len=20: 01 03 a3 03 ab 02 07 c2 02 08 03 0b 84 04 c3 02 8e 73 03 00 +[ 17139ms] VEN_0488&Col02 len=20: 01 03 a2 03 b2 02 07 c1 02 0f 03 0b 82 04 cb 02 d4 73 03 00 +[ 17146ms] VEN_0488&Col02 len=20: 01 03 a1 03 ba 02 07 c0 02 17 03 0b 81 04 d3 02 1a 74 03 00 +[ 17153ms] VEN_0488&Col02 len=20: 01 03 a0 03 c1 02 07 be 02 1f 03 0b 80 04 d9 02 60 74 03 00 +[ 17160ms] VEN_0488&Col02 len=20: 01 03 9e 03 c9 02 07 bc 02 27 03 0b 7e 04 df 02 a6 74 03 00 +[ 17167ms] VEN_0488&Col02 len=20: 01 03 9d 03 d2 02 07 bb 02 2e 03 0b 7d 04 e5 02 ec 74 03 00 +[ 17174ms] VEN_0488&Col02 len=20: 01 03 9d 03 dc 02 07 ba 02 34 03 0b 7d 04 eb 02 32 75 03 00 +[ 17181ms] VEN_0488&Col02 len=20: 01 03 9c 03 e5 02 07 b9 02 3a 03 0b 7c 04 f1 02 78 75 03 00 +[ 17188ms] VEN_0488&Col02 len=20: 01 03 9a 03 ed 02 07 b8 02 3f 03 0b 7a 04 f7 02 be 75 03 00 +[ 17195ms] VEN_0488&Col02 len=20: 01 03 99 03 f5 02 07 b7 02 45 03 0b 7a 04 fc 02 04 76 03 00 +[ 17202ms] VEN_0488&Col02 len=20: 01 03 98 03 fd 02 07 b6 02 4d 03 0b 7a 04 03 03 4a 76 03 00 +[ 17209ms] VEN_0488&Col02 len=20: 01 03 97 03 07 03 07 b6 02 54 03 0b 7a 04 0a 03 90 76 03 00 +[ 17219ms] VEN_0488&Col02 len=20: 01 03 96 03 13 03 07 b6 02 5d 03 0b 78 04 13 03 d6 76 03 00 +[ 17227ms] VEN_0488&Col02 len=20: 01 03 93 03 1f 03 07 b6 02 65 03 0b 77 04 1b 03 1c 77 03 00 +[ 17231ms] VEN_0488&Col02 len=20: 01 03 90 03 2a 03 07 b6 02 6d 03 0b 76 04 22 03 62 77 03 00 +[ 17238ms] VEN_0488&Col02 len=20: 01 03 90 03 37 03 07 b6 02 77 03 0b 75 04 2b 03 a8 77 03 00 +[ 17245ms] VEN_0488&Col02 len=20: 01 03 8d 03 42 03 07 b6 02 80 03 0b 74 04 34 03 ee 77 03 00 +[ 17252ms] VEN_0488&Col02 len=20: 01 03 8b 03 4e 03 07 b6 02 89 03 0b 73 04 3f 03 34 78 03 00 +[ 17259ms] VEN_0488&Col02 len=20: 01 03 88 03 58 03 07 b7 02 94 03 0b 72 04 4a 03 7a 78 03 00 +[ 17266ms] VEN_0488&Col02 len=20: 01 03 86 03 63 03 07 b7 02 9e 03 0b 71 04 55 03 c0 78 03 00 +[ 17273ms] VEN_0488&Col02 len=20: 01 03 84 03 6e 03 07 b7 02 a7 03 0b 70 04 5d 03 06 79 03 00 +[ 17281ms] VEN_0488&Col02 len=20: 01 01 84 03 6e 03 05 b7 02 a7 03 09 70 04 5d 03 4c 79 03 00 +[ 17732ms] VEN_0488&Col02 len=20: 01 03 5b 04 49 03 00 00 00 00 00 00 00 00 00 00 e9 8a 01 00 +[ 17739ms] VEN_0488&Col02 len=20: 01 03 5b 04 49 03 00 00 00 00 00 00 00 00 00 00 2f 8b 01 00 +[ 17747ms] VEN_0488&Col02 len=20: 01 03 5b 04 49 03 07 70 03 21 03 00 00 00 00 00 75 8b 02 00 +[ 17753ms] VEN_0488&Col02 len=20: 01 03 5b 04 49 03 07 70 03 21 03 0b 9a 02 40 03 bb 8b 03 00 +[ 17760ms] VEN_0488&Col02 len=20: 01 03 5b 04 49 03 07 70 03 21 03 0b 9a 02 40 03 01 8c 03 00 +[ 17768ms] VEN_0488&Col02 len=20: 01 03 5b 04 49 03 07 70 03 21 03 0b 9a 02 40 03 47 8c 03 00 +[ 17775ms] VEN_0488&Col02 len=20: 01 03 5b 04 49 03 07 70 03 21 03 0b 9a 02 40 03 8d 8c 03 00 +[ 17782ms] VEN_0488&Col02 len=20: 01 03 5c 04 47 03 07 71 03 1e 03 0b 9b 02 3d 03 d3 8c 03 00 +[ 17789ms] VEN_0488&Col02 len=20: 01 03 5d 04 43 03 07 74 03 1a 03 0b 9c 02 37 03 19 8d 03 00 +[ 17796ms] VEN_0488&Col02 len=20: 01 03 60 04 3c 03 07 78 03 11 03 0b 9f 02 2b 03 5f 8d 03 00 +[ 17803ms] VEN_0488&Col02 len=20: 01 03 65 04 31 03 07 7f 03 02 03 0b a4 02 1a 03 a5 8d 03 00 +[ 17810ms] VEN_0488&Col02 len=20: 01 03 69 04 28 03 07 84 03 f6 02 0b a9 02 0d 03 eb 8d 03 00 +[ 17817ms] VEN_0488&Col02 len=20: 01 03 69 04 23 03 07 85 03 f2 02 0b ab 02 0a 03 31 8e 03 00 +[ 17824ms] VEN_0488&Col02 len=20: 01 03 6b 04 1e 03 07 86 03 ee 02 0b ad 02 05 03 77 8e 03 00 +[ 17831ms] VEN_0488&Col02 len=20: 01 03 6c 04 19 03 07 87 03 ea 02 0b ae 02 00 03 bd 8e 03 00 +[ 17838ms] VEN_0488&Col02 len=20: 01 03 6d 04 13 03 07 87 03 e6 02 0b ae 02 fd 02 03 8f 03 00 +[ 17845ms] VEN_0488&Col02 len=20: 01 03 70 04 0e 03 07 89 03 e0 02 0b ae 02 f7 02 49 8f 03 00 +[ 17852ms] VEN_0488&Col02 len=20: 01 03 71 04 0a 03 07 8a 03 db 02 0b ae 02 f2 02 8f 8f 03 00 +[ 17859ms] VEN_0488&Col02 len=20: 01 03 70 04 03 03 07 89 03 d4 02 0b ae 02 ec 02 d5 8f 03 00 +[ 17867ms] VEN_0488&Col02 len=20: 01 03 71 04 fe 02 07 89 03 ce 02 0b ae 02 e6 02 1b 90 03 00 +[ 17874ms] VEN_0488&Col02 len=20: 01 03 71 04 f8 02 07 89 03 c8 02 0b ae 02 e0 02 61 90 03 00 +[ 17880ms] VEN_0488&Col02 len=20: 01 03 71 04 f1 02 07 89 03 c1 02 0b ae 02 db 02 a7 90 03 00 +[ 17889ms] VEN_0488&Col02 len=20: 01 03 71 04 ea 02 07 87 03 bb 02 0b ae 02 d4 02 ed 90 03 00 +[ 17895ms] VEN_0488&Col02 len=20: 01 03 71 04 e4 02 07 86 03 b5 02 0b ae 02 ce 02 33 91 03 00 +[ 17902ms] VEN_0488&Col02 len=20: 01 03 71 04 df 02 07 86 03 af 02 0b ae 02 c7 02 79 91 03 00 +[ 17910ms] VEN_0488&Col02 len=20: 01 03 71 04 da 02 07 85 03 a8 02 0b af 02 bf 02 bf 91 03 00 +[ 17916ms] VEN_0488&Col02 len=20: 01 03 71 04 d4 02 07 85 03 a2 02 0b af 02 b8 02 05 92 03 00 +[ 17923ms] VEN_0488&Col02 len=20: 01 03 71 04 ce 02 07 85 03 9d 02 0b af 02 b3 02 4b 92 03 00 +[ 17931ms] VEN_0488&Col02 len=20: 01 03 71 04 c8 02 07 85 03 97 02 0b b0 02 ad 02 91 92 03 00 +[ 17937ms] VEN_0488&Col02 len=20: 01 03 71 04 c3 02 07 85 03 91 02 0b b0 02 a8 02 d7 92 03 00 +[ 17945ms] VEN_0488&Col02 len=20: 01 03 70 04 bc 02 07 85 03 8b 02 0b b0 02 a1 02 1d 93 03 00 +[ 17951ms] VEN_0488&Col02 len=20: 01 03 70 04 b6 02 07 85 03 85 02 0b b0 02 9b 02 63 93 03 00 +[ 17959ms] VEN_0488&Col02 len=20: 01 03 70 04 b2 02 07 85 03 81 02 0b b0 02 96 02 a9 93 03 00 +[ 17966ms] VEN_0488&Col02 len=20: 01 03 70 04 ac 02 07 85 03 7b 02 0b b0 02 90 02 ef 93 03 00 +[ 17972ms] VEN_0488&Col02 len=20: 01 03 70 04 a6 02 07 85 03 77 02 0b b0 02 8c 02 35 94 03 00 +[ 17979ms] VEN_0488&Col02 len=20: 01 03 70 04 a1 02 07 85 03 72 02 0b b0 02 86 02 7b 94 03 00 +[ 17987ms] VEN_0488&Col02 len=20: 01 03 70 04 9c 02 07 85 03 6d 02 0b b0 02 80 02 c1 94 03 00 +[ 17994ms] VEN_0488&Col02 len=20: 01 03 6f 04 97 02 07 85 03 67 02 0b b1 02 7b 02 07 95 03 00 +[ 18000ms] VEN_0488&Col02 len=20: 01 03 6e 04 93 02 07 85 03 63 02 0b b1 02 77 02 4d 95 03 00 +[ 18008ms] VEN_0488&Col02 len=20: 01 03 6e 04 8f 02 07 84 03 60 02 0b b1 02 74 02 93 95 03 00 +[ 18015ms] VEN_0488&Col02 len=20: 01 03 6e 04 8b 02 07 84 03 5c 02 0b b0 02 70 02 d9 95 03 00 +[ 18022ms] VEN_0488&Col02 len=20: 01 03 6e 04 86 02 07 83 03 57 02 0b af 02 6c 02 1f 96 03 00 +[ 18029ms] VEN_0488&Col02 len=20: 01 03 6d 04 82 02 07 82 03 52 02 0b af 02 67 02 65 96 03 00 +[ 18036ms] VEN_0488&Col02 len=20: 01 03 6c 04 7f 02 07 82 03 4d 02 0b ae 02 63 02 ab 96 03 00 +[ 18043ms] VEN_0488&Col02 len=20: 01 03 6b 04 7c 02 07 82 03 49 02 0b ad 02 60 02 f1 96 03 00 +[ 18050ms] VEN_0488&Col02 len=20: 01 03 6b 04 77 02 07 81 03 44 02 0b aa 02 5b 02 37 97 03 00 +[ 18057ms] VEN_0488&Col02 len=20: 01 03 69 04 72 02 07 80 03 40 02 0b a9 02 56 02 7d 97 03 00 +[ 18064ms] VEN_0488&Col02 len=20: 01 03 69 04 6d 02 07 7f 03 3c 02 0b a8 02 51 02 c3 97 03 00 +[ 18071ms] VEN_0488&Col02 len=20: 01 03 69 04 6a 02 07 7d 03 37 02 0b a8 02 4c 02 09 98 03 00 +[ 18079ms] VEN_0488&Col02 len=20: 01 03 68 04 65 02 07 7d 03 33 02 0b a7 02 47 02 4f 98 03 00 +[ 18086ms] VEN_0488&Col02 len=20: 01 03 67 04 61 02 07 7c 03 2f 02 0b a6 02 42 02 95 98 03 00 +[ 18093ms] VEN_0488&Col02 len=20: 01 03 67 04 5d 02 07 7c 03 2b 02 0b a6 02 3e 02 db 98 03 00 +[ 18100ms] VEN_0488&Col02 len=20: 01 03 66 04 58 02 07 7b 03 25 02 0b a6 02 38 02 21 99 03 00 +[ 18107ms] VEN_0488&Col02 len=20: 01 03 66 04 54 02 07 7a 03 20 02 0b a6 02 34 02 67 99 03 00 +[ 18114ms] VEN_0488&Col02 len=20: 01 03 66 04 50 02 07 7a 03 1c 02 0b a6 02 30 02 ad 99 03 00 +[ 18121ms] VEN_0488&Col02 len=20: 01 03 65 04 4b 02 07 79 03 17 02 0b a6 02 2c 02 f3 99 03 00 +[ 18128ms] VEN_0488&Col02 len=20: 01 03 65 04 46 02 07 79 03 12 02 0b a6 02 28 02 39 9a 03 00 +[ 18135ms] VEN_0488&Col02 len=20: 01 03 65 04 42 02 07 79 03 0c 02 0b a6 02 24 02 7f 9a 03 00 +[ 18143ms] VEN_0488&Col02 len=20: 01 03 65 04 3a 02 07 78 03 05 02 0b a6 02 1f 02 c5 9a 03 00 +[ 18149ms] VEN_0488&Col02 len=20: 01 03 65 04 34 02 07 77 03 ff 01 0b a6 02 1a 02 0b 9b 03 00 +[ 18156ms] VEN_0488&Col02 len=20: 01 03 66 04 2e 02 07 77 03 f8 01 0b a6 02 13 02 51 9b 03 00 +[ 18163ms] VEN_0488&Col02 len=20: 01 03 66 04 28 02 07 77 03 f1 01 0b a6 02 0d 02 97 9b 03 00 +[ 18170ms] VEN_0488&Col02 len=20: 01 03 66 04 21 02 07 77 03 eb 01 0b a6 02 07 02 dd 9b 03 00 +[ 18177ms] VEN_0488&Col02 len=20: 01 03 66 04 1a 02 07 78 03 e4 01 0b a6 02 01 02 23 9c 03 00 +[ 18184ms] VEN_0488&Col02 len=20: 01 03 65 04 14 02 07 78 03 dd 01 0b a7 02 f9 01 69 9c 03 00 +[ 18191ms] VEN_0488&Col02 len=20: 01 03 64 04 0e 02 07 77 03 d8 01 0b a8 02 f3 01 af 9c 03 00 +[ 18199ms] VEN_0488&Col02 len=20: 01 03 64 04 09 02 07 76 03 d3 01 0b a9 02 ef 01 f5 9c 03 00 +[ 18206ms] VEN_0488&Col02 len=20: 01 03 64 04 03 02 07 75 03 cc 01 0b a9 02 e9 01 3b 9d 03 00 +[ 18213ms] VEN_0488&Col02 len=20: 01 03 64 04 fc 01 07 74 03 c5 01 0b a9 02 e3 01 81 9d 03 00 +[ 18219ms] VEN_0488&Col02 len=20: 01 03 64 04 f5 01 07 74 03 bc 01 0b a9 02 dd 01 c7 9d 03 00 +[ 18227ms] VEN_0488&Col02 len=20: 01 03 65 04 ee 01 07 74 03 b5 01 0b a9 02 d7 01 0d 9e 03 00 +[ 18234ms] VEN_0488&Col02 len=20: 01 03 65 04 e5 01 07 74 03 ac 01 0b a9 02 cf 01 53 9e 03 00 +[ 18241ms] VEN_0488&Col02 len=20: 01 03 64 04 de 01 07 74 03 a6 01 0b a8 02 c9 01 99 9e 03 00 +[ 18248ms] VEN_0488&Col02 len=20: 01 03 63 04 d7 01 07 74 03 9d 01 0b a8 02 c0 01 df 9e 03 00 +[ 18255ms] VEN_0488&Col02 len=20: 01 03 63 04 d0 01 07 74 03 96 01 0b a8 02 b9 01 25 9f 03 00 +[ 18262ms] VEN_0488&Col02 len=20: 01 03 63 04 c9 01 07 74 03 8e 01 0b a8 02 b2 01 6b 9f 03 00 +[ 18269ms] VEN_0488&Col02 len=20: 01 03 63 04 c2 01 07 72 03 86 01 0b a8 02 aa 01 b1 9f 03 00 +[ 18276ms] VEN_0488&Col02 len=20: 01 03 63 04 bb 01 07 71 03 7e 01 0b a8 02 a4 01 f7 9f 03 00 +[ 18283ms] VEN_0488&Col02 len=20: 01 03 63 04 b4 01 07 71 03 75 01 0b a8 02 9e 01 3d a0 03 00 +[ 18290ms] VEN_0488&Col02 len=20: 01 03 63 04 ac 01 07 72 03 6d 01 0b a8 02 99 01 83 a0 03 00 +[ 18297ms] VEN_0488&Col02 len=20: 01 03 63 04 a5 01 07 73 03 66 01 0b a8 02 93 01 c9 a0 03 00 +[ 18304ms] VEN_0488&Col02 len=20: 01 03 63 04 a0 01 07 73 03 5f 01 0b a8 02 8b 01 0f a1 03 00 +[ 18312ms] VEN_0488&Col02 len=20: 01 03 63 04 98 01 07 73 03 58 01 0b a8 02 84 01 55 a1 03 00 +[ 18319ms] VEN_0488&Col02 len=20: 01 03 63 04 91 01 07 73 03 51 01 0b a8 02 7c 01 9b a1 03 00 +[ 18327ms] VEN_0488&Col02 len=20: 01 03 63 04 8c 01 07 73 03 4b 01 0b a8 02 76 01 e1 a1 03 00 +[ 18333ms] VEN_0488&Col02 len=20: 01 03 62 04 86 01 07 71 03 44 01 0b a9 02 70 01 27 a2 03 00 +[ 18341ms] VEN_0488&Col02 len=20: 01 03 62 04 80 01 07 70 03 3d 01 0b aa 02 69 01 6d a2 03 00 +[ 18348ms] VEN_0488&Col02 len=20: 01 03 62 04 7a 01 07 70 03 37 01 0b aa 02 63 01 b3 a2 03 00 +[ 18355ms] VEN_0488&Col02 len=20: 01 03 63 04 74 01 07 71 03 30 01 0b aa 02 5e 01 f9 a2 03 00 +[ 18362ms] VEN_0488&Col02 len=20: 01 03 63 04 6e 01 07 72 03 2a 01 0b aa 02 59 01 3f a3 03 00 +[ 18369ms] VEN_0488&Col02 len=20: 01 03 63 04 68 01 07 72 03 24 01 0b aa 02 55 01 85 a3 03 00 +[ 18377ms] VEN_0488&Col02 len=20: 01 03 64 04 63 01 07 73 03 1e 01 0b aa 02 4e 01 cb a3 03 00 +[ 18384ms] VEN_0488&Col02 len=20: 01 03 64 04 5c 01 07 73 03 18 01 0b aa 02 48 01 11 a4 03 00 +[ 18391ms] VEN_0488&Col02 len=20: 01 03 63 04 56 01 07 73 03 12 01 0b aa 02 42 01 57 a4 03 00 +[ 18398ms] VEN_0488&Col02 len=20: 01 03 63 04 50 01 07 72 03 0d 01 0b aa 02 3b 01 9d a4 03 00 +[ 18406ms] VEN_0488&Col02 len=20: 01 03 63 04 4a 01 07 71 03 07 01 0b aa 02 34 01 e3 a4 03 00 +[ 18412ms] VEN_0488&Col02 len=20: 01 03 63 04 44 01 07 71 03 01 01 0b aa 02 2e 01 29 a5 03 00 +[ 18420ms] VEN_0488&Col02 len=20: 01 03 63 04 3e 01 07 71 03 fb 00 0b aa 02 28 01 6f a5 03 00 +[ 18427ms] VEN_0488&Col02 len=20: 01 03 63 04 38 01 07 71 03 f5 00 0b aa 02 23 01 b5 a5 03 00 +[ 18434ms] VEN_0488&Col02 len=20: 01 03 63 04 32 01 07 71 03 ef 00 0b aa 02 1d 01 fb a5 03 00 +[ 18442ms] VEN_0488&Col02 len=20: 01 03 63 04 2c 01 07 71 03 ea 00 0b aa 02 19 01 41 a6 03 00 +[ 18448ms] VEN_0488&Col02 len=20: 01 03 63 04 27 01 07 72 03 e5 00 0b aa 02 15 01 87 a6 03 00 +[ 18456ms] VEN_0488&Col02 len=20: 01 03 63 04 22 01 07 72 03 df 00 0b aa 02 10 01 cd a6 03 00 +[ 18463ms] VEN_0488&Col02 len=20: 01 03 62 04 1b 01 07 73 03 da 00 0b aa 02 09 01 13 a7 03 00 +[ 18470ms] VEN_0488&Col02 len=20: 01 03 62 04 16 01 07 73 03 d6 00 0b aa 02 04 01 59 a7 03 00 +[ 18477ms] VEN_0488&Col02 len=20: 01 03 62 04 12 01 07 73 03 d1 00 0b aa 02 00 01 9f a7 03 00 +[ 18484ms] VEN_0488&Col02 len=20: 01 03 62 04 0c 01 07 73 03 cc 00 0b aa 02 f9 00 e5 a7 03 00 +[ 18492ms] VEN_0488&Col02 len=20: 01 03 61 04 07 01 07 72 03 c7 00 0b aa 02 f4 00 2b a8 03 00 +[ 18499ms] VEN_0488&Col02 len=20: 01 03 61 04 03 01 07 72 03 c3 00 0b aa 02 ef 00 71 a8 03 00 +[ 18506ms] VEN_0488&Col02 len=20: 01 03 61 04 fc 00 07 72 03 bf 00 0b aa 02 eb 00 b7 a8 03 00 +[ 18513ms] VEN_0488&Col02 len=20: 01 03 61 04 f7 00 07 72 03 ba 00 0b ab 02 e6 00 fd a8 03 00 +[ 18520ms] VEN_0488&Col02 len=20: 01 03 61 04 f3 00 07 72 03 b7 00 0b ab 02 e2 00 43 a9 03 00 +[ 18528ms] VEN_0488&Col02 len=20: 01 03 61 04 ee 00 07 72 03 b2 00 0b ab 02 dd 00 89 a9 03 00 +[ 18535ms] VEN_0488&Col02 len=20: 01 03 62 04 e9 00 07 72 03 ae 00 0b ab 02 da 00 cf a9 03 00 +[ 18542ms] VEN_0488&Col02 len=20: 01 03 62 04 e4 00 07 72 03 ab 00 0b ab 02 d7 00 15 aa 03 00 +[ 18549ms] VEN_0488&Col02 len=20: 01 03 61 04 e0 00 07 72 03 a6 00 0b ab 02 d4 00 5b aa 03 00 +[ 18557ms] VEN_0488&Col02 len=20: 01 03 61 04 db 00 07 73 03 a1 00 0b ab 02 d0 00 a1 aa 03 00 +[ 18564ms] VEN_0488&Col02 len=20: 01 03 61 04 d6 00 07 73 03 9d 00 0b ab 02 cc 00 e7 aa 03 00 +[ 18571ms] VEN_0488&Col02 len=20: 01 03 61 04 d1 00 07 74 03 98 00 0b ab 02 c7 00 2d ab 03 00 +[ 18578ms] VEN_0488&Col02 len=20: 01 03 60 04 cb 00 07 74 03 92 00 0b ab 02 c2 00 73 ab 03 00 +[ 18585ms] VEN_0488&Col02 len=20: 01 03 60 04 c7 00 07 74 03 8e 00 0b ab 02 bd 00 b9 ab 03 00 +[ 18592ms] VEN_0488&Col02 len=20: 01 03 60 04 c0 00 07 73 03 89 00 0b ab 02 b8 00 ff ab 03 00 +[ 18600ms] VEN_0488&Col02 len=20: 01 03 60 04 bb 00 07 72 03 83 00 0b ab 02 b1 00 45 ac 03 00 +[ 18607ms] VEN_0488&Col02 len=20: 01 03 60 04 b6 00 07 72 03 7e 00 0b ab 02 ac 00 8b ac 03 00 +[ 18614ms] VEN_0488&Col02 len=20: 01 03 61 04 ae 00 07 72 03 76 00 0b ab 02 a6 00 d1 ac 03 00 +[ 18622ms] VEN_0488&Col02 len=20: 01 03 62 04 a7 00 07 73 03 6f 00 0b ab 02 a1 00 17 ad 03 00 +[ 18629ms] VEN_0488&Col02 len=20: 01 03 62 04 a1 00 07 74 03 69 00 0b ab 02 9e 00 5d ad 03 00 +[ 18636ms] VEN_0488&Col02 len=20: 01 03 61 04 98 00 07 75 03 64 00 0b ab 02 9d 00 a3 ad 03 00 +[ 18643ms] VEN_0488&Col02 len=20: 01 01 61 04 98 00 05 75 03 64 00 09 ab 02 9d 00 e9 ad 03 00 +[ 18826ms] VEN_0488&Col02 len=20: 01 03 97 04 85 00 00 00 00 00 00 00 00 00 00 00 51 b5 01 00 +[ 18833ms] VEN_0488&Col02 len=20: 01 03 97 04 85 00 00 00 00 00 00 00 00 00 00 00 97 b5 01 00 +[ 18841ms] VEN_0488&Col02 len=20: 01 03 97 04 85 00 07 b0 03 41 00 00 00 00 00 00 dd b5 02 00 +[ 18848ms] VEN_0488&Col02 len=20: 01 03 97 04 85 00 07 b0 03 41 00 00 00 00 00 00 23 b6 02 00 +[ 18855ms] VEN_0488&Col02 len=20: 01 03 97 04 85 00 07 b0 03 41 00 0b d3 02 b2 00 69 b6 03 00 +[ 18862ms] VEN_0488&Col02 len=20: 01 03 97 04 85 00 07 b0 03 41 00 0b d3 02 b2 00 af b6 03 00 +[ 18870ms] VEN_0488&Col02 len=20: 01 03 97 04 85 00 07 b0 03 41 00 0b d3 02 b2 00 f5 b6 03 00 +[ 18877ms] VEN_0488&Col02 len=20: 01 03 97 04 85 00 07 b0 03 41 00 0b d3 02 b2 00 3b b7 03 00 +[ 18884ms] VEN_0488&Col02 len=20: 01 03 98 04 87 00 07 b1 03 43 00 0b d3 02 b2 00 81 b7 03 00 +[ 18891ms] VEN_0488&Col02 len=20: 01 03 99 04 8a 00 07 b2 03 46 00 0b d3 02 b3 00 c7 b7 03 00 +[ 18898ms] VEN_0488&Col02 len=20: 01 03 9b 04 8f 00 07 b4 03 4c 00 0b d3 02 b6 00 0d b8 03 00 +[ 18905ms] VEN_0488&Col02 len=20: 01 03 9f 04 9b 00 07 b8 03 57 00 0b d4 02 bc 00 53 b8 03 00 +[ 18912ms] VEN_0488&Col02 len=20: 01 03 a2 04 a8 00 07 bb 03 64 00 0b d5 02 c7 00 99 b8 03 00 +[ 18919ms] VEN_0488&Col02 len=20: 01 03 a4 04 b1 00 07 bd 03 6d 00 0b d8 02 d8 00 df b8 03 00 +[ 18926ms] VEN_0488&Col02 len=20: 01 03 a6 04 bc 00 07 bf 03 79 00 0b da 02 e1 00 25 b9 03 00 +[ 18934ms] VEN_0488&Col02 len=20: 01 03 a9 04 c7 00 07 c2 03 84 00 0b dc 02 ea 00 6b b9 03 00 +[ 18941ms] VEN_0488&Col02 len=20: 01 03 aa 04 d0 00 07 c3 03 8d 00 0b dd 02 f4 00 b1 b9 03 00 +[ 18948ms] VEN_0488&Col02 len=20: 01 03 ac 04 d8 00 07 c5 03 96 00 0b df 02 ff 00 f7 b9 03 00 +[ 18954ms] VEN_0488&Col02 len=20: 01 03 ae 04 e1 00 07 c6 03 9f 00 0b e1 02 0b 01 3d ba 03 00 +[ 18962ms] VEN_0488&Col02 len=20: 01 03 af 04 ef 00 07 c8 03 ac 00 0b e2 02 16 01 83 ba 03 00 +[ 18969ms] VEN_0488&Col02 len=20: 01 03 b0 04 fe 00 07 ca 03 bb 00 0b e3 02 23 01 c9 ba 03 00 +[ 18976ms] VEN_0488&Col02 len=20: 01 03 b0 04 0b 01 07 ca 03 c8 00 0b e3 02 2e 01 0f bb 03 00 +[ 18983ms] VEN_0488&Col02 len=20: 01 03 b0 04 18 01 07 c9 03 d5 00 0b e4 02 3d 01 55 bb 03 00 +[ 18991ms] VEN_0488&Col02 len=20: 01 03 b0 04 24 01 07 c9 03 e2 00 0b e4 02 4c 01 9b bb 03 00 +[ 18998ms] VEN_0488&Col02 len=20: 01 03 b0 04 30 01 07 c9 03 f0 00 0b e3 02 5b 01 e1 bb 03 00 +[ 19005ms] VEN_0488&Col02 len=20: 01 03 ad 04 41 01 07 c8 03 01 01 0b e1 02 68 01 27 bc 03 00 +[ 19012ms] VEN_0488&Col02 len=20: 01 03 ac 04 4f 01 07 c6 03 0f 01 0b df 02 75 01 6d bc 03 00 +[ 19019ms] VEN_0488&Col02 len=20: 01 03 ab 04 5b 01 07 c4 03 1a 01 0b dd 02 82 01 b3 bc 03 00 +[ 19026ms] VEN_0488&Col02 len=20: 01 03 a9 04 67 01 07 c3 03 27 01 0b da 02 92 01 f9 bc 03 00 +[ 19033ms] VEN_0488&Col02 len=20: 01 03 a7 04 74 01 07 c1 03 35 01 0b d8 02 a1 01 3f bd 03 00 +[ 19040ms] VEN_0488&Col02 len=20: 01 03 a4 04 82 01 07 bf 03 45 01 0b d5 02 ae 01 85 bd 03 00 +[ 19047ms] VEN_0488&Col02 len=20: 01 03 a1 04 91 01 07 bc 03 52 01 0b d2 02 ba 01 cb bd 03 00 +[ 19054ms] VEN_0488&Col02 len=20: 01 03 9f 04 9d 01 07 ba 03 5e 01 0b d0 02 c7 01 11 be 03 00 +[ 19061ms] VEN_0488&Col02 len=20: 01 03 9c 04 a9 01 07 b8 03 6b 01 0b ce 02 d8 01 57 be 03 00 +[ 19068ms] VEN_0488&Col02 len=20: 01 03 98 04 b4 01 07 b5 03 79 01 0b cb 02 e4 01 9d be 03 00 +[ 19075ms] VEN_0488&Col02 len=20: 01 03 95 04 bf 01 07 b3 03 86 01 0b c9 02 ef 01 e3 be 03 00 +[ 19082ms] VEN_0488&Col02 len=20: 01 03 92 04 cd 01 07 b0 03 95 01 0b c6 02 fc 01 29 bf 03 00 +[ 19090ms] VEN_0488&Col02 len=20: 01 03 8e 04 d9 01 07 ad 03 a1 01 0b c2 02 0b 02 6f bf 03 00 +[ 19097ms] VEN_0488&Col02 len=20: 01 03 8a 04 e3 01 07 ab 03 ac 01 0b bf 02 19 02 b5 bf 03 00 +[ 19104ms] VEN_0488&Col02 len=20: 01 03 88 04 ea 01 07 a9 03 b7 01 0b bd 02 25 02 fb bf 03 00 +[ 19111ms] VEN_0488&Col02 len=20: 01 03 85 04 f4 01 07 a5 03 c4 01 0b bb 02 2f 02 41 c0 03 00 +[ 19118ms] VEN_0488&Col02 len=20: 01 03 82 04 00 02 07 a2 03 d2 01 0b b8 02 3a 02 87 c0 03 00 +[ 19125ms] VEN_0488&Col02 len=20: 01 03 80 04 0e 02 07 a0 03 dd 01 0b b4 02 49 02 cd c0 03 00 +[ 19132ms] VEN_0488&Col02 len=20: 01 03 7d 04 19 02 07 9d 03 e9 01 0b b1 02 57 02 13 c1 03 00 +[ 19139ms] VEN_0488&Col02 len=20: 01 03 7a 04 23 02 07 9a 03 f4 01 0b af 02 63 02 59 c1 03 00 +[ 19146ms] VEN_0488&Col02 len=20: 01 03 78 04 2a 02 07 98 03 ff 01 0b ad 02 6d 02 9f c1 03 00 +[ 19153ms] VEN_0488&Col02 len=20: 01 03 76 04 33 02 07 96 03 0c 02 0b ab 02 77 02 e5 c1 03 00 +[ 19160ms] VEN_0488&Col02 len=20: 01 03 75 04 3c 02 07 93 03 17 02 0b a8 02 80 02 2b c2 03 00 +[ 19167ms] VEN_0488&Col02 len=20: 01 03 73 04 46 02 07 90 03 21 02 0b a5 02 8a 02 71 c2 03 00 +[ 19174ms] VEN_0488&Col02 len=20: 01 03 71 04 50 02 07 8e 03 2a 02 0b a3 02 96 02 b7 c2 03 00 +[ 19181ms] VEN_0488&Col02 len=20: 01 03 70 04 58 02 07 8c 03 31 02 0b a2 02 a0 02 fd c2 03 00 +[ 19189ms] VEN_0488&Col02 len=20: 01 03 6f 04 61 02 07 8c 03 3b 02 0b a1 02 aa 02 43 c3 03 00 +[ 19196ms] VEN_0488&Col02 len=20: 01 03 6e 04 69 02 07 8a 03 47 02 0b 9f 02 b3 02 89 c3 03 00 +[ 19203ms] VEN_0488&Col02 len=20: 01 03 6d 04 70 02 07 88 03 53 02 0b 9e 02 bb 02 cf c3 03 00 +[ 19210ms] VEN_0488&Col02 len=20: 01 03 6b 04 7b 02 07 86 03 60 02 0b 9e 02 c8 02 15 c4 03 00 +[ 19217ms] VEN_0488&Col02 len=20: 01 03 69 04 85 02 07 84 03 6c 02 0b 9d 02 d5 02 5b c4 03 00 +[ 19224ms] VEN_0488&Col02 len=20: 01 03 67 04 90 02 07 82 03 77 02 0b 9b 02 e3 02 a1 c4 03 00 +[ 19231ms] VEN_0488&Col02 len=20: 01 03 66 04 9b 02 07 80 03 86 02 0b 99 02 f0 02 e7 c4 03 00 +[ 19238ms] VEN_0488&Col02 len=20: 01 03 64 04 a5 02 07 7d 03 94 02 0b 97 02 fb 02 2d c5 03 00 +[ 19245ms] VEN_0488&Col02 len=20: 01 03 62 04 b0 02 07 7a 03 a4 02 0b 96 02 07 03 73 c5 03 00 +[ 19252ms] VEN_0488&Col02 len=20: 01 03 61 04 ba 02 07 77 03 b2 02 0b 95 02 13 03 b9 c5 03 00 +[ 19259ms] VEN_0488&Col02 len=20: 01 03 5f 04 c5 02 07 75 03 c1 02 0b 93 02 1f 03 ff c5 03 00 +[ 19266ms] VEN_0488&Col02 len=20: 01 03 5f 04 d0 02 07 73 03 d0 02 0b 92 02 2a 03 45 c6 03 00 +[ 19273ms] VEN_0488&Col02 len=20: 01 03 5f 04 dc 02 07 71 03 e3 02 0b 92 02 34 03 8b c6 03 00 +[ 19280ms] VEN_0488&Col02 len=20: 01 03 5e 04 e7 02 07 70 03 f4 02 0b 93 02 3f 03 d1 c6 03 00 +[ 19288ms] VEN_0488&Col02 len=20: 01 03 5e 04 f4 02 07 70 03 06 03 0b 95 02 49 03 17 c7 03 00 +[ 19294ms] VEN_0488&Col02 len=20: 01 01 5e 04 f4 02 05 70 03 06 03 09 95 02 49 03 5d c7 03 00 +[ 19563ms] VEN_0488&Col02 len=20: 01 03 28 04 d2 01 00 00 00 00 00 00 00 00 00 00 ce d1 01 00 +[ 19570ms] VEN_0488&Col02 len=20: 01 03 28 04 d2 01 00 00 00 00 00 00 00 00 00 00 14 d2 01 00 +[ 19577ms] VEN_0488&Col02 len=20: 01 03 28 04 d2 01 00 00 00 00 00 00 00 00 00 00 5a d2 01 00 +[ 19584ms] VEN_0488&Col02 len=20: 01 03 28 04 d2 01 00 00 00 00 00 00 00 00 00 00 a0 d2 01 00 +[ 19591ms] VEN_0488&Col02 len=20: 01 03 26 04 d3 01 00 00 00 00 00 00 00 00 00 00 e6 d2 01 00 +[ 19599ms] VEN_0488&Col02 len=20: 01 03 1d 04 d6 01 00 00 00 00 00 00 00 00 00 00 2c d3 01 00 +[ 19606ms] VEN_0488&Col02 len=20: 01 03 08 04 db 01 00 00 00 00 00 00 00 00 00 00 72 d3 01 00 +[ 19613ms] VEN_0488&Col02 len=20: 01 03 fb 03 de 01 00 00 00 00 00 00 00 00 00 00 b8 d3 01 00 +[ 19620ms] VEN_0488&Col02 len=20: 01 03 ed 03 e0 01 00 00 00 00 00 00 00 00 00 00 fe d3 01 00 +[ 19627ms] VEN_0488&Col02 len=20: 01 03 e4 03 e2 01 00 00 00 00 00 00 00 00 00 00 44 d4 01 00 +[ 19634ms] VEN_0488&Col02 len=20: 01 03 d7 03 e4 01 00 00 00 00 00 00 00 00 00 00 8a d4 01 00 +[ 19641ms] VEN_0488&Col02 len=20: 01 03 c7 03 e5 01 00 00 00 00 00 00 00 00 00 00 d0 d4 01 00 +[ 19648ms] VEN_0488&Col02 len=20: 01 03 bc 03 e7 01 00 00 00 00 00 00 00 00 00 00 16 d5 01 00 +[ 19656ms] VEN_0488&Col02 len=20: 01 03 b1 03 e9 01 00 00 00 00 00 00 00 00 00 00 5c d5 01 00 +[ 19663ms] VEN_0488&Col02 len=20: 01 03 a6 03 eb 01 00 00 00 00 00 00 00 00 00 00 a2 d5 01 00 +[ 19670ms] VEN_0488&Col02 len=20: 01 03 97 03 ec 01 00 00 00 00 00 00 00 00 00 00 e8 d5 01 00 +[ 19677ms] VEN_0488&Col02 len=20: 01 03 88 03 ed 01 00 00 00 00 00 00 00 00 00 00 2e d6 01 00 +[ 19684ms] VEN_0488&Col02 len=20: 01 03 7c 03 ef 01 00 00 00 00 00 00 00 00 00 00 74 d6 01 00 +[ 19691ms] VEN_0488&Col02 len=20: 01 03 6f 03 f1 01 00 00 00 00 00 00 00 00 00 00 ba d6 01 00 +[ 19698ms] VEN_0488&Col02 len=20: 01 03 61 03 f2 01 00 00 00 00 00 00 00 00 00 00 00 d7 01 00 +[ 19705ms] VEN_0488&Col02 len=20: 01 03 51 03 f3 01 00 00 00 00 00 00 00 00 00 00 46 d7 01 00 +[ 19712ms] VEN_0488&Col02 len=20: 01 03 42 03 f3 01 00 00 00 00 00 00 00 00 00 00 8c d7 01 00 +[ 19719ms] VEN_0488&Col02 len=20: 01 03 35 03 f4 01 00 00 00 00 00 00 00 00 00 00 d2 d7 01 00 +[ 19726ms] VEN_0488&Col02 len=20: 01 03 26 03 f5 01 00 00 00 00 00 00 00 00 00 00 18 d8 01 00 +[ 19733ms] VEN_0488&Col02 len=20: 01 03 16 03 f6 01 00 00 00 00 00 00 00 00 00 00 5e d8 01 00 +[ 19740ms] VEN_0488&Col02 len=20: 01 03 07 03 f6 01 00 00 00 00 00 00 00 00 00 00 a4 d8 01 00 +[ 19747ms] VEN_0488&Col02 len=20: 01 03 fa 02 f7 01 00 00 00 00 00 00 00 00 00 00 ea d8 01 00 +[ 19754ms] VEN_0488&Col02 len=20: 01 03 ee 02 f7 01 00 00 00 00 00 00 00 00 00 00 30 d9 01 00 +[ 19761ms] VEN_0488&Col02 len=20: 01 03 dd 02 f8 01 00 00 00 00 00 00 00 00 00 00 76 d9 01 00 +[ 19768ms] VEN_0488&Col02 len=20: 01 03 ce 02 f8 01 00 00 00 00 00 00 00 00 00 00 bc d9 01 00 +[ 19775ms] VEN_0488&Col02 len=20: 01 03 bf 02 f8 01 00 00 00 00 00 00 00 00 00 00 02 da 01 00 +[ 19782ms] VEN_0488&Col02 len=20: 01 03 b2 02 f8 01 00 00 00 00 00 00 00 00 00 00 48 da 01 00 +[ 19789ms] VEN_0488&Col02 len=20: 01 03 a2 02 f8 01 00 00 00 00 00 00 00 00 00 00 8e da 01 00 +[ 19797ms] VEN_0488&Col02 len=20: 01 03 94 02 f8 01 00 00 00 00 00 00 00 00 00 00 d4 da 01 00 +[ 19803ms] VEN_0488&Col02 len=20: 01 03 88 02 f8 01 00 00 00 00 00 00 00 00 00 00 1a db 01 00 +[ 19811ms] VEN_0488&Col02 len=20: 01 03 7d 02 f7 01 00 00 00 00 00 00 00 00 00 00 60 db 01 00 +[ 19818ms] VEN_0488&Col02 len=20: 01 03 70 02 f7 01 00 00 00 00 00 00 00 00 00 00 a6 db 01 00 +[ 19825ms] VEN_0488&Col02 len=20: 01 03 65 02 f6 01 00 00 00 00 00 00 00 00 00 00 ec db 01 00 +[ 19832ms] VEN_0488&Col02 len=20: 01 03 59 02 f6 01 00 00 00 00 00 00 00 00 00 00 32 dc 01 00 +[ 19839ms] VEN_0488&Col02 len=20: 01 03 4d 02 f5 01 00 00 00 00 00 00 00 00 00 00 78 dc 01 00 +[ 19846ms] VEN_0488&Col02 len=20: 01 03 43 02 f5 01 00 00 00 00 00 00 00 00 00 00 be dc 01 00 +[ 19853ms] VEN_0488&Col02 len=20: 01 03 39 02 f5 01 00 00 00 00 00 00 00 00 00 00 04 dd 01 00 +[ 19860ms] VEN_0488&Col02 len=20: 01 03 2c 02 f5 01 00 00 00 00 00 00 00 00 00 00 4a dd 01 00 +[ 19867ms] VEN_0488&Col02 len=20: 01 03 23 02 f5 01 00 00 00 00 00 00 00 00 00 00 90 dd 01 00 +[ 19874ms] VEN_0488&Col02 len=20: 01 03 18 02 f4 01 00 00 00 00 00 00 00 00 00 00 d6 dd 01 00 +[ 19882ms] VEN_0488&Col02 len=20: 01 03 0d 02 f2 01 00 00 00 00 00 00 00 00 00 00 1c de 01 00 +[ 19889ms] VEN_0488&Col02 len=20: 01 03 04 02 f2 01 00 00 00 00 00 00 00 00 00 00 62 de 01 00 +[ 19896ms] VEN_0488&Col02 len=20: 01 03 fb 01 f2 01 00 00 00 00 00 00 00 00 00 00 a8 de 01 00 +[ 19903ms] VEN_0488&Col02 len=20: 01 03 f0 01 f1 01 00 00 00 00 00 00 00 00 00 00 ee de 01 00 +[ 19910ms] VEN_0488&Col02 len=20: 01 03 e5 01 f1 01 00 00 00 00 00 00 00 00 00 00 34 df 01 00 +[ 19917ms] VEN_0488&Col02 len=20: 01 03 d9 01 f0 01 00 00 00 00 00 00 00 00 00 00 7a df 01 00 +[ 19924ms] VEN_0488&Col02 len=20: 01 03 cf 01 ef 01 00 00 00 00 00 00 00 00 00 00 c0 df 01 00 +[ 19931ms] VEN_0488&Col02 len=20: 01 03 c7 01 ef 01 00 00 00 00 00 00 00 00 00 00 06 e0 01 00 +[ 19938ms] VEN_0488&Col02 len=20: 01 03 be 01 ef 01 00 00 00 00 00 00 00 00 00 00 4c e0 01 00 +[ 19945ms] VEN_0488&Col02 len=20: 01 03 b4 01 ef 01 00 00 00 00 00 00 00 00 00 00 92 e0 01 00 +[ 19952ms] VEN_0488&Col02 len=20: 01 03 a9 01 ee 01 00 00 00 00 00 00 00 00 00 00 d8 e0 01 00 +[ 19959ms] VEN_0488&Col02 len=20: 01 03 9e 01 ee 01 00 00 00 00 00 00 00 00 00 00 1e e1 01 00 +[ 19966ms] VEN_0488&Col02 len=20: 01 03 93 01 ee 01 00 00 00 00 00 00 00 00 00 00 64 e1 01 00 +[ 19973ms] VEN_0488&Col02 len=20: 01 03 8a 01 ee 01 00 00 00 00 00 00 00 00 00 00 aa e1 01 00 +[ 19980ms] VEN_0488&Col02 len=20: 01 03 81 01 ee 01 00 00 00 00 00 00 00 00 00 00 f0 e1 01 00 +[ 19987ms] VEN_0488&Col02 len=20: 01 03 77 01 ef 01 00 00 00 00 00 00 00 00 00 00 36 e2 01 00 +[ 19994ms] VEN_0488&Col02 len=20: 01 03 6e 01 ef 01 00 00 00 00 00 00 00 00 00 00 7c e2 01 00 +[ 20001ms] VEN_0488&Col02 len=20: 01 03 64 01 f0 01 00 00 00 00 00 00 00 00 00 00 c2 e2 01 00 +[ 20008ms] VEN_0488&Col02 len=20: 01 03 5b 01 f0 01 00 00 00 00 00 00 00 00 00 00 08 e3 01 00 +[ 20016ms] VEN_0488&Col02 len=20: 01 03 53 01 f1 01 00 00 00 00 00 00 00 00 00 00 4e e3 01 00 +[ 20023ms] VEN_0488&Col02 len=20: 01 03 4d 01 f1 01 00 00 00 00 00 00 00 00 00 00 94 e3 01 00 +[ 20030ms] VEN_0488&Col02 len=20: 01 03 4c 01 f1 01 00 00 00 00 00 00 00 00 00 00 da e3 01 00 +[ 20037ms] VEN_0488&Col02 len=20: 01 03 4a 01 f1 01 00 00 00 00 00 00 00 00 00 00 20 e4 01 00 +[ 20044ms] VEN_0488&Col02 len=20: 01 03 4a 01 f1 01 00 00 00 00 00 00 00 00 00 00 66 e4 01 00 +[ 20051ms] VEN_0488&Col02 len=20: 01 03 4a 01 f1 01 00 00 00 00 00 00 00 00 00 00 ac e4 01 00 +[ 20058ms] VEN_0488&Col02 len=20: 01 03 4a 01 f1 01 00 00 00 00 00 00 00 00 00 00 f2 e4 01 00 +[ 20065ms] VEN_0488&Col02 len=20: 01 03 4b 01 f1 01 00 00 00 00 00 00 00 00 00 00 38 e5 01 00 +[ 20072ms] VEN_0488&Col02 len=20: 01 03 4b 01 f1 01 00 00 00 00 00 00 00 00 00 00 7e e5 01 00 +[ 20079ms] VEN_0488&Col02 len=20: 01 03 4c 01 f1 01 00 00 00 00 00 00 00 00 00 00 c4 e5 01 00 +[ 20086ms] VEN_0488&Col02 len=20: 01 03 4c 01 f1 01 00 00 00 00 00 00 00 00 00 00 0a e6 01 00 +[ 20094ms] VEN_0488&Col02 len=20: 01 03 4d 01 f1 01 00 00 00 00 00 00 00 00 00 00 50 e6 01 00 +[ 20101ms] VEN_0488&Col02 len=20: 01 03 4f 01 f1 01 00 00 00 00 00 00 00 00 00 00 96 e6 01 00 +[ 20107ms] VEN_0488&Col02 len=20: 01 03 54 01 f0 01 00 00 00 00 00 00 00 00 00 00 dc e6 01 00 +[ 20114ms] VEN_0488&Col02 len=20: 01 03 5d 01 ef 01 00 00 00 00 00 00 00 00 00 00 22 e7 01 00 +[ 20121ms] VEN_0488&Col02 len=20: 01 03 6d 01 ed 01 00 00 00 00 00 00 00 00 00 00 68 e7 01 00 +[ 20129ms] VEN_0488&Col02 len=20: 01 03 7e 01 eb 01 00 00 00 00 00 00 00 00 00 00 ae e7 01 00 +[ 20136ms] VEN_0488&Col02 len=20: 01 03 8d 01 e8 01 00 00 00 00 00 00 00 00 00 00 f4 e7 01 00 +[ 20143ms] VEN_0488&Col02 len=20: 01 03 9a 01 e7 01 00 00 00 00 00 00 00 00 00 00 3a e8 01 00 +[ 20150ms] VEN_0488&Col02 len=20: 01 03 ac 01 e6 01 00 00 00 00 00 00 00 00 00 00 80 e8 01 00 +[ 20157ms] VEN_0488&Col02 len=20: 01 03 bf 01 e4 01 00 00 00 00 00 00 00 00 00 00 c6 e8 01 00 +[ 20164ms] VEN_0488&Col02 len=20: 01 03 d1 01 e3 01 00 00 00 00 00 00 00 00 00 00 0c e9 01 00 +[ 20171ms] VEN_0488&Col02 len=20: 01 03 e6 01 e1 01 00 00 00 00 00 00 00 00 00 00 52 e9 01 00 +[ 20178ms] VEN_0488&Col02 len=20: 01 03 fd 01 e0 01 00 00 00 00 00 00 00 00 00 00 98 e9 01 00 +[ 20185ms] VEN_0488&Col02 len=20: 01 03 12 02 de 01 00 00 00 00 00 00 00 00 00 00 de e9 01 00 +[ 20192ms] VEN_0488&Col02 len=20: 01 03 26 02 dc 01 00 00 00 00 00 00 00 00 00 00 24 ea 01 00 +[ 20199ms] VEN_0488&Col02 len=20: 01 03 3d 02 db 01 00 00 00 00 00 00 00 00 00 00 6a ea 01 00 +[ 20206ms] VEN_0488&Col02 len=20: 01 03 4f 02 d9 01 00 00 00 00 00 00 00 00 00 00 b0 ea 01 00 +[ 20213ms] VEN_0488&Col02 len=20: 01 03 68 02 d8 01 00 00 00 00 00 00 00 00 00 00 f6 ea 01 00 +[ 20220ms] VEN_0488&Col02 len=20: 01 03 80 02 d7 01 00 00 00 00 00 00 00 00 00 00 3c eb 01 00 +[ 20227ms] VEN_0488&Col02 len=20: 01 03 97 02 d5 01 00 00 00 00 00 00 00 00 00 00 82 eb 01 00 +[ 20234ms] VEN_0488&Col02 len=20: 01 03 af 02 d2 01 00 00 00 00 00 00 00 00 00 00 c8 eb 01 00 +[ 20241ms] VEN_0488&Col02 len=20: 01 03 c8 02 cf 01 00 00 00 00 00 00 00 00 00 00 0e ec 01 00 +[ 20248ms] VEN_0488&Col02 len=20: 01 03 e1 02 cd 01 00 00 00 00 00 00 00 00 00 00 54 ec 01 00 +[ 20256ms] VEN_0488&Col02 len=20: 01 03 fb 02 cb 01 00 00 00 00 00 00 00 00 00 00 9a ec 01 00 +[ 20262ms] VEN_0488&Col02 len=20: 01 03 11 03 c8 01 00 00 00 00 00 00 00 00 00 00 e0 ec 01 00 +[ 20270ms] VEN_0488&Col02 len=20: 01 03 2a 03 c5 01 00 00 00 00 00 00 00 00 00 00 26 ed 01 00 +[ 20277ms] VEN_0488&Col02 len=20: 01 03 42 03 c2 01 00 00 00 00 00 00 00 00 00 00 6c ed 01 00 +[ 20284ms] VEN_0488&Col02 len=20: 01 03 5a 03 bf 01 00 00 00 00 00 00 00 00 00 00 b2 ed 01 00 +[ 20291ms] VEN_0488&Col02 len=20: 01 03 74 03 bb 01 00 00 00 00 00 00 00 00 00 00 f8 ed 01 00 +[ 20298ms] VEN_0488&Col02 len=20: 01 03 8a 03 b8 01 00 00 00 00 00 00 00 00 00 00 3e ee 01 00 +[ 20305ms] VEN_0488&Col02 len=20: 01 03 a2 03 b6 01 00 00 00 00 00 00 00 00 00 00 84 ee 01 00 +[ 20312ms] VEN_0488&Col02 len=20: 01 03 ba 03 b2 01 00 00 00 00 00 00 00 00 00 00 ca ee 01 00 +[ 20319ms] VEN_0488&Col02 len=20: 01 03 cd 03 b1 01 00 00 00 00 00 00 00 00 00 00 10 ef 01 00 +[ 20326ms] VEN_0488&Col02 len=20: 01 03 e2 03 af 01 00 00 00 00 00 00 00 00 00 00 56 ef 01 00 +[ 20333ms] VEN_0488&Col02 len=20: 01 03 f7 03 ad 01 00 00 00 00 00 00 00 00 00 00 9c ef 01 00 +[ 20341ms] VEN_0488&Col02 len=20: 01 03 09 04 ab 01 00 00 00 00 00 00 00 00 00 00 e2 ef 01 00 +[ 20348ms] VEN_0488&Col02 len=20: 01 03 1f 04 a9 01 00 00 00 00 00 00 00 00 00 00 28 f0 01 00 +[ 20355ms] VEN_0488&Col02 len=20: 01 03 33 04 a7 01 00 00 00 00 00 00 00 00 00 00 6e f0 01 00 +[ 20362ms] VEN_0488&Col02 len=20: 01 03 41 04 a5 01 00 00 00 00 00 00 00 00 00 00 b4 f0 01 00 +[ 20369ms] VEN_0488&Col02 len=20: 01 03 51 04 a4 01 00 00 00 00 00 00 00 00 00 00 fa f0 01 00 +[ 20376ms] VEN_0488&Col02 len=20: 01 03 5f 04 a3 01 00 00 00 00 00 00 00 00 00 00 40 f1 01 00 +[ 20383ms] VEN_0488&Col02 len=20: 01 03 6c 04 a2 01 00 00 00 00 00 00 00 00 00 00 86 f1 01 00 +[ 20390ms] VEN_0488&Col02 len=20: 01 03 75 04 a1 01 00 00 00 00 00 00 00 00 00 00 cc f1 01 00 +[ 20397ms] VEN_0488&Col02 len=20: 01 03 7c 04 a1 01 00 00 00 00 00 00 00 00 00 00 12 f2 01 00 +[ 20404ms] VEN_0488&Col02 len=20: 01 03 80 04 a1 01 00 00 00 00 00 00 00 00 00 00 58 f2 01 00 +[ 20411ms] VEN_0488&Col02 len=20: 01 03 84 04 a1 01 00 00 00 00 00 00 00 00 00 00 9e f2 01 00 +[ 20418ms] VEN_0488&Col02 len=20: 01 03 84 04 a1 01 00 00 00 00 00 00 00 00 00 00 e4 f2 01 00 +[ 20425ms] VEN_0488&Col02 len=20: 01 03 84 04 a1 01 00 00 00 00 00 00 00 00 00 00 2a f3 01 00 +[ 20432ms] VEN_0488&Col02 len=20: 01 03 84 04 a1 01 00 00 00 00 00 00 00 00 00 00 70 f3 01 00 +[ 20439ms] VEN_0488&Col02 len=20: 01 03 83 04 a2 01 00 00 00 00 00 00 00 00 00 00 b6 f3 01 00 +[ 20447ms] VEN_0488&Col02 len=20: 01 03 82 04 a2 01 00 00 00 00 00 00 00 00 00 00 fc f3 01 00 +[ 20454ms] VEN_0488&Col02 len=20: 01 03 82 04 a3 01 00 00 00 00 00 00 00 00 00 00 42 f4 01 00 +[ 20461ms] VEN_0488&Col02 len=20: 01 03 81 04 a4 01 00 00 00 00 00 00 00 00 00 00 88 f4 01 00 +[ 20468ms] VEN_0488&Col02 len=20: 01 03 7f 04 a4 01 00 00 00 00 00 00 00 00 00 00 ce f4 01 00 +[ 20475ms] VEN_0488&Col02 len=20: 01 03 7e 04 a5 01 00 00 00 00 00 00 00 00 00 00 14 f5 01 00 +[ 20482ms] VEN_0488&Col02 len=20: 01 03 7a 04 a5 01 00 00 00 00 00 00 00 00 00 00 5a f5 01 00 +[ 20489ms] VEN_0488&Col02 len=20: 01 03 75 04 a8 01 00 00 00 00 00 00 00 00 00 00 a0 f5 01 00 +[ 20497ms] VEN_0488&Col02 len=20: 01 03 6a 04 a9 01 00 00 00 00 00 00 00 00 00 00 e6 f5 01 00 +[ 20503ms] VEN_0488&Col02 len=20: 01 03 5b 04 aa 01 00 00 00 00 00 00 00 00 00 00 2c f6 01 00 +[ 20510ms] VEN_0488&Col02 len=20: 01 03 4c 04 ac 01 00 00 00 00 00 00 00 00 00 00 72 f6 01 00 +[ 20517ms] VEN_0488&Col02 len=20: 01 03 3e 04 ad 01 00 00 00 00 00 00 00 00 00 00 b8 f6 01 00 +[ 20524ms] VEN_0488&Col02 len=20: 01 03 33 04 ae 01 00 00 00 00 00 00 00 00 00 00 fe f6 01 00 +[ 20531ms] VEN_0488&Col02 len=20: 01 03 24 04 af 01 00 00 00 00 00 00 00 00 00 00 44 f7 01 00 +[ 20538ms] VEN_0488&Col02 len=20: 01 03 14 04 b1 01 00 00 00 00 00 00 00 00 00 00 8a f7 01 00 +[ 20545ms] VEN_0488&Col02 len=20: 01 03 02 04 b1 01 00 00 00 00 00 00 00 00 00 00 d0 f7 01 00 +[ 20552ms] VEN_0488&Col02 len=20: 01 03 f3 03 b1 01 00 00 00 00 00 00 00 00 00 00 16 f8 01 00 +[ 20559ms] VEN_0488&Col02 len=20: 01 03 e4 03 b2 01 00 00 00 00 00 00 00 00 00 00 5c f8 01 00 +[ 20567ms] VEN_0488&Col02 len=20: 01 03 d3 03 b3 01 00 00 00 00 00 00 00 00 00 00 a2 f8 01 00 +[ 20574ms] VEN_0488&Col02 len=20: 01 03 c0 03 b2 01 00 00 00 00 00 00 00 00 00 00 e8 f8 01 00 +[ 20581ms] VEN_0488&Col02 len=20: 01 03 b0 03 b3 01 00 00 00 00 00 00 00 00 00 00 2e f9 01 00 +[ 20588ms] VEN_0488&Col02 len=20: 01 03 9f 03 b4 01 00 00 00 00 00 00 00 00 00 00 74 f9 01 00 +[ 20595ms] VEN_0488&Col02 len=20: 01 03 8a 03 b4 01 00 00 00 00 00 00 00 00 00 00 ba f9 01 00 +[ 20602ms] VEN_0488&Col02 len=20: 01 03 79 03 b4 01 00 00 00 00 00 00 00 00 00 00 00 fa 01 00 +[ 20609ms] VEN_0488&Col02 len=20: 01 03 67 03 b4 01 00 00 00 00 00 00 00 00 00 00 46 fa 01 00 +[ 20616ms] VEN_0488&Col02 len=20: 01 03 53 03 b5 01 00 00 00 00 00 00 00 00 00 00 8c fa 01 00 +[ 20623ms] VEN_0488&Col02 len=20: 01 03 3f 03 b5 01 00 00 00 00 00 00 00 00 00 00 d2 fa 01 00 +[ 20630ms] VEN_0488&Col02 len=20: 01 03 2d 03 b5 01 00 00 00 00 00 00 00 00 00 00 18 fb 01 00 +[ 20637ms] VEN_0488&Col02 len=20: 01 03 1a 03 b6 01 00 00 00 00 00 00 00 00 00 00 5e fb 01 00 +[ 20644ms] VEN_0488&Col02 len=20: 01 03 07 03 b7 01 00 00 00 00 00 00 00 00 00 00 a4 fb 01 00 +[ 20651ms] VEN_0488&Col02 len=20: 01 03 f6 02 b7 01 00 00 00 00 00 00 00 00 00 00 ea fb 01 00 +[ 20658ms] VEN_0488&Col02 len=20: 01 03 e4 02 b9 01 00 00 00 00 00 00 00 00 00 00 30 fc 01 00 +[ 20665ms] VEN_0488&Col02 len=20: 01 03 d1 02 b9 01 00 00 00 00 00 00 00 00 00 00 76 fc 01 00 +[ 20672ms] VEN_0488&Col02 len=20: 01 03 be 02 b9 01 00 00 00 00 00 00 00 00 00 00 bc fc 01 00 +[ 20679ms] VEN_0488&Col02 len=20: 01 03 ad 02 b9 01 00 00 00 00 00 00 00 00 00 00 02 fd 01 00 +[ 20686ms] VEN_0488&Col02 len=20: 01 03 97 02 ba 01 00 00 00 00 00 00 00 00 00 00 48 fd 01 00 +[ 20694ms] VEN_0488&Col02 len=20: 01 03 84 02 ba 01 00 00 00 00 00 00 00 00 00 00 8e fd 01 00 +[ 20701ms] VEN_0488&Col02 len=20: 01 03 75 02 bb 01 00 00 00 00 00 00 00 00 00 00 d4 fd 01 00 +[ 20708ms] VEN_0488&Col02 len=20: 01 03 63 02 bc 01 00 00 00 00 00 00 00 00 00 00 1a fe 01 00 +[ 20715ms] VEN_0488&Col02 len=20: 01 03 50 02 bd 01 00 00 00 00 00 00 00 00 00 00 60 fe 01 00 +[ 20722ms] VEN_0488&Col02 len=20: 01 03 3d 02 bf 01 00 00 00 00 00 00 00 00 00 00 a6 fe 01 00 +[ 20729ms] VEN_0488&Col02 len=20: 01 03 2c 02 c0 01 00 00 00 00 00 00 00 00 00 00 ec fe 01 00 +[ 20736ms] VEN_0488&Col02 len=20: 01 03 18 02 c2 01 00 00 00 00 00 00 00 00 00 00 32 ff 01 00 +[ 20743ms] VEN_0488&Col02 len=20: 01 03 07 02 c3 01 00 00 00 00 00 00 00 00 00 00 78 ff 01 00 +[ 20750ms] VEN_0488&Col02 len=20: 01 03 f7 01 c6 01 00 00 00 00 00 00 00 00 00 00 be ff 01 00 +[ 20757ms] VEN_0488&Col02 len=20: 01 03 e6 01 c9 01 00 00 00 00 00 00 00 00 00 00 04 00 01 00 +[ 20764ms] VEN_0488&Col02 len=20: 01 03 d4 01 cc 01 00 00 00 00 00 00 00 00 00 00 4a 00 01 00 +[ 20771ms] VEN_0488&Col02 len=20: 01 03 c5 01 ce 01 00 00 00 00 00 00 00 00 00 00 90 00 01 00 +[ 20778ms] VEN_0488&Col02 len=20: 01 03 b7 01 d1 01 00 00 00 00 00 00 00 00 00 00 d6 00 01 00 +[ 20785ms] VEN_0488&Col02 len=20: 01 03 a5 01 d4 01 00 00 00 00 00 00 00 00 00 00 1c 01 01 00 +[ 20792ms] VEN_0488&Col02 len=20: 01 03 93 01 d7 01 00 00 00 00 00 00 00 00 00 00 62 01 01 00 +[ 20800ms] VEN_0488&Col02 len=20: 01 03 84 01 da 01 00 00 00 00 00 00 00 00 00 00 a8 01 01 00 +[ 20807ms] VEN_0488&Col02 len=20: 01 03 73 01 db 01 00 00 00 00 00 00 00 00 00 00 ee 01 01 00 +[ 20814ms] VEN_0488&Col02 len=20: 01 03 61 01 dd 01 00 00 00 00 00 00 00 00 00 00 34 02 01 00 +[ 20821ms] VEN_0488&Col02 len=20: 01 03 53 01 e1 01 00 00 00 00 00 00 00 00 00 00 7a 02 01 00 +[ 20828ms] VEN_0488&Col02 len=20: 01 03 47 01 e4 01 00 00 00 00 00 00 00 00 00 00 c0 02 01 00 +[ 20835ms] VEN_0488&Col02 len=20: 01 03 37 01 e6 01 00 00 00 00 00 00 00 00 00 00 06 03 01 00 +[ 20842ms] VEN_0488&Col02 len=20: 01 03 28 01 e9 01 00 00 00 00 00 00 00 00 00 00 4c 03 01 00 +[ 20849ms] VEN_0488&Col02 len=20: 01 03 1c 01 eb 01 00 00 00 00 00 00 00 00 00 00 92 03 01 00 +[ 20856ms] VEN_0488&Col02 len=20: 01 03 12 01 ee 01 00 00 00 00 00 00 00 00 00 00 d8 03 01 00 +[ 20863ms] VEN_0488&Col02 len=20: 01 03 0a 01 ee 01 00 00 00 00 00 00 00 00 00 00 1e 04 01 00 +[ 20870ms] VEN_0488&Col02 len=20: 01 03 06 01 f2 01 00 00 00 00 00 00 00 00 00 00 64 04 01 00 +[ 20877ms] VEN_0488&Col02 len=20: 01 03 01 01 f3 01 00 00 00 00 00 00 00 00 00 00 aa 04 01 00 +[ 20884ms] VEN_0488&Col02 len=20: 01 03 00 01 f3 01 00 00 00 00 00 00 00 00 00 00 f0 04 01 00 +[ 20891ms] VEN_0488&Col02 len=20: 01 03 00 01 f4 01 00 00 00 00 00 00 00 00 00 00 36 05 01 00 +[ 20898ms] VEN_0488&Col02 len=20: 01 03 00 01 f4 01 00 00 00 00 00 00 00 00 00 00 7c 05 01 00 +[ 20905ms] VEN_0488&Col02 len=20: 01 03 00 01 f4 01 00 00 00 00 00 00 00 00 00 00 c2 05 01 00 +[ 20913ms] VEN_0488&Col02 len=20: 01 03 01 01 f4 01 00 00 00 00 00 00 00 00 00 00 08 06 01 00 +[ 20920ms] VEN_0488&Col02 len=20: 01 03 01 01 f4 01 00 00 00 00 00 00 00 00 00 00 4e 06 01 00 +[ 20927ms] VEN_0488&Col02 len=20: 01 03 02 01 f4 01 00 00 00 00 00 00 00 00 00 00 94 06 01 00 +[ 20934ms] VEN_0488&Col02 len=20: 01 03 04 01 f4 01 00 00 00 00 00 00 00 00 00 00 da 06 01 00 +[ 20941ms] VEN_0488&Col02 len=20: 01 03 07 01 f4 01 00 00 00 00 00 00 00 00 00 00 20 07 01 00 +[ 20948ms] VEN_0488&Col02 len=20: 01 03 0b 01 f4 01 00 00 00 00 00 00 00 00 00 00 66 07 01 00 +[ 20955ms] VEN_0488&Col02 len=20: 01 03 14 01 f4 01 00 00 00 00 00 00 00 00 00 00 ac 07 01 00 +[ 20963ms] VEN_0488&Col02 len=20: 01 03 21 01 f4 01 00 00 00 00 00 00 00 00 00 00 f2 07 01 00 +[ 20969ms] VEN_0488&Col02 len=20: 01 03 31 01 f4 01 00 00 00 00 00 00 00 00 00 00 38 08 01 00 +[ 20977ms] VEN_0488&Col02 len=20: 01 03 43 01 f2 01 00 00 00 00 00 00 00 00 00 00 7e 08 01 00 +[ 20983ms] VEN_0488&Col02 len=20: 01 03 52 01 f1 01 00 00 00 00 00 00 00 00 00 00 c4 08 01 00 +[ 20990ms] VEN_0488&Col02 len=20: 01 03 64 01 f0 01 00 00 00 00 00 00 00 00 00 00 0a 09 01 00 +[ 20997ms] VEN_0488&Col02 len=20: 01 03 78 01 ee 01 00 00 00 00 00 00 00 00 00 00 50 09 01 00 +[ 21005ms] VEN_0488&Col02 len=20: 01 03 8c 01 ec 01 00 00 00 00 00 00 00 00 00 00 96 09 01 00 +[ 21011ms] VEN_0488&Col02 len=20: 01 03 9f 01 eb 01 00 00 00 00 00 00 00 00 00 00 dc 09 01 00 +[ 21018ms] VEN_0488&Col02 len=20: 01 03 b3 01 e8 01 00 00 00 00 00 00 00 00 00 00 22 0a 01 00 +[ 21025ms] VEN_0488&Col02 len=20: 01 03 cc 01 e6 01 00 00 00 00 00 00 00 00 00 00 68 0a 01 00 +[ 21032ms] VEN_0488&Col02 len=20: 01 03 e7 01 e5 01 00 00 00 00 00 00 00 00 00 00 ae 0a 01 00 +[ 21040ms] VEN_0488&Col02 len=20: 01 03 03 02 e3 01 00 00 00 00 00 00 00 00 00 00 f4 0a 01 00 +[ 21047ms] VEN_0488&Col02 len=20: 01 03 19 02 e2 01 00 00 00 00 00 00 00 00 00 00 3a 0b 01 00 +[ 21054ms] VEN_0488&Col02 len=20: 01 03 32 02 e0 01 00 00 00 00 00 00 00 00 00 00 80 0b 01 00 +[ 21061ms] VEN_0488&Col02 len=20: 01 03 4a 02 df 01 00 00 00 00 00 00 00 00 00 00 c6 0b 01 00 +[ 21068ms] VEN_0488&Col02 len=20: 01 03 65 02 dd 01 00 00 00 00 00 00 00 00 00 00 0c 0c 01 00 +[ 21075ms] VEN_0488&Col02 len=20: 01 03 80 02 dc 01 00 00 00 00 00 00 00 00 00 00 52 0c 01 00 +[ 21082ms] VEN_0488&Col02 len=20: 01 03 99 02 db 01 00 00 00 00 00 00 00 00 00 00 98 0c 01 00 +[ 21089ms] VEN_0488&Col02 len=20: 01 03 b3 02 da 01 00 00 00 00 00 00 00 00 00 00 de 0c 01 00 +[ 21096ms] VEN_0488&Col02 len=20: 01 03 cc 02 d8 01 00 00 00 00 00 00 00 00 00 00 24 0d 01 00 +[ 21103ms] VEN_0488&Col02 len=20: 01 03 e6 02 d6 01 00 00 00 00 00 00 00 00 00 00 6a 0d 01 00 +[ 21111ms] VEN_0488&Col02 len=20: 01 03 02 03 d5 01 00 00 00 00 00 00 00 00 00 00 b0 0d 01 00 +[ 21118ms] VEN_0488&Col02 len=20: 01 03 1a 03 d2 01 00 00 00 00 00 00 00 00 00 00 f6 0d 01 00 +[ 21125ms] VEN_0488&Col02 len=20: 01 03 36 03 d2 01 00 00 00 00 00 00 00 00 00 00 3c 0e 01 00 +[ 21132ms] VEN_0488&Col02 len=20: 01 03 4c 03 d0 01 00 00 00 00 00 00 00 00 00 00 82 0e 01 00 +[ 21139ms] VEN_0488&Col02 len=20: 01 03 65 03 ce 01 00 00 00 00 00 00 00 00 00 00 c8 0e 01 00 +[ 21146ms] VEN_0488&Col02 len=20: 01 03 7e 03 cd 01 00 00 00 00 00 00 00 00 00 00 0e 0f 01 00 +[ 21153ms] VEN_0488&Col02 len=20: 01 03 94 03 cb 01 00 00 00 00 00 00 00 00 00 00 54 0f 01 00 +[ 21160ms] VEN_0488&Col02 len=20: 01 03 ac 03 ca 01 00 00 00 00 00 00 00 00 00 00 9a 0f 01 00 +[ 21167ms] VEN_0488&Col02 len=20: 01 03 c4 03 c9 01 00 00 00 00 00 00 00 00 00 00 e0 0f 01 00 +[ 21174ms] VEN_0488&Col02 len=20: 01 03 d7 03 c8 01 00 00 00 00 00 00 00 00 00 00 26 10 01 00 +[ 21182ms] VEN_0488&Col02 len=20: 01 03 ed 03 c6 01 00 00 00 00 00 00 00 00 00 00 6c 10 01 00 +[ 21188ms] VEN_0488&Col02 len=20: 01 03 02 04 c5 01 00 00 00 00 00 00 00 00 00 00 b2 10 01 00 +[ 21196ms] VEN_0488&Col02 len=20: 01 03 17 04 c4 01 00 00 00 00 00 00 00 00 00 00 f8 10 01 00 +[ 21202ms] VEN_0488&Col02 len=20: 01 03 2d 04 c3 01 00 00 00 00 00 00 00 00 00 00 3e 11 01 00 +[ 21210ms] VEN_0488&Col02 len=20: 01 03 40 04 c2 01 00 00 00 00 00 00 00 00 00 00 84 11 01 00 +[ 21217ms] VEN_0488&Col02 len=20: 01 03 51 04 c1 01 00 00 00 00 00 00 00 00 00 00 ca 11 01 00 +[ 21224ms] VEN_0488&Col02 len=20: 01 03 62 04 c0 01 00 00 00 00 00 00 00 00 00 00 10 12 01 00 +[ 21231ms] VEN_0488&Col02 len=20: 01 03 72 04 bf 01 00 00 00 00 00 00 00 00 00 00 56 12 01 00 +[ 21238ms] VEN_0488&Col02 len=20: 01 03 7d 04 bf 01 00 00 00 00 00 00 00 00 00 00 9c 12 01 00 +[ 21245ms] VEN_0488&Col02 len=20: 01 03 8b 04 bf 01 00 00 00 00 00 00 00 00 00 00 e2 12 01 00 +[ 21252ms] VEN_0488&Col02 len=20: 01 03 95 04 bf 01 00 00 00 00 00 00 00 00 00 00 28 13 01 00 +[ 21259ms] VEN_0488&Col02 len=20: 01 03 a0 04 be 01 00 00 00 00 00 00 00 00 00 00 6e 13 01 00 +[ 21266ms] VEN_0488&Col02 len=20: 01 03 a7 04 be 01 00 00 00 00 00 00 00 00 00 00 b4 13 01 00 +[ 21274ms] VEN_0488&Col02 len=20: 01 03 ad 04 bd 01 00 00 00 00 00 00 00 00 00 00 fa 13 01 00 +[ 21280ms] VEN_0488&Col02 len=20: 01 03 b2 04 bd 01 00 00 00 00 00 00 00 00 00 00 40 14 01 00 +[ 21287ms] VEN_0488&Col02 len=20: 01 03 b5 04 bd 01 00 00 00 00 00 00 00 00 00 00 86 14 01 00 +[ 21294ms] VEN_0488&Col02 len=20: 01 03 b6 04 bd 01 00 00 00 00 00 00 00 00 00 00 cc 14 01 00 +[ 21302ms] VEN_0488&Col02 len=20: 01 03 b7 04 be 01 00 00 00 00 00 00 00 00 00 00 12 15 01 00 +[ 21309ms] VEN_0488&Col02 len=20: 01 03 b7 04 be 01 00 00 00 00 00 00 00 00 00 00 58 15 01 00 +[ 21316ms] VEN_0488&Col02 len=20: 01 03 b7 04 bf 01 00 00 00 00 00 00 00 00 00 00 9e 15 01 00 +[ 21323ms] VEN_0488&Col02 len=20: 01 03 b6 04 bf 01 00 00 00 00 00 00 00 00 00 00 e4 15 01 00 +[ 21330ms] VEN_0488&Col02 len=20: 01 03 b5 04 bf 01 00 00 00 00 00 00 00 00 00 00 2a 16 01 00 +[ 21337ms] VEN_0488&Col02 len=20: 01 03 b5 04 c0 01 00 00 00 00 00 00 00 00 00 00 70 16 01 00 +[ 21344ms] VEN_0488&Col02 len=20: 01 03 b5 04 c1 01 00 00 00 00 00 00 00 00 00 00 b6 16 01 00 +[ 21351ms] VEN_0488&Col02 len=20: 01 03 b4 04 c2 01 00 00 00 00 00 00 00 00 00 00 fc 16 01 00 +[ 21358ms] VEN_0488&Col02 len=20: 01 03 b3 04 c2 01 00 00 00 00 00 00 00 00 00 00 42 17 01 00 +[ 21365ms] VEN_0488&Col02 len=20: 01 03 b2 04 c3 01 00 00 00 00 00 00 00 00 00 00 88 17 01 00 +[ 21372ms] VEN_0488&Col02 len=20: 01 03 ae 04 c4 01 00 00 00 00 00 00 00 00 00 00 ce 17 01 00 +[ 21379ms] VEN_0488&Col02 len=20: 01 03 a6 04 c5 01 00 00 00 00 00 00 00 00 00 00 14 18 01 00 +[ 21386ms] VEN_0488&Col02 len=20: 01 03 99 04 c8 01 00 00 00 00 00 00 00 00 00 00 5a 18 01 00 +[ 21393ms] VEN_0488&Col02 len=20: 01 03 88 04 cb 01 00 00 00 00 00 00 00 00 00 00 a0 18 01 00 +[ 21401ms] VEN_0488&Col02 len=20: 01 03 7a 04 cb 01 00 00 00 00 00 00 00 00 00 00 e6 18 01 00 +[ 21407ms] VEN_0488&Col02 len=20: 01 03 6e 04 cc 01 00 00 00 00 00 00 00 00 00 00 2c 19 01 00 +[ 21414ms] VEN_0488&Col02 len=20: 01 03 61 04 cd 01 00 00 00 00 00 00 00 00 00 00 72 19 01 00 +[ 21421ms] VEN_0488&Col02 len=20: 01 03 50 04 d0 01 00 00 00 00 00 00 00 00 00 00 b8 19 01 00 +[ 21429ms] VEN_0488&Col02 len=20: 01 03 3f 04 d3 01 00 00 00 00 00 00 00 00 00 00 fe 19 01 00 +[ 21436ms] VEN_0488&Col02 len=20: 01 03 2e 04 d2 01 00 00 00 00 00 00 00 00 00 00 44 1a 01 00 +[ 21443ms] VEN_0488&Col02 len=20: 01 03 1b 04 d5 01 00 00 00 00 00 00 00 00 00 00 8a 1a 01 00 +[ 21450ms] VEN_0488&Col02 len=20: 01 03 06 04 d8 01 00 00 00 00 00 00 00 00 00 00 d0 1a 01 00 +[ 21457ms] VEN_0488&Col02 len=20: 01 03 f4 03 d8 01 00 00 00 00 00 00 00 00 00 00 16 1b 01 00 +[ 21464ms] VEN_0488&Col02 len=20: 01 03 e0 03 d8 01 00 00 00 00 00 00 00 00 00 00 5c 1b 01 00 +[ 21471ms] VEN_0488&Col02 len=20: 01 03 cb 03 db 01 00 00 00 00 00 00 00 00 00 00 a2 1b 01 00 +[ 21478ms] VEN_0488&Col02 len=20: 01 03 b7 03 dd 01 00 00 00 00 00 00 00 00 00 00 e8 1b 01 00 +[ 21485ms] VEN_0488&Col02 len=20: 01 03 a2 03 dd 01 00 00 00 00 00 00 00 00 00 00 2e 1c 01 00 +[ 21492ms] VEN_0488&Col02 len=20: 01 03 8b 03 e0 01 00 00 00 00 00 00 00 00 00 00 74 1c 01 00 +[ 21499ms] VEN_0488&Col02 len=20: 01 03 76 03 e0 01 00 00 00 00 00 00 00 00 00 00 ba 1c 01 00 +[ 21506ms] VEN_0488&Col02 len=20: 01 03 5f 03 e1 01 00 00 00 00 00 00 00 00 00 00 00 1d 01 00 +[ 21513ms] VEN_0488&Col02 len=20: 01 03 44 03 e4 01 00 00 00 00 00 00 00 00 00 00 46 1d 01 00 +[ 21520ms] VEN_0488&Col02 len=20: 01 03 2d 03 e4 01 00 00 00 00 00 00 00 00 00 00 8c 1d 01 00 +[ 21527ms] VEN_0488&Col02 len=20: 01 03 15 03 e5 01 00 00 00 00 00 00 00 00 00 00 d2 1d 01 00 +[ 21535ms] VEN_0488&Col02 len=20: 01 03 fe 02 e8 01 00 00 00 00 00 00 00 00 00 00 18 1e 01 00 +[ 21542ms] VEN_0488&Col02 len=20: 01 03 e5 02 ea 01 00 00 00 00 00 00 00 00 00 00 5e 1e 01 00 +[ 21549ms] VEN_0488&Col02 len=20: 01 03 cc 02 ec 01 00 00 00 00 00 00 00 00 00 00 a4 1e 01 00 +[ 21556ms] VEN_0488&Col02 len=20: 01 03 b6 02 ee 01 00 00 00 00 00 00 00 00 00 00 ea 1e 01 00 +[ 21563ms] VEN_0488&Col02 len=20: 01 03 9d 02 f0 01 00 00 00 00 00 00 00 00 00 00 30 1f 01 00 +[ 21570ms] VEN_0488&Col02 len=20: 01 03 83 02 f0 01 00 00 00 00 00 00 00 00 00 00 76 1f 01 00 +[ 21577ms] VEN_0488&Col02 len=20: 01 03 6e 02 f1 01 00 00 00 00 00 00 00 00 00 00 bc 1f 01 00 +[ 21584ms] VEN_0488&Col02 len=20: 01 03 56 02 f2 01 00 00 00 00 00 00 00 00 00 00 02 20 01 00 +[ 21591ms] VEN_0488&Col02 len=20: 01 03 41 02 f3 01 00 00 00 00 00 00 00 00 00 00 48 20 01 00 +[ 21598ms] VEN_0488&Col02 len=20: 01 03 2c 02 f4 01 00 00 00 00 00 00 00 00 00 00 8e 20 01 00 +[ 21605ms] VEN_0488&Col02 len=20: 01 03 17 02 f5 01 00 00 00 00 00 00 00 00 00 00 d4 20 01 00 +[ 21613ms] VEN_0488&Col02 len=20: 01 03 01 02 f6 01 00 00 00 00 00 00 00 00 00 00 1a 21 01 00 +[ 21619ms] VEN_0488&Col02 len=20: 01 03 ef 01 f9 01 00 00 00 00 00 00 00 00 00 00 60 21 01 00 +[ 21627ms] VEN_0488&Col02 len=20: 01 03 dc 01 f9 01 00 00 00 00 00 00 00 00 00 00 a6 21 01 00 +[ 21634ms] VEN_0488&Col02 len=20: 01 03 cb 01 f9 01 00 00 00 00 00 00 00 00 00 00 ec 21 01 00 +[ 21641ms] VEN_0488&Col02 len=20: 01 03 bc 01 f9 01 00 00 00 00 00 00 00 00 00 00 32 22 01 00 +[ 21648ms] VEN_0488&Col02 len=20: 01 03 ab 01 fc 01 00 00 00 00 00 00 00 00 00 00 78 22 01 00 +[ 21655ms] VEN_0488&Col02 len=20: 01 03 99 01 fc 01 00 00 00 00 00 00 00 00 00 00 be 22 01 00 +[ 21662ms] VEN_0488&Col02 len=20: 01 03 89 01 fc 01 00 00 00 00 00 00 00 00 00 00 04 23 01 00 +[ 21669ms] VEN_0488&Col02 len=20: 01 03 7a 01 fc 01 00 00 00 00 00 00 00 00 00 00 4a 23 01 00 +[ 21676ms] VEN_0488&Col02 len=20: 01 03 6d 01 fd 01 00 00 00 00 00 00 00 00 00 00 90 23 01 00 +[ 21683ms] VEN_0488&Col02 len=20: 01 03 5f 01 fe 01 00 00 00 00 00 00 00 00 00 00 d6 23 01 00 +[ 21690ms] VEN_0488&Col02 len=20: 01 03 52 01 fe 01 00 00 00 00 00 00 00 00 00 00 1c 24 01 00 +[ 21697ms] VEN_0488&Col02 len=20: 01 03 49 01 fe 01 00 00 00 00 00 00 00 00 00 00 62 24 01 00 +[ 21705ms] VEN_0488&Col02 len=20: 01 03 3f 01 fd 01 00 00 00 00 00 00 00 00 00 00 a8 24 01 00 +[ 21711ms] VEN_0488&Col02 len=20: 01 03 36 01 fc 01 00 00 00 00 00 00 00 00 00 00 ee 24 01 00 +[ 21718ms] VEN_0488&Col02 len=20: 01 03 2f 01 fb 01 00 00 00 00 00 00 00 00 00 00 34 25 01 00 +[ 21725ms] VEN_0488&Col02 len=20: 01 03 29 01 fa 01 00 00 00 00 00 00 00 00 00 00 7a 25 01 00 +[ 21732ms] VEN_0488&Col02 len=20: 01 03 25 01 f9 01 00 00 00 00 00 00 00 00 00 00 c0 25 01 00 +[ 21739ms] VEN_0488&Col02 len=20: 01 03 23 01 f8 01 00 00 00 00 00 00 00 00 00 00 06 26 01 00 +[ 21747ms] VEN_0488&Col02 len=20: 01 03 23 01 f7 01 00 00 00 00 00 00 00 00 00 00 4c 26 01 00 +[ 21753ms] VEN_0488&Col02 len=20: 01 03 23 01 f6 01 00 00 00 00 00 00 00 00 00 00 92 26 01 00 +[ 21761ms] VEN_0488&Col02 len=20: 01 03 23 01 f6 01 00 00 00 00 00 00 00 00 00 00 d8 26 01 00 +[ 21768ms] VEN_0488&Col02 len=20: 01 03 23 01 f5 01 00 00 00 00 00 00 00 00 00 00 1e 27 01 00 +[ 21775ms] VEN_0488&Col02 len=20: 01 03 24 01 f5 01 00 00 00 00 00 00 00 00 00 00 64 27 01 00 +[ 21782ms] VEN_0488&Col02 len=20: 01 03 25 01 f5 01 00 00 00 00 00 00 00 00 00 00 aa 27 01 00 +[ 21789ms] VEN_0488&Col02 len=20: 01 03 26 01 f5 01 00 00 00 00 00 00 00 00 00 00 f0 27 01 00 +[ 21796ms] VEN_0488&Col02 len=20: 01 03 29 01 f5 01 00 00 00 00 00 00 00 00 00 00 36 28 01 00 +[ 21803ms] VEN_0488&Col02 len=20: 01 03 29 01 f5 01 00 00 00 00 00 00 00 00 00 00 7c 28 01 00 +[ 21810ms] VEN_0488&Col02 len=20: 01 03 2c 01 f5 01 00 00 00 00 00 00 00 00 00 00 c2 28 01 00 +[ 21817ms] VEN_0488&Col02 len=20: 01 03 34 01 f5 01 00 00 00 00 00 00 00 00 00 00 08 29 01 00 +[ 21824ms] VEN_0488&Col02 len=20: 01 03 40 01 f1 01 00 00 00 00 00 00 00 00 00 00 4e 29 01 00 +[ 21831ms] VEN_0488&Col02 len=20: 01 03 4d 01 f0 01 00 00 00 00 00 00 00 00 00 00 94 29 01 00 +[ 21838ms] VEN_0488&Col02 len=20: 01 03 59 01 f0 01 00 00 00 00 00 00 00 00 00 00 da 29 01 00 +[ 21845ms] VEN_0488&Col02 len=20: 01 03 6a 01 f0 01 00 00 00 00 00 00 00 00 00 00 20 2a 01 00 +[ 21852ms] VEN_0488&Col02 len=20: 01 03 7c 01 ee 01 00 00 00 00 00 00 00 00 00 00 66 2a 01 00 +[ 21859ms] VEN_0488&Col02 len=20: 01 03 8c 01 ec 01 00 00 00 00 00 00 00 00 00 00 ac 2a 01 00 +[ 21866ms] VEN_0488&Col02 len=20: 01 03 9b 01 eb 01 00 00 00 00 00 00 00 00 00 00 f2 2a 01 00 +[ 21873ms] VEN_0488&Col02 len=20: 01 03 b1 01 e9 01 00 00 00 00 00 00 00 00 00 00 38 2b 01 00 +[ 21880ms] VEN_0488&Col02 len=20: 01 03 c6 01 e8 01 00 00 00 00 00 00 00 00 00 00 7e 2b 01 00 +[ 21888ms] VEN_0488&Col02 len=20: 01 03 da 01 e7 01 00 00 00 00 00 00 00 00 00 00 c4 2b 01 00 +[ 21895ms] VEN_0488&Col02 len=20: 01 03 f5 01 e5 01 00 00 00 00 00 00 00 00 00 00 0a 2c 01 00 +[ 21902ms] VEN_0488&Col02 len=20: 01 03 0d 02 e4 01 00 00 00 00 00 00 00 00 00 00 50 2c 01 00 +[ 21909ms] VEN_0488&Col02 len=20: 01 03 23 02 e3 01 00 00 00 00 00 00 00 00 00 00 96 2c 01 00 +[ 21916ms] VEN_0488&Col02 len=20: 01 03 3b 02 e1 01 00 00 00 00 00 00 00 00 00 00 dc 2c 01 00 +[ 21923ms] VEN_0488&Col02 len=20: 01 03 50 02 e0 01 00 00 00 00 00 00 00 00 00 00 22 2d 01 00 +[ 21930ms] VEN_0488&Col02 len=20: 01 03 6b 02 df 01 00 00 00 00 00 00 00 00 00 00 68 2d 01 00 +[ 21937ms] VEN_0488&Col02 len=20: 01 03 83 02 de 01 00 00 00 00 00 00 00 00 00 00 ae 2d 01 00 +[ 21944ms] VEN_0488&Col02 len=20: 01 03 9a 02 dd 01 00 00 00 00 00 00 00 00 00 00 f4 2d 01 00 +[ 21951ms] VEN_0488&Col02 len=20: 01 03 b4 02 dc 01 00 00 00 00 00 00 00 00 00 00 3a 2e 01 00 +[ 21959ms] VEN_0488&Col02 len=20: 01 03 ca 02 da 01 00 00 00 00 00 00 00 00 00 00 80 2e 01 00 +[ 21965ms] VEN_0488&Col02 len=20: 01 03 e2 02 d9 01 00 00 00 00 00 00 00 00 00 00 c6 2e 01 00 +[ 21972ms] VEN_0488&Col02 len=20: 01 03 fc 02 d8 01 00 00 00 00 00 00 00 00 00 00 0c 2f 01 00 +[ 21980ms] VEN_0488&Col02 len=20: 01 03 13 03 d7 01 00 00 00 00 00 00 00 00 00 00 52 2f 01 00 +[ 21987ms] VEN_0488&Col02 len=20: 01 03 2c 03 d6 01 00 00 00 00 00 00 00 00 00 00 98 2f 01 00 +[ 21994ms] VEN_0488&Col02 len=20: 01 03 42 03 d5 01 00 00 00 00 00 00 00 00 00 00 de 2f 01 00 +[ 22001ms] VEN_0488&Col02 len=20: 01 03 5b 03 d3 01 00 00 00 00 00 00 00 00 00 00 24 30 01 00 +[ 22008ms] VEN_0488&Col02 len=20: 01 03 75 03 d3 01 00 00 00 00 00 00 00 00 00 00 6a 30 01 00 +[ 22015ms] VEN_0488&Col02 len=20: 01 03 8a 03 d0 01 00 00 00 00 00 00 00 00 00 00 b0 30 01 00 +[ 22022ms] VEN_0488&Col02 len=20: 01 03 a1 03 d0 01 00 00 00 00 00 00 00 00 00 00 f6 30 01 00 +[ 22029ms] VEN_0488&Col02 len=20: 01 03 b9 03 d0 01 00 00 00 00 00 00 00 00 00 00 3c 31 01 00 +[ 22036ms] VEN_0488&Col02 len=20: 01 03 cf 03 cf 01 00 00 00 00 00 00 00 00 00 00 82 31 01 00 +[ 22043ms] VEN_0488&Col02 len=20: 01 03 e6 03 ce 01 00 00 00 00 00 00 00 00 00 00 c8 31 01 00 +[ 22050ms] VEN_0488&Col02 len=20: 01 03 fd 03 cd 01 00 00 00 00 00 00 00 00 00 00 0e 32 01 00 +[ 22057ms] VEN_0488&Col02 len=20: 01 03 13 04 cd 01 00 00 00 00 00 00 00 00 00 00 54 32 01 00 +[ 22064ms] VEN_0488&Col02 len=20: 01 03 2b 04 cc 01 00 00 00 00 00 00 00 00 00 00 9a 32 01 00 +[ 22072ms] VEN_0488&Col02 len=20: 01 03 41 04 cb 01 00 00 00 00 00 00 00 00 00 00 e0 32 01 00 +[ 22079ms] VEN_0488&Col02 len=20: 01 03 54 04 ca 01 00 00 00 00 00 00 00 00 00 00 26 33 01 00 +[ 22086ms] VEN_0488&Col02 len=20: 01 03 68 04 c9 01 00 00 00 00 00 00 00 00 00 00 6c 33 01 00 +[ 22093ms] VEN_0488&Col02 len=20: 01 03 7b 04 c8 01 00 00 00 00 00 00 00 00 00 00 b2 33 01 00 +[ 22100ms] VEN_0488&Col02 len=20: 01 03 8d 04 c7 01 00 00 00 00 00 00 00 00 00 00 f8 33 01 00 +[ 22107ms] VEN_0488&Col02 len=20: 01 03 a0 04 c4 01 00 00 00 00 00 00 00 00 00 00 3e 34 01 00 +[ 22114ms] VEN_0488&Col02 len=20: 01 03 b3 04 c3 01 00 00 00 00 00 00 00 00 00 00 84 34 01 00 +[ 22121ms] VEN_0488&Col02 len=20: 01 03 c1 04 c3 01 00 00 00 00 00 00 00 00 00 00 ca 34 01 00 +[ 22128ms] VEN_0488&Col02 len=20: 01 03 d2 04 c2 01 00 00 00 00 00 00 00 00 00 00 10 35 01 00 +[ 22135ms] VEN_0488&Col02 len=20: 01 03 e3 04 c1 01 00 00 00 00 00 00 00 00 00 00 56 35 01 00 +[ 22143ms] VEN_0488&Col02 len=20: 01 03 f0 04 c0 01 00 00 00 00 00 00 00 00 00 00 9c 35 01 00 +[ 22149ms] VEN_0488&Col02 len=20: 01 03 fb 04 c0 01 00 00 00 00 00 00 00 00 00 00 e2 35 01 00 +[ 22156ms] VEN_0488&Col02 len=20: 01 03 04 05 c1 01 00 00 00 00 00 00 00 00 00 00 28 36 01 00 +[ 22163ms] VEN_0488&Col02 len=20: 01 03 0b 05 c1 01 00 00 00 00 00 00 00 00 00 00 6e 36 01 00 +[ 22170ms] VEN_0488&Col02 len=20: 01 03 0f 05 c2 01 00 00 00 00 00 00 00 00 00 00 b4 36 01 00 +[ 22177ms] VEN_0488&Col02 len=20: 01 03 0f 05 c2 01 00 00 00 00 00 00 00 00 00 00 fa 36 01 00 +[ 22184ms] VEN_0488&Col02 len=20: 01 03 0f 05 c3 01 00 00 00 00 00 00 00 00 00 00 40 37 01 00 +[ 22191ms] VEN_0488&Col02 len=20: 01 03 0f 05 c4 01 00 00 00 00 00 00 00 00 00 00 86 37 01 00 +[ 22199ms] VEN_0488&Col02 len=20: 01 03 0e 05 c4 01 00 00 00 00 00 00 00 00 00 00 cc 37 01 00 +[ 22206ms] VEN_0488&Col02 len=20: 01 03 0d 05 c5 01 00 00 00 00 00 00 00 00 00 00 12 38 01 00 +[ 22212ms] VEN_0488&Col02 len=20: 01 03 0b 05 c6 01 00 00 00 00 00 00 00 00 00 00 58 38 01 00 +[ 22219ms] VEN_0488&Col02 len=20: 01 03 07 05 c9 01 00 00 00 00 00 00 00 00 00 00 9e 38 01 00 +[ 22227ms] VEN_0488&Col02 len=20: 01 03 fb 04 cc 01 00 00 00 00 00 00 00 00 00 00 e4 38 01 00 +[ 22234ms] VEN_0488&Col02 len=20: 01 03 eb 04 cf 01 00 00 00 00 00 00 00 00 00 00 2a 39 01 00 +[ 22241ms] VEN_0488&Col02 len=20: 01 03 d8 04 d4 01 00 00 00 00 00 00 00 00 00 00 70 39 01 00 +[ 22248ms] VEN_0488&Col02 len=20: 01 03 c2 04 d8 01 00 00 00 00 00 00 00 00 00 00 b6 39 01 00 +[ 22255ms] VEN_0488&Col02 len=20: 01 03 af 04 db 01 00 00 00 00 00 00 00 00 00 00 fc 39 01 00 +[ 22262ms] VEN_0488&Col02 len=20: 01 03 9c 04 db 01 00 00 00 00 00 00 00 00 00 00 42 3a 01 00 +[ 22269ms] VEN_0488&Col02 len=20: 01 03 84 04 de 01 00 00 00 00 00 00 00 00 00 00 88 3a 01 00 +[ 22276ms] VEN_0488&Col02 len=20: 01 03 6f 04 de 01 00 00 00 00 00 00 00 00 00 00 ce 3a 01 00 +[ 22283ms] VEN_0488&Col02 len=20: 01 03 59 04 df 01 00 00 00 00 00 00 00 00 00 00 14 3b 01 00 +[ 22290ms] VEN_0488&Col02 len=20: 01 03 41 04 df 01 00 00 00 00 00 00 00 00 00 00 5a 3b 01 00 +[ 22297ms] VEN_0488&Col02 len=20: 01 03 2c 04 df 01 00 00 00 00 00 00 00 00 00 00 a0 3b 01 00 +[ 22304ms] VEN_0488&Col02 len=20: 01 03 14 04 df 01 00 00 00 00 00 00 00 00 00 00 e6 3b 01 00 +[ 22311ms] VEN_0488&Col02 len=20: 01 03 fc 03 df 01 00 00 00 00 00 00 00 00 00 00 2c 3c 01 00 +[ 22319ms] VEN_0488&Col02 len=20: 01 03 e6 03 df 01 00 00 00 00 00 00 00 00 00 00 72 3c 01 00 +[ 22325ms] VEN_0488&Col02 len=20: 01 03 ce 03 de 01 00 00 00 00 00 00 00 00 00 00 b8 3c 01 00 +[ 22333ms] VEN_0488&Col02 len=20: 01 03 b8 03 dd 01 00 00 00 00 00 00 00 00 00 00 fe 3c 01 00 +[ 22340ms] VEN_0488&Col02 len=20: 01 03 a4 03 da 01 00 00 00 00 00 00 00 00 00 00 44 3d 01 00 +[ 22347ms] VEN_0488&Col02 len=20: 01 03 8c 03 da 01 00 00 00 00 00 00 00 00 00 00 8a 3d 01 00 +[ 22354ms] VEN_0488&Col02 len=20: 01 03 77 03 d9 01 00 00 00 00 00 00 00 00 00 00 d0 3d 01 00 +[ 22361ms] VEN_0488&Col02 len=20: 01 03 60 03 d6 01 00 00 00 00 00 00 00 00 00 00 16 3e 01 00 +[ 22368ms] VEN_0488&Col02 len=20: 01 03 48 03 d6 01 00 00 00 00 00 00 00 00 00 00 5c 3e 01 00 +[ 22375ms] VEN_0488&Col02 len=20: 01 03 33 03 d3 01 00 00 00 00 00 00 00 00 00 00 a2 3e 01 00 +[ 22382ms] VEN_0488&Col02 len=20: 01 03 1e 03 d2 01 00 00 00 00 00 00 00 00 00 00 e8 3e 01 00 +[ 22389ms] VEN_0488&Col02 len=20: 01 03 06 03 d2 01 00 00 00 00 00 00 00 00 00 00 2e 3f 01 00 +[ 22396ms] VEN_0488&Col02 len=20: 01 03 f2 02 cf 01 00 00 00 00 00 00 00 00 00 00 74 3f 01 00 +[ 22403ms] VEN_0488&Col02 len=20: 01 03 dc 02 cf 01 00 00 00 00 00 00 00 00 00 00 ba 3f 01 00 +[ 22410ms] VEN_0488&Col02 len=20: 01 03 c5 02 ce 01 00 00 00 00 00 00 00 00 00 00 00 40 01 00 +[ 22417ms] VEN_0488&Col02 len=20: 01 03 b1 02 cb 01 00 00 00 00 00 00 00 00 00 00 46 40 01 00 +[ 22424ms] VEN_0488&Col02 len=20: 01 03 9b 02 cb 01 00 00 00 00 00 00 00 00 00 00 8c 40 01 00 +[ 22431ms] VEN_0488&Col02 len=20: 01 03 85 02 cb 01 00 00 00 00 00 00 00 00 00 00 d2 40 01 00 +[ 22438ms] VEN_0488&Col02 len=20: 01 03 73 02 c8 01 00 00 00 00 00 00 00 00 00 00 18 41 01 00 +[ 22446ms] VEN_0488&Col02 len=20: 01 03 5f 02 c8 01 00 00 00 00 00 00 00 00 00 00 5e 41 01 00 +[ 22453ms] VEN_0488&Col02 len=20: 01 03 4b 02 c8 01 00 00 00 00 00 00 00 00 00 00 a4 41 01 00 +[ 22460ms] VEN_0488&Col02 len=20: 01 03 3a 02 c8 01 00 00 00 00 00 00 00 00 00 00 ea 41 01 00 +[ 22467ms] VEN_0488&Col02 len=20: 01 03 27 02 c7 01 00 00 00 00 00 00 00 00 00 00 30 42 01 00 +[ 22474ms] VEN_0488&Col02 len=20: 01 03 15 02 c8 01 00 00 00 00 00 00 00 00 00 00 76 42 01 00 +[ 22481ms] VEN_0488&Col02 len=20: 01 03 03 02 c8 01 00 00 00 00 00 00 00 00 00 00 bc 42 01 00 +[ 22488ms] VEN_0488&Col02 len=20: 01 03 f4 01 c8 01 00 00 00 00 00 00 00 00 00 00 02 43 01 00 +[ 22495ms] VEN_0488&Col02 len=20: 01 03 e4 01 c9 01 00 00 00 00 00 00 00 00 00 00 48 43 01 00 +[ 22502ms] VEN_0488&Col02 len=20: 01 03 d4 01 ca 01 00 00 00 00 00 00 00 00 00 00 8e 43 01 00 +[ 22509ms] VEN_0488&Col02 len=20: 01 03 c9 01 cb 01 00 00 00 00 00 00 00 00 00 00 d4 43 01 00 +[ 22516ms] VEN_0488&Col02 len=20: 01 03 be 01 cc 01 00 00 00 00 00 00 00 00 00 00 1a 44 01 00 +[ 22523ms] VEN_0488&Col02 len=20: 01 03 b2 01 cd 01 00 00 00 00 00 00 00 00 00 00 60 44 01 00 +[ 22530ms] VEN_0488&Col02 len=20: 01 03 a6 01 cd 01 00 00 00 00 00 00 00 00 00 00 a6 44 01 00 +[ 22537ms] VEN_0488&Col02 len=20: 01 03 9d 01 ce 01 00 00 00 00 00 00 00 00 00 00 ec 44 01 00 +[ 22544ms] VEN_0488&Col02 len=20: 01 03 96 01 cf 01 00 00 00 00 00 00 00 00 00 00 32 45 01 00 +[ 22551ms] VEN_0488&Col02 len=20: 01 03 91 01 cf 01 00 00 00 00 00 00 00 00 00 00 78 45 01 00 +[ 22559ms] VEN_0488&Col02 len=20: 01 03 8f 01 cf 01 00 00 00 00 00 00 00 00 00 00 be 45 01 00 +[ 22566ms] VEN_0488&Col02 len=20: 01 03 8e 01 d0 01 00 00 00 00 00 00 00 00 00 00 04 46 01 00 +[ 22573ms] VEN_0488&Col02 len=20: 01 03 8e 01 d0 01 00 00 00 00 00 00 00 00 00 00 4a 46 01 00 +[ 22580ms] VEN_0488&Col02 len=20: 01 03 8e 01 d0 01 00 00 00 00 00 00 00 00 00 00 90 46 01 00 +[ 22587ms] VEN_0488&Col02 len=20: 01 03 8e 01 d0 01 00 00 00 00 00 00 00 00 00 00 d6 46 01 00 +[ 22594ms] VEN_0488&Col02 len=20: 01 03 8f 01 d1 01 00 00 00 00 00 00 00 00 00 00 1c 47 01 00 +[ 22601ms] VEN_0488&Col02 len=20: 01 03 90 01 d1 01 00 00 00 00 00 00 00 00 00 00 62 47 01 00 +[ 22608ms] VEN_0488&Col02 len=20: 01 03 91 01 d2 01 00 00 00 00 00 00 00 00 00 00 a8 47 01 00 +[ 22615ms] VEN_0488&Col02 len=20: 01 03 92 01 d2 01 00 00 00 00 00 00 00 00 00 00 ee 47 01 00 +[ 22622ms] VEN_0488&Col02 len=20: 01 03 94 01 d3 01 00 00 00 00 00 00 00 00 00 00 34 48 01 00 +[ 22629ms] VEN_0488&Col02 len=20: 01 03 98 01 d3 01 00 00 00 00 00 00 00 00 00 00 7a 48 01 00 +[ 22636ms] VEN_0488&Col02 len=20: 01 03 a1 01 d5 01 00 00 00 00 00 00 00 00 00 00 c0 48 01 00 +[ 22643ms] VEN_0488&Col02 len=20: 01 03 ac 01 d7 01 00 00 00 00 00 00 00 00 00 00 06 49 01 00 +[ 22650ms] VEN_0488&Col02 len=20: 01 03 bb 01 d9 01 00 00 00 00 00 00 00 00 00 00 4c 49 01 00 +[ 22657ms] VEN_0488&Col02 len=20: 01 03 c9 01 da 01 00 00 00 00 00 00 00 00 00 00 92 49 01 00 +[ 22664ms] VEN_0488&Col02 len=20: 01 03 d7 01 db 01 00 00 00 00 00 00 00 00 00 00 d8 49 01 00 +[ 22671ms] VEN_0488&Col02 len=20: 01 03 eb 01 dc 01 00 00 00 00 00 00 00 00 00 00 1e 4a 01 00 +[ 22679ms] VEN_0488&Col02 len=20: 01 03 fd 01 de 01 00 00 00 00 00 00 00 00 00 00 64 4a 01 00 +[ 22686ms] VEN_0488&Col02 len=20: 01 03 0e 02 df 01 00 00 00 00 00 00 00 00 00 00 aa 4a 01 00 +[ 22692ms] VEN_0488&Col02 len=20: 01 03 22 02 df 01 00 00 00 00 00 00 00 00 00 00 f0 4a 01 00 +[ 22700ms] VEN_0488&Col02 len=20: 01 03 37 02 e1 01 00 00 00 00 00 00 00 00 00 00 36 4b 01 00 +[ 22707ms] VEN_0488&Col02 len=20: 01 03 4c 02 e1 01 00 00 00 00 00 00 00 00 00 00 7c 4b 01 00 +[ 22714ms] VEN_0488&Col02 len=20: 01 03 64 02 e2 01 00 00 00 00 00 00 00 00 00 00 c2 4b 01 00 +[ 22721ms] VEN_0488&Col02 len=20: 01 03 7f 02 e3 01 00 00 00 00 00 00 00 00 00 00 08 4c 01 00 +[ 22728ms] VEN_0488&Col02 len=20: 01 03 96 02 e4 01 00 00 00 00 00 00 00 00 00 00 4e 4c 01 00 +[ 22735ms] VEN_0488&Col02 len=20: 01 03 b0 02 e4 01 00 00 00 00 00 00 00 00 00 00 94 4c 01 00 +[ 22742ms] VEN_0488&Col02 len=20: 01 03 ca 02 e5 01 00 00 00 00 00 00 00 00 00 00 da 4c 01 00 +[ 22749ms] VEN_0488&Col02 len=20: 01 03 e5 02 e5 01 00 00 00 00 00 00 00 00 00 00 20 4d 01 00 +[ 22756ms] VEN_0488&Col02 len=20: 01 03 01 03 e4 01 00 00 00 00 00 00 00 00 00 00 66 4d 01 00 +[ 22763ms] VEN_0488&Col02 len=20: 01 03 1c 03 e4 01 00 00 00 00 00 00 00 00 00 00 ac 4d 01 00 +[ 22770ms] VEN_0488&Col02 len=20: 01 03 39 03 e3 01 00 00 00 00 00 00 00 00 00 00 f2 4d 01 00 +[ 22777ms] VEN_0488&Col02 len=20: 01 03 54 03 e3 01 00 00 00 00 00 00 00 00 00 00 38 4e 01 00 +[ 22784ms] VEN_0488&Col02 len=20: 01 03 71 03 e2 01 00 00 00 00 00 00 00 00 00 00 7e 4e 01 00 +[ 22792ms] VEN_0488&Col02 len=20: 01 03 8c 03 e1 01 00 00 00 00 00 00 00 00 00 00 c4 4e 01 00 +[ 22798ms] VEN_0488&Col02 len=20: 01 03 aa 03 e1 01 00 00 00 00 00 00 00 00 00 00 0a 4f 01 00 +[ 22806ms] VEN_0488&Col02 len=20: 01 03 c4 03 e0 01 00 00 00 00 00 00 00 00 00 00 50 4f 01 00 +[ 22813ms] VEN_0488&Col02 len=20: 01 03 e0 03 e0 01 00 00 00 00 00 00 00 00 00 00 96 4f 01 00 +[ 22820ms] VEN_0488&Col02 len=20: 01 03 fa 03 e0 01 00 00 00 00 00 00 00 00 00 00 dc 4f 01 00 +[ 22827ms] VEN_0488&Col02 len=20: 01 03 15 04 e0 01 00 00 00 00 00 00 00 00 00 00 22 50 01 00 +[ 22834ms] VEN_0488&Col02 len=20: 01 03 33 04 df 01 00 00 00 00 00 00 00 00 00 00 68 50 01 00 +[ 22841ms] VEN_0488&Col02 len=20: 01 03 4c 04 de 01 00 00 00 00 00 00 00 00 00 00 ae 50 01 00 +[ 22848ms] VEN_0488&Col02 len=20: 01 03 65 04 de 01 00 00 00 00 00 00 00 00 00 00 f4 50 01 00 +[ 22855ms] VEN_0488&Col02 len=20: 01 03 7d 04 de 01 00 00 00 00 00 00 00 00 00 00 3a 51 01 00 +[ 22862ms] VEN_0488&Col02 len=20: 01 03 93 04 dd 01 00 00 00 00 00 00 00 00 00 00 80 51 01 00 +[ 22869ms] VEN_0488&Col02 len=20: 01 03 aa 04 dd 01 00 00 00 00 00 00 00 00 00 00 c6 51 01 00 +[ 22876ms] VEN_0488&Col02 len=20: 01 03 be 04 dd 01 00 00 00 00 00 00 00 00 00 00 0c 52 01 00 +[ 22884ms] VEN_0488&Col02 len=20: 01 03 d1 04 dd 01 00 00 00 00 00 00 00 00 00 00 52 52 01 00 +[ 22891ms] VEN_0488&Col02 len=20: 01 03 e6 04 dd 01 00 00 00 00 00 00 00 00 00 00 98 52 01 00 +[ 22898ms] VEN_0488&Col02 len=20: 01 03 f7 04 dd 01 00 00 00 00 00 00 00 00 00 00 de 52 01 00 +[ 22905ms] VEN_0488&Col02 len=20: 01 03 09 05 dd 01 00 00 00 00 00 00 00 00 00 00 24 53 01 00 +[ 22912ms] VEN_0488&Col02 len=20: 01 03 1a 05 dd 01 00 00 00 00 00 00 00 00 00 00 6a 53 01 00 +[ 22919ms] VEN_0488&Col02 len=20: 01 03 29 05 dd 01 00 00 00 00 00 00 00 00 00 00 b0 53 01 00 +[ 22926ms] VEN_0488&Col02 len=20: 01 03 33 05 dd 01 00 00 00 00 00 00 00 00 00 00 f6 53 01 00 +[ 22933ms] VEN_0488&Col02 len=20: 01 03 3d 05 dd 01 00 00 00 00 00 00 00 00 00 00 3c 54 01 00 +[ 22940ms] VEN_0488&Col02 len=20: 01 03 46 05 dd 01 00 00 00 00 00 00 00 00 00 00 82 54 01 00 +[ 22947ms] VEN_0488&Col02 len=20: 01 03 4c 05 dc 01 00 00 00 00 00 00 00 00 00 00 c8 54 01 00 +[ 22954ms] VEN_0488&Col02 len=20: 01 03 51 05 dc 01 00 00 00 00 00 00 00 00 00 00 0e 55 01 00 +[ 22961ms] VEN_0488&Col02 len=20: 01 03 55 05 dc 01 00 00 00 00 00 00 00 00 00 00 54 55 01 00 +[ 22968ms] VEN_0488&Col02 len=20: 01 03 56 05 db 01 00 00 00 00 00 00 00 00 00 00 9a 55 01 00 +[ 22975ms] VEN_0488&Col02 len=20: 01 03 56 05 db 01 00 00 00 00 00 00 00 00 00 00 e0 55 01 00 +[ 22982ms] VEN_0488&Col02 len=20: 01 03 56 05 db 01 00 00 00 00 00 00 00 00 00 00 26 56 01 00 +[ 22989ms] VEN_0488&Col02 len=20: 01 03 56 05 db 01 00 00 00 00 00 00 00 00 00 00 6c 56 01 00 +[ 22996ms] VEN_0488&Col02 len=20: 01 03 55 05 db 01 00 00 00 00 00 00 00 00 00 00 b2 56 01 00 +[ 23003ms] VEN_0488&Col02 len=20: 01 03 55 05 db 01 00 00 00 00 00 00 00 00 00 00 f8 56 01 00 +[ 23011ms] VEN_0488&Col02 len=20: 01 03 54 05 db 01 00 00 00 00 00 00 00 00 00 00 3e 57 01 00 +[ 23017ms] VEN_0488&Col02 len=20: 01 03 53 05 db 01 00 00 00 00 00 00 00 00 00 00 84 57 01 00 +[ 23024ms] VEN_0488&Col02 len=20: 01 03 52 05 db 01 00 00 00 00 00 00 00 00 00 00 ca 57 01 00 +[ 23032ms] VEN_0488&Col02 len=20: 01 03 51 05 dc 01 00 00 00 00 00 00 00 00 00 00 10 58 01 00 +[ 23039ms] VEN_0488&Col02 len=20: 01 03 4f 05 dc 01 00 00 00 00 00 00 00 00 00 00 56 58 01 00 +[ 23046ms] VEN_0488&Col02 len=20: 01 03 4d 05 dc 01 00 00 00 00 00 00 00 00 00 00 9c 58 01 00 +[ 23053ms] VEN_0488&Col02 len=20: 01 03 49 05 db 01 00 00 00 00 00 00 00 00 00 00 e2 58 01 00 +[ 23060ms] VEN_0488&Col02 len=20: 01 03 40 05 da 01 00 00 00 00 00 00 00 00 00 00 28 59 01 00 +[ 23067ms] VEN_0488&Col02 len=20: 01 03 34 05 da 01 00 00 00 00 00 00 00 00 00 00 6e 59 01 00 +[ 23075ms] VEN_0488&Col02 len=20: 01 03 25 05 d9 01 00 00 00 00 00 00 00 00 00 00 b4 59 01 00 +[ 23081ms] VEN_0488&Col02 len=20: 01 03 15 05 d8 01 00 00 00 00 00 00 00 00 00 00 fa 59 01 00 +[ 23088ms] VEN_0488&Col02 len=20: 01 03 04 05 d7 01 00 00 00 00 00 00 00 00 00 00 40 5a 01 00 +[ 23095ms] VEN_0488&Col02 len=20: 01 03 f3 04 d7 01 00 00 00 00 00 00 00 00 00 00 86 5a 01 00 +[ 23102ms] VEN_0488&Col02 len=20: 01 03 e4 04 d6 01 00 00 00 00 00 00 00 00 00 00 cc 5a 01 00 +[ 23109ms] VEN_0488&Col02 len=20: 01 03 cf 04 d5 01 00 00 00 00 00 00 00 00 00 00 12 5b 01 00 +[ 23116ms] VEN_0488&Col02 len=20: 01 03 b9 04 d5 01 00 00 00 00 00 00 00 00 00 00 58 5b 01 00 +[ 23123ms] VEN_0488&Col02 len=20: 01 03 a6 04 d5 01 00 00 00 00 00 00 00 00 00 00 9e 5b 01 00 +[ 23130ms] VEN_0488&Col02 len=20: 01 03 91 04 d5 01 00 00 00 00 00 00 00 00 00 00 e4 5b 01 00 +[ 23138ms] VEN_0488&Col02 len=20: 01 03 7a 04 d5 01 00 00 00 00 00 00 00 00 00 00 2a 5c 01 00 +[ 23144ms] VEN_0488&Col02 len=20: 01 03 66 04 d5 01 00 00 00 00 00 00 00 00 00 00 70 5c 01 00 +[ 23152ms] VEN_0488&Col02 len=20: 01 03 50 04 d4 01 00 00 00 00 00 00 00 00 00 00 b6 5c 01 00 +[ 23159ms] VEN_0488&Col02 len=20: 01 03 3a 04 d4 01 00 00 00 00 00 00 00 00 00 00 fc 5c 01 00 +[ 23166ms] VEN_0488&Col02 len=20: 01 03 24 04 d4 01 00 00 00 00 00 00 00 00 00 00 42 5d 01 00 +[ 23173ms] VEN_0488&Col02 len=20: 01 03 0d 04 d4 01 00 00 00 00 00 00 00 00 00 00 88 5d 01 00 +[ 23180ms] VEN_0488&Col02 len=20: 01 03 f6 03 d3 01 00 00 00 00 00 00 00 00 00 00 ce 5d 01 00 +[ 23187ms] VEN_0488&Col02 len=20: 01 03 e0 03 d2 01 00 00 00 00 00 00 00 00 00 00 14 5e 01 00 +[ 23194ms] VEN_0488&Col02 len=20: 01 03 c8 03 d1 01 00 00 00 00 00 00 00 00 00 00 5a 5e 01 00 +[ 23201ms] VEN_0488&Col02 len=20: 01 03 b2 03 d0 01 00 00 00 00 00 00 00 00 00 00 a0 5e 01 00 +[ 23208ms] VEN_0488&Col02 len=20: 01 03 9c 03 cf 01 00 00 00 00 00 00 00 00 00 00 e6 5e 01 00 +[ 23215ms] VEN_0488&Col02 len=20: 01 03 85 03 cf 01 00 00 00 00 00 00 00 00 00 00 2c 5f 01 00 +[ 23222ms] VEN_0488&Col02 len=20: 01 03 6f 03 cd 01 00 00 00 00 00 00 00 00 00 00 72 5f 01 00 +[ 23229ms] VEN_0488&Col02 len=20: 01 03 57 03 cc 01 00 00 00 00 00 00 00 00 00 00 b8 5f 01 00 +[ 23236ms] VEN_0488&Col02 len=20: 01 03 3f 03 cc 01 00 00 00 00 00 00 00 00 00 00 fe 5f 01 00 +[ 23243ms] VEN_0488&Col02 len=20: 01 03 28 03 cb 01 00 00 00 00 00 00 00 00 00 00 44 60 01 00 +[ 23250ms] VEN_0488&Col02 len=20: 01 03 11 03 ca 01 00 00 00 00 00 00 00 00 00 00 8a 60 01 00 +[ 23257ms] VEN_0488&Col02 len=20: 01 03 fd 02 c9 01 00 00 00 00 00 00 00 00 00 00 d0 60 01 00 +[ 23264ms] VEN_0488&Col02 len=20: 01 03 e5 02 c8 01 00 00 00 00 00 00 00 00 00 00 16 61 01 00 +[ 23272ms] VEN_0488&Col02 len=20: 01 03 cd 02 c7 01 00 00 00 00 00 00 00 00 00 00 5c 61 01 00 +[ 23279ms] VEN_0488&Col02 len=20: 01 03 b4 02 c6 01 00 00 00 00 00 00 00 00 00 00 a2 61 01 00 +[ 23286ms] VEN_0488&Col02 len=20: 01 03 99 02 c6 01 00 00 00 00 00 00 00 00 00 00 e8 61 01 00 +[ 23293ms] VEN_0488&Col02 len=20: 01 03 80 02 c4 01 00 00 00 00 00 00 00 00 00 00 2e 62 01 00 +[ 23300ms] VEN_0488&Col02 len=20: 01 03 6a 02 c3 01 00 00 00 00 00 00 00 00 00 00 74 62 01 00 +[ 23307ms] VEN_0488&Col02 len=20: 01 03 52 02 c2 01 00 00 00 00 00 00 00 00 00 00 ba 62 01 00 +[ 23314ms] VEN_0488&Col02 len=20: 01 03 3b 02 c1 01 00 00 00 00 00 00 00 00 00 00 00 63 01 00 +[ 23321ms] VEN_0488&Col02 len=20: 01 03 25 02 c1 01 00 00 00 00 00 00 00 00 00 00 46 63 01 00 +[ 23328ms] VEN_0488&Col02 len=20: 01 03 0e 02 bf 01 00 00 00 00 00 00 00 00 00 00 8c 63 01 00 +[ 23335ms] VEN_0488&Col02 len=20: 01 03 fa 01 bf 01 00 00 00 00 00 00 00 00 00 00 d2 63 01 00 +[ 23342ms] VEN_0488&Col02 len=20: 01 03 e2 01 c0 01 00 00 00 00 00 00 00 00 00 00 18 64 01 00 +[ 23349ms] VEN_0488&Col02 len=20: 01 03 ce 01 c0 01 00 00 00 00 00 00 00 00 00 00 5e 64 01 00 +[ 23356ms] VEN_0488&Col02 len=20: 01 03 be 01 c0 01 00 00 00 00 00 00 00 00 00 00 a4 64 01 00 +[ 23363ms] VEN_0488&Col02 len=20: 01 03 ab 01 c1 01 00 00 00 00 00 00 00 00 00 00 ea 64 01 00 +[ 23370ms] VEN_0488&Col02 len=20: 01 03 9b 01 c4 01 00 00 00 00 00 00 00 00 00 00 30 65 01 00 +[ 23378ms] VEN_0488&Col02 len=20: 01 03 8d 01 c7 01 00 00 00 00 00 00 00 00 00 00 76 65 01 00 +[ 23385ms] VEN_0488&Col02 len=20: 01 03 81 01 c6 01 00 00 00 00 00 00 00 00 00 00 bc 65 01 00 +[ 23391ms] VEN_0488&Col02 len=20: 01 03 77 01 c7 01 00 00 00 00 00 00 00 00 00 00 02 66 01 00 +[ 23399ms] VEN_0488&Col02 len=20: 01 03 70 01 c7 01 00 00 00 00 00 00 00 00 00 00 48 66 01 00 +[ 23406ms] VEN_0488&Col02 len=20: 01 03 6c 01 c8 01 00 00 00 00 00 00 00 00 00 00 8e 66 01 00 +[ 23413ms] VEN_0488&Col02 len=20: 01 03 6c 01 c8 01 00 00 00 00 00 00 00 00 00 00 d4 66 01 00 +[ 23420ms] VEN_0488&Col02 len=20: 01 03 6c 01 c7 01 00 00 00 00 00 00 00 00 00 00 1a 67 01 00 +[ 23427ms] VEN_0488&Col02 len=20: 01 03 6c 01 c7 01 00 00 00 00 00 00 00 00 00 00 60 67 01 00 +[ 23434ms] VEN_0488&Col02 len=20: 01 03 6d 01 c7 01 00 00 00 00 00 00 00 00 00 00 a6 67 01 00 +[ 23441ms] VEN_0488&Col02 len=20: 01 03 6d 01 c7 01 00 00 00 00 00 00 00 00 00 00 ec 67 01 00 +[ 23448ms] VEN_0488&Col02 len=20: 01 03 6e 01 c7 01 00 00 00 00 00 00 00 00 00 00 32 68 01 00 +[ 23455ms] VEN_0488&Col02 len=20: 01 03 71 01 c7 01 00 00 00 00 00 00 00 00 00 00 78 68 01 00 +[ 23462ms] VEN_0488&Col02 len=20: 01 03 72 01 c7 01 00 00 00 00 00 00 00 00 00 00 be 68 01 00 +[ 23469ms] VEN_0488&Col02 len=20: 01 03 75 01 c7 01 00 00 00 00 00 00 00 00 00 00 04 69 01 00 +[ 23476ms] VEN_0488&Col02 len=20: 01 03 78 01 c7 01 00 00 00 00 00 00 00 00 00 00 4a 69 01 00 +[ 23483ms] VEN_0488&Col02 len=20: 01 03 81 01 c7 01 00 00 00 00 00 00 00 00 00 00 90 69 01 00 +[ 23490ms] VEN_0488&Col02 len=20: 01 03 8e 01 c7 01 00 00 00 00 00 00 00 00 00 00 d6 69 01 00 +[ 23497ms] VEN_0488&Col02 len=20: 01 03 9a 01 c6 01 00 00 00 00 00 00 00 00 00 00 1c 6a 01 00 +[ 23504ms] VEN_0488&Col02 len=20: 01 03 ab 01 c6 01 00 00 00 00 00 00 00 00 00 00 62 6a 01 00 +[ 23512ms] VEN_0488&Col02 len=20: 01 03 bc 01 c6 01 00 00 00 00 00 00 00 00 00 00 a8 6a 01 00 +[ 23519ms] VEN_0488&Col02 len=20: 01 03 cf 01 c6 01 00 00 00 00 00 00 00 00 00 00 ee 6a 01 00 +[ 23526ms] VEN_0488&Col02 len=20: 01 03 e0 01 c6 01 00 00 00 00 00 00 00 00 00 00 34 6b 01 00 +[ 23533ms] VEN_0488&Col02 len=20: 01 03 f6 01 c5 01 00 00 00 00 00 00 00 00 00 00 7a 6b 01 00 +[ 23540ms] VEN_0488&Col02 len=20: 01 03 0b 02 c5 01 00 00 00 00 00 00 00 00 00 00 c0 6b 01 00 +[ 23547ms] VEN_0488&Col02 len=20: 01 03 1c 02 c5 01 00 00 00 00 00 00 00 00 00 00 06 6c 01 00 +[ 23554ms] VEN_0488&Col02 len=20: 01 03 32 02 c4 01 00 00 00 00 00 00 00 00 00 00 4c 6c 01 00 +[ 23561ms] VEN_0488&Col02 len=20: 01 03 44 02 c3 01 00 00 00 00 00 00 00 00 00 00 92 6c 01 00 +[ 23568ms] VEN_0488&Col02 len=20: 01 03 57 02 c3 01 00 00 00 00 00 00 00 00 00 00 d8 6c 01 00 +[ 23575ms] VEN_0488&Col02 len=20: 01 03 70 02 c3 01 00 00 00 00 00 00 00 00 00 00 1e 6d 01 00 +[ 23582ms] VEN_0488&Col02 len=20: 01 03 86 02 c2 01 00 00 00 00 00 00 00 00 00 00 64 6d 01 00 +[ 23589ms] VEN_0488&Col02 len=20: 01 03 9b 02 c2 01 00 00 00 00 00 00 00 00 00 00 aa 6d 01 00 +[ 23596ms] VEN_0488&Col02 len=20: 01 03 b3 02 c1 01 00 00 00 00 00 00 00 00 00 00 f0 6d 01 00 +[ 23603ms] VEN_0488&Col02 len=20: 01 03 cc 02 bf 01 00 00 00 00 00 00 00 00 00 00 36 6e 01 00 +[ 23611ms] VEN_0488&Col02 len=20: 01 03 e4 02 bf 01 00 00 00 00 00 00 00 00 00 00 7c 6e 01 00 +[ 23617ms] VEN_0488&Col02 len=20: 01 03 ff 02 bd 01 00 00 00 00 00 00 00 00 00 00 c2 6e 01 00 +[ 23625ms] VEN_0488&Col02 len=20: 01 03 16 03 bd 01 00 00 00 00 00 00 00 00 00 00 08 6f 01 00 +[ 23632ms] VEN_0488&Col02 len=20: 01 03 31 03 bd 01 00 00 00 00 00 00 00 00 00 00 4e 6f 01 00 +[ 23639ms] VEN_0488&Col02 len=20: 01 03 4a 03 bd 01 00 00 00 00 00 00 00 00 00 00 94 6f 01 00 +[ 23646ms] VEN_0488&Col02 len=20: 01 03 63 03 bd 01 00 00 00 00 00 00 00 00 00 00 da 6f 01 00 +[ 23653ms] VEN_0488&Col02 len=20: 01 03 7e 03 bd 01 00 00 00 00 00 00 00 00 00 00 20 70 01 00 +[ 23660ms] VEN_0488&Col02 len=20: 01 03 97 03 bd 01 00 00 00 00 00 00 00 00 00 00 66 70 01 00 +[ 23667ms] VEN_0488&Col02 len=20: 01 03 b4 03 bc 01 00 00 00 00 00 00 00 00 00 00 ac 70 01 00 +[ 23674ms] VEN_0488&Col02 len=20: 01 03 ce 03 bc 01 00 00 00 00 00 00 00 00 00 00 f2 70 01 00 +[ 23681ms] VEN_0488&Col02 len=20: 01 03 e9 03 bc 01 00 00 00 00 00 00 00 00 00 00 38 71 01 00 +[ 23688ms] VEN_0488&Col02 len=20: 01 03 03 04 bb 01 00 00 00 00 00 00 00 00 00 00 7e 71 01 00 +[ 23695ms] VEN_0488&Col02 len=20: 01 03 1d 04 bb 01 00 00 00 00 00 00 00 00 00 00 c4 71 01 00 +[ 23702ms] VEN_0488&Col02 len=20: 01 03 39 04 bb 01 00 00 00 00 00 00 00 00 00 00 0a 72 01 00 +[ 23709ms] VEN_0488&Col02 len=20: 01 03 51 04 bb 01 00 00 00 00 00 00 00 00 00 00 50 72 01 00 +[ 23716ms] VEN_0488&Col02 len=20: 01 03 68 04 bb 01 00 00 00 00 00 00 00 00 00 00 96 72 01 00 +[ 23724ms] VEN_0488&Col02 len=20: 01 03 7e 04 bb 01 00 00 00 00 00 00 00 00 00 00 dc 72 01 00 +[ 23731ms] VEN_0488&Col02 len=20: 01 03 95 04 bb 01 00 00 00 00 00 00 00 00 00 00 22 73 01 00 +[ 23738ms] VEN_0488&Col02 len=20: 01 03 ad 04 bb 01 00 00 00 00 00 00 00 00 00 00 68 73 01 00 +[ 23745ms] VEN_0488&Col02 len=20: 01 03 c1 04 bb 01 00 00 00 00 00 00 00 00 00 00 ae 73 01 00 +[ 23752ms] VEN_0488&Col02 len=20: 01 03 d4 04 bb 01 00 00 00 00 00 00 00 00 00 00 f4 73 01 00 +[ 23759ms] VEN_0488&Col02 len=20: 01 03 e9 04 bb 01 00 00 00 00 00 00 00 00 00 00 3a 74 01 00 +[ 23766ms] VEN_0488&Col02 len=20: 01 03 fa 04 bc 01 00 00 00 00 00 00 00 00 00 00 80 74 01 00 +[ 23773ms] VEN_0488&Col02 len=20: 01 03 0a 05 bc 01 00 00 00 00 00 00 00 00 00 00 c6 74 01 00 +[ 23780ms] VEN_0488&Col02 len=20: 01 03 17 05 bc 01 00 00 00 00 00 00 00 00 00 00 0c 75 01 00 +[ 23787ms] VEN_0488&Col02 len=20: 01 03 24 05 bc 01 00 00 00 00 00 00 00 00 00 00 52 75 01 00 +[ 23794ms] VEN_0488&Col02 len=20: 01 03 2f 05 bc 01 00 00 00 00 00 00 00 00 00 00 98 75 01 00 +[ 23801ms] VEN_0488&Col02 len=20: 01 03 35 05 bc 01 00 00 00 00 00 00 00 00 00 00 de 75 01 00 +[ 23808ms] VEN_0488&Col02 len=20: 01 03 3c 05 bc 01 00 00 00 00 00 00 00 00 00 00 24 76 01 00 +[ 23815ms] VEN_0488&Col02 len=20: 01 03 3f 05 bc 01 00 00 00 00 00 00 00 00 00 00 6a 76 01 00 +[ 23822ms] VEN_0488&Col02 len=20: 01 03 40 05 bc 01 00 00 00 00 00 00 00 00 00 00 b0 76 01 00 +[ 23829ms] VEN_0488&Col02 len=20: 01 03 41 05 bc 01 00 00 00 00 00 00 00 00 00 00 f6 76 01 00 +[ 23836ms] VEN_0488&Col02 len=20: 01 03 41 05 bc 01 00 00 00 00 00 00 00 00 00 00 3c 77 01 00 +[ 23843ms] VEN_0488&Col02 len=20: 01 03 41 05 bc 01 00 00 00 00 00 00 00 00 00 00 82 77 01 00 +[ 23850ms] VEN_0488&Col02 len=20: 01 03 40 05 bc 01 00 00 00 00 00 00 00 00 00 00 c8 77 01 00 +[ 23858ms] VEN_0488&Col02 len=20: 01 03 3f 05 bc 01 00 00 00 00 00 00 00 00 00 00 0e 78 01 00 +[ 23865ms] VEN_0488&Col02 len=20: 01 03 3e 05 bc 01 00 00 00 00 00 00 00 00 00 00 54 78 01 00 +[ 23872ms] VEN_0488&Col02 len=20: 01 03 3d 05 bc 01 00 00 00 00 00 00 00 00 00 00 9a 78 01 00 +[ 23879ms] VEN_0488&Col02 len=20: 01 03 3a 05 bd 01 00 00 00 00 00 00 00 00 00 00 e0 78 01 00 +[ 23886ms] VEN_0488&Col02 len=20: 01 03 38 05 bd 01 00 00 00 00 00 00 00 00 00 00 26 79 01 00 +[ 23893ms] VEN_0488&Col02 len=20: 01 03 35 05 bd 01 00 00 00 00 00 00 00 00 00 00 6c 79 01 00 +[ 23900ms] VEN_0488&Col02 len=20: 01 03 2f 05 bd 01 00 00 00 00 00 00 00 00 00 00 b2 79 01 00 +[ 23907ms] VEN_0488&Col02 len=20: 01 03 22 05 bd 01 00 00 00 00 00 00 00 00 00 00 f8 79 01 00 +[ 23914ms] VEN_0488&Col02 len=20: 01 03 0f 05 bd 01 00 00 00 00 00 00 00 00 00 00 3e 7a 01 00 +[ 23921ms] VEN_0488&Col02 len=20: 01 03 fa 04 bd 01 00 00 00 00 00 00 00 00 00 00 84 7a 01 00 +[ 23929ms] VEN_0488&Col02 len=20: 01 03 e9 04 be 01 00 00 00 00 00 00 00 00 00 00 ca 7a 01 00 +[ 23935ms] VEN_0488&Col02 len=20: 01 03 d3 04 be 01 00 00 00 00 00 00 00 00 00 00 10 7b 01 00 +[ 23942ms] VEN_0488&Col02 len=20: 01 03 ba 04 be 01 00 00 00 00 00 00 00 00 00 00 56 7b 01 00 +[ 23949ms] VEN_0488&Col02 len=20: 01 03 a4 04 bf 01 00 00 00 00 00 00 00 00 00 00 9c 7b 01 00 +[ 23957ms] VEN_0488&Col02 len=20: 01 03 88 04 bf 01 00 00 00 00 00 00 00 00 00 00 e2 7b 01 00 +[ 23963ms] VEN_0488&Col02 len=20: 01 03 6f 04 c0 01 00 00 00 00 00 00 00 00 00 00 28 7c 01 00 +[ 23971ms] VEN_0488&Col02 len=20: 01 03 56 04 c0 01 00 00 00 00 00 00 00 00 00 00 6e 7c 01 00 +[ 23978ms] VEN_0488&Col02 len=20: 01 03 3c 04 c0 01 00 00 00 00 00 00 00 00 00 00 b4 7c 01 00 +[ 23985ms] VEN_0488&Col02 len=20: 01 03 24 04 c1 01 00 00 00 00 00 00 00 00 00 00 fa 7c 01 00 +[ 23992ms] VEN_0488&Col02 len=20: 01 03 0a 04 c1 01 00 00 00 00 00 00 00 00 00 00 40 7d 01 00 +[ 23999ms] VEN_0488&Col02 len=20: 01 03 f2 03 c1 01 00 00 00 00 00 00 00 00 00 00 86 7d 01 00 +[ 24006ms] VEN_0488&Col02 len=20: 01 03 de 03 c1 01 00 00 00 00 00 00 00 00 00 00 cc 7d 01 00 +[ 24013ms] VEN_0488&Col02 len=20: 01 03 c7 03 c1 01 00 00 00 00 00 00 00 00 00 00 12 7e 01 00 +[ 24020ms] VEN_0488&Col02 len=20: 01 03 b5 03 c0 01 00 00 00 00 00 00 00 00 00 00 58 7e 01 00 +[ 24027ms] VEN_0488&Col02 len=20: 01 03 a4 03 bf 01 00 00 00 00 00 00 00 00 00 00 9e 7e 01 00 +[ 24034ms] VEN_0488&Col02 len=20: 01 03 93 03 bc 01 00 00 00 00 00 00 00 00 00 00 e4 7e 01 00 +[ 24041ms] VEN_0488&Col02 len=20: 01 03 85 03 ba 01 00 00 00 00 00 00 00 00 00 00 2a 7f 01 00 +[ 24048ms] VEN_0488&Col02 len=20: 01 03 78 03 b8 01 00 00 00 00 00 00 00 00 00 00 70 7f 01 00 +[ 24055ms] VEN_0488&Col02 len=20: 01 03 6d 03 b5 01 00 00 00 00 00 00 00 00 00 00 b6 7f 01 00 +[ 24062ms] VEN_0488&Col02 len=20: 01 03 64 03 b5 01 00 00 00 00 00 00 00 00 00 00 fc 7f 01 00 +[ 24069ms] VEN_0488&Col02 len=20: 01 03 5d 03 b2 01 00 00 00 00 00 00 00 00 00 00 42 80 01 00 +[ 24076ms] VEN_0488&Col02 len=20: 01 03 59 03 b2 01 00 00 00 00 00 00 00 00 00 00 88 80 01 00 +[ 24084ms] VEN_0488&Col02 len=20: 01 03 56 03 b1 01 00 00 00 00 00 00 00 00 00 00 ce 80 01 00 +[ 24091ms] VEN_0488&Col02 len=20: 01 03 56 03 b0 01 00 00 00 00 00 00 00 00 00 00 14 81 01 00 +[ 24098ms] VEN_0488&Col02 len=20: 01 03 56 03 af 01 00 00 00 00 00 00 00 00 00 00 5a 81 01 00 +[ 24105ms] VEN_0488&Col02 len=20: 01 03 56 03 af 01 00 00 00 00 00 00 00 00 00 00 a0 81 01 00 +[ 24112ms] VEN_0488&Col02 len=20: 01 03 56 03 ae 01 00 00 00 00 00 00 00 00 00 00 e6 81 01 00 +[ 24119ms] VEN_0488&Col02 len=20: 01 03 57 03 ae 01 00 00 00 00 00 00 00 00 00 00 2c 82 01 00 +[ 24126ms] VEN_0488&Col02 len=20: 01 03 58 03 ae 01 00 00 00 00 00 00 00 00 00 00 72 82 01 00 +[ 24133ms] VEN_0488&Col02 len=20: 01 03 59 03 ae 01 00 00 00 00 00 00 00 00 00 00 b8 82 01 00 +[ 24140ms] VEN_0488&Col02 len=20: 01 03 5c 03 ae 01 00 00 00 00 00 00 00 00 00 00 fe 82 01 00 +[ 24147ms] VEN_0488&Col02 len=20: 01 03 5e 03 af 01 00 00 00 00 00 00 00 00 00 00 44 83 01 00 +[ 24154ms] VEN_0488&Col02 len=20: 01 03 61 03 b0 01 00 00 00 00 00 00 00 00 00 00 8a 83 01 00 +[ 24161ms] VEN_0488&Col02 len=20: 01 03 65 03 b3 01 00 00 00 00 00 00 00 00 00 00 d0 83 01 00 +[ 24168ms] VEN_0488&Col02 len=20: 01 03 6d 03 b6 01 00 00 00 00 00 00 00 00 00 00 16 84 01 00 +[ 24175ms] VEN_0488&Col02 len=20: 01 03 7d 03 b9 01 00 00 00 00 00 00 00 00 00 00 5c 84 01 00 +[ 24182ms] VEN_0488&Col02 len=20: 01 03 90 03 c0 01 00 00 00 00 00 00 00 00 00 00 a2 84 01 00 +[ 24189ms] VEN_0488&Col02 len=20: 01 03 a8 03 c7 01 00 00 00 00 00 00 00 00 00 00 e8 84 01 00 +[ 24197ms] VEN_0488&Col02 len=20: 01 03 c2 03 d2 01 00 00 00 00 00 00 00 00 00 00 2e 85 01 00 +[ 24204ms] VEN_0488&Col02 len=20: 01 03 dd 03 dd 01 00 00 00 00 00 00 00 00 00 00 74 85 01 00 +[ 24211ms] VEN_0488&Col02 len=20: 01 03 fc 03 ea 01 00 00 00 00 00 00 00 00 00 00 ba 85 01 00 +[ 24218ms] VEN_0488&Col02 len=20: 01 01 fc 03 ea 01 00 00 00 00 00 00 00 00 00 00 00 86 01 00 +raw-input tap closed diff --git a/docs/mx-master-4-panel-captures/openlogi-diag-panel-arm-confirmed.txt b/docs/mx-master-4-panel-captures/openlogi-diag-panel-arm-confirmed.txt new file mode 100644 index 00000000..c6219301 --- /dev/null +++ b/docs/mx-master-4-panel-captures/openlogi-diag-panel-arm-confirmed.txt @@ -0,0 +1,14 @@ +2026-07-20T08:13:11.228787Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T08:13:14.270630Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T08:13:17.287740Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +device: MX Master 4 (slot 2 on receiver 97B76948A846C55A) +arming Action Ring panel (analytics on CIDs 0x0050/0x0051) — press it now, 75s window + +[watch_panel] 0x1b04 feature index = 13 +[watch_panel] force-sensing feature present = true +[watch_panel] force threshold set -> [00, 15, a3, 00] +[watch_panel] analytics armed on 0x0050 +[watch_panel] analytics armed on 0x0051 + +0 panel event(s) captured. +none seen — was the mouse moving while arming? is Options+ holding the device? diff --git a/docs/mx-master-4-panel-captures/openlogi-panel-confirmed-clean.txt b/docs/mx-master-4-panel-captures/openlogi-panel-confirmed-clean.txt new file mode 100644 index 00000000..93216a05 --- /dev/null +++ b/docs/mx-master-4-panel-captures/openlogi-panel-confirmed-clean.txt @@ -0,0 +1,62 @@ +2026-07-20T09:07:57.848262Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T09:08:00.880293Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T09:08:03.885247Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +device: MX Master 4 (slot 2 on receiver 97B76948A846C55A) +arming Action Ring panel (analytics on CIDs 0x0050/0x0051) — press it now, 150s window + +[watch_panel] 0x1b04 feature index = 13 +[watch_panel] force-sensing feature present = true +[watch_panel] force threshold set -> [00, 15, a3, 00] +[watch_panel] analytics armed on 0x01a0 +[watch_panel] analytics armed on 0x0050 +[watch_panel] analytics armed on 0x0051 + [ 1] panel cid=0x0050 PRESS (event=0x01) + [ 2] panel cid=0x0050 RELEASE (event=0x00) + [ 3] panel cid=0x0050 PRESS (event=0x01) + [ 4] panel cid=0x0050 RELEASE (event=0x00) + [ 5] panel cid=0x0050 PRESS (event=0x01) + [ 6] panel cid=0x0050 RELEASE (event=0x00) + [ 7] panel cid=0x0050 PRESS (event=0x01) + [ 8] panel cid=0x0050 RELEASE (event=0x00) + [ 9] panel cid=0x0050 PRESS (event=0x01) + [ 10] panel cid=0x0050 RELEASE (event=0x00) + [ 11] panel cid=0x0050 PRESS (event=0x01) + [ 12] panel cid=0x0050 RELEASE (event=0x00) + [ 13] panel cid=0x0050 PRESS (event=0x01) + [ 14] panel cid=0x0050 RELEASE (event=0x00) + [ 15] panel cid=0x0050 PRESS (event=0x01) + [ 16] panel cid=0x0050 RELEASE (event=0x00) + [ 17] panel cid=0x0050 PRESS (event=0x01) + [ 18] panel cid=0x0050 RELEASE (event=0x00) + [ 19] panel cid=0x01a0 PRESS (event=0x01) + [ 20] panel cid=0x01a0 RELEASE (event=0x00) + [ 21] panel cid=0x01a0 PRESS (event=0x01) + [ 22] panel cid=0x01a0 RELEASE (event=0x00) + [ 23] panel cid=0x01a0 PRESS (event=0x01) + [ 24] panel cid=0x01a0 RELEASE (event=0x00) + [ 25] panel cid=0x01a0 PRESS (event=0x01) + [ 26] panel cid=0x01a0 RELEASE (event=0x00) + [ 27] panel cid=0x01a0 PRESS (event=0x01) + [ 28] panel cid=0x01a0 RELEASE (event=0x00) + [ 29] panel cid=0x01a0 PRESS (event=0x01) + [ 30] panel cid=0x01a0 RELEASE (event=0x00) + [ 31] panel cid=0x01a0 PRESS (event=0x01) + [ 32] panel cid=0x01a0 RELEASE (event=0x00) + [ 33] panel cid=0x01a0 PRESS (event=0x01) + [ 34] panel cid=0x01a0 RELEASE (event=0x00) + [ 35] panel cid=0x01a0 PRESS (event=0x01) + [ 36] panel cid=0x01a0 RELEASE (event=0x00) + [ 37] panel cid=0x01a0 PRESS (event=0x01) + [ 38] panel cid=0x01a0 RELEASE (event=0x00) + [ 39] panel cid=0x01a0 PRESS (event=0x01) + [ 40] panel cid=0x01a0 RELEASE (event=0x00) + [ 41] panel cid=0x01a0 PRESS (event=0x01) + [ 42] panel cid=0x01a0 RELEASE (event=0x00) + [ 43] panel cid=0x01a0 PRESS (event=0x01) + [ 44] panel cid=0x01a0 RELEASE (event=0x00) + [ 45] panel cid=0x01a0 PRESS (event=0x01) + [ 46] panel cid=0x01a0 RELEASE (event=0x00) + [ 47] panel cid=0x01a0 PRESS (event=0x01) + [ 48] panel cid=0x01a0 RELEASE (event=0x00) + +48 panel event(s) captured. diff --git a/docs/mx-master-4-panel-captures/optionsplus-coldstart-full.txt b/docs/mx-master-4-panel-captures/optionsplus-coldstart-full.txt new file mode 100644 index 00000000..0cc5830e --- /dev/null +++ b/docs/mx-master-4-panel-captures/optionsplus-coldstart-full.txt @@ -0,0 +1,315 @@ +raw-input tap live for 75 s — pages 0x0D digitizer, 0x0E haptics, 0xFF00/0xFF43 vendor +device hdev=10077: \\?\HID#VID_046D&PID_C548&MI_02&Col02#8&1ce49569&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030} +[ 163ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 282ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 1107ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 1266ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 2023ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 2218ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 2713ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 2826ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3261ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3359ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 4116ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 4205ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 5474ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 5541ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 5623ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 6021ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 6419ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 6486ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 6568ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 6981ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 7415ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 7475ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 7850ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 7963ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 8308ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 8420ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 8990ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +device hdev=10094f: \\?\HID#VID_046D&PID_C539&MI_02&Col01#7&2071e0a2&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} +[ 9000ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 81 00 00 01 00 +[ 9001ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 81 00 00 01 00 +device hdev=1006f: \\?\HID#VID_046D&PID_C548&MI_02&Col01#8&1ce49569&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} +[ 9001ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 81 00 00 09 00 +[ 9003ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 81 02 00 01 00 +[ 9004ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 81 00 00 09 00 +[ 9005ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 01 41 0c 62 79 40 +[ 9006ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 80 02 00 00 00 +[ 9011ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 81 02 00 01 00 +[ 9019ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 02 41 10 02 42 b0 +[ 9021ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 80 02 00 00 00 +device hdev=1006b: \\?\HID#VID_046D&PID_C339&MI_01&Col03#9&17be02e2&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030} +[ 9027ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 00 1c 04 02 39 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 9029ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 02 0c 02 35 31 47 07 00 08 c3 39 00 00 00 00 04 00 00 +[ 9032ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 02 1c 00 55 31 20 13 04 00 19 01 c3 39 00 00 00 00 00 +[ 9035ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 02 1c 00 55 31 20 13 04 00 19 01 c3 39 00 00 00 00 00 +[ 9038ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff ff 02 2c 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 9052ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff ff 02 2c 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 9056ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 02 0c 02 35 31 47 07 00 08 c3 39 00 00 00 00 04 00 00 +[ 9058ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 02 1c 00 55 31 20 13 04 00 19 01 c3 39 00 00 00 00 00 +[ 9061ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 02 1c 00 55 31 20 13 04 00 19 01 c3 39 00 00 00 00 00 +[ 9064ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 02 1c 01 42 4f 54 14 00 c4 b1 00 aa d0 00 00 00 00 00 +[ 9066ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 8f 00 1c 01 00 +device hdev=27909d3: \\?\HID#VID_046D&PID_C539&MI_02&Col02#7&2071e0a2&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030} +[ 9069ms] VID_046D&PID_C539&MI_02&Col02 len=20: 11 ff 83 b5 03 4b f5 94 dc 01 01 07 00 00 00 00 00 00 00 00 +[ 9071ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 81 f1 01 39 06 +[ 9073ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 81 f1 02 00 40 +[ 9089ms] VID_046D&PID_C539&MI_02&Col02 len=20: 11 ff 83 b5 40 06 47 20 50 72 6f 20 00 00 00 00 00 00 00 00 +[ 9093ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 8f 00 1c 01 00 +[ 9096ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 fb 39 37 42 37 36 39 34 38 41 38 34 36 43 35 35 41 +[ 9098ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 01 30 01 00 10 6e 3d 3d a0 00 00 00 00 00 00 00 +[ 9101ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 00 05 05 00 30 18 6a 26 ba 00 00 00 00 00 00 00 +[ 9102ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 05 00 00 01 3e 00 00 00 00 00 00 00 00 00 00 00 +[ 9105ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 02 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 9108ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 8f 83 f4 0b 00 +[ 9110ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 9112ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 fc 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 9125ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 12710ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 12785ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 13739ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 13829ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 15531ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 15605ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 16754ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 16829ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 17871ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 17930ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 18576ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 18636ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 19888ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 20000ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 20624ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 20728ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 21261ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 21366ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 21936ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 22041ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 22971ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 23046ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 24929ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 26999ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 27741ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 28289ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 32470ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 32473ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 32476ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 fb 39 37 42 37 36 39 34 38 41 38 34 36 43 35 35 41 +[ 32479ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 01 30 01 00 10 6e 3d 3d a0 00 00 00 00 00 00 00 +[ 32482ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 00 05 05 00 30 18 6a 26 ba 00 00 00 00 00 00 00 +[ 32486ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 05 00 00 01 3e 00 00 00 00 00 00 00 00 00 00 00 +[ 32487ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 02 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 32491ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 8f 83 f4 0b 00 +[ 32510ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1c 04 05 39 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 32534ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 0c 04 12 c1 78 4d 00 02 b0 42 00 00 00 00 01 01 00 +[ 32556ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1c 00 52 42 4d 27 03 00 19 05 b0 42 03 ce 08 d8 00 +[ 32579ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1c 01 4c 44 00 04 00 00 00 00 00 00 64 2b a1 a1 00 +[ 32601ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1c 00 52 42 4d 27 00 00 15 00 b0 42 f2 1a 37 9a 00 +[ 32616ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1c 00 52 42 4d 27 03 00 19 05 b0 42 03 ce 08 d8 00 +[ 32645ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1c 01 4c 44 00 04 00 00 00 00 00 00 64 2b a1 a1 00 +[ 32661ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 32675ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1c 00 52 42 4d 27 00 00 15 00 b0 42 f2 1a 37 9a 00 +[ 32699ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1c 00 52 42 4d 27 03 00 19 05 b0 42 03 ce 08 d8 00 +[ 32729ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0e 0c 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 32743ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 06 0c 0d 33 21 0b e2 5e 89 8a b5 66 aa 24 cf f7 60 db +[ 32765ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 06 1c b2 c0 e0 33 ff f1 fb c7 19 47 5b 71 f8 79 a1 22 +[ 32778ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 b5 52 02 42 b0 12 c1 78 4d 02 01 80 14 01 00 00 00 +[ 32804ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 0c 04 12 c1 78 4d 00 02 b0 42 00 00 00 00 01 01 00 +[ 32826ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1c 01 4c 44 00 04 00 00 00 00 00 00 64 2b a1 a1 00 +[ 32849ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1c 00 52 42 4d 27 00 00 15 00 b0 42 f2 1a 37 9a 00 +[ 32871ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1c 00 52 42 4d 27 03 00 19 05 b0 42 03 ce 08 d8 00 +[ 32893ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1c 01 4c 44 00 04 00 00 00 00 00 00 64 2b a1 a1 00 +[ 32915ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1c 00 52 42 4d 27 00 00 15 00 b0 42 f2 1a 37 9a 00 +[ 32939ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1c 00 52 42 4d 27 03 00 19 05 b0 42 03 ce 08 d8 00 +[ 32961ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1c 02 48 57 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 32983ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0a 0c 01 00 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33006ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 16 0c 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33062ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff ff 02 2c 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33066ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff ff 02 2c 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33076ms] VID_046D&PID_C539&MI_02&Col02 len=20: 11 ff 83 b5 03 4b f5 94 dc 01 01 07 00 00 00 00 00 00 00 00 +[ 33079ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 8f 83 f5 02 00 +[ 33094ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 fb 39 37 42 37 36 39 34 38 41 38 34 36 43 35 35 41 +[ 33099ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33119ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 09 0c 0f 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33148ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33218ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 01 30 01 00 10 6e 3d 3d a0 00 00 00 00 00 00 00 +[ 33220ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 00 05 05 00 30 18 6a 26 ba 00 00 00 00 00 00 00 +[ 33222ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 05 00 00 01 3e 00 00 00 00 00 00 00 00 00 00 00 +[ 33225ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 02 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33228ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 8f 83 f4 0b 00 +[ 33230ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 01 30 01 00 10 6e 3d 3d a0 00 00 00 00 00 00 00 +[ 33232ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 00 05 05 00 30 18 6a 26 ba 00 00 00 00 00 00 00 +[ 33235ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 05 00 00 01 3e 00 00 00 00 00 00 00 00 00 00 00 +[ 33237ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 02 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33240ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 8f 83 f4 0b 00 +[ 33243ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 01 30 01 00 10 6e 3d 3d a0 00 00 00 00 00 00 00 +[ 33244ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 00 05 05 00 30 18 6a 26 ba 00 00 00 00 00 00 00 +[ 33246ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 05 00 00 01 3e 00 00 00 00 00 00 00 00 00 00 00 +[ 33250ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 02 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33252ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 8f 83 f4 0b 00 +[ 33256ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 01 30 01 00 10 6e 3d 3d a0 00 00 00 00 00 00 00 +[ 33259ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 00 05 05 00 30 18 6a 26 ba 00 00 00 00 00 00 00 +[ 33262ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 05 00 00 01 3e 00 00 00 00 00 00 00 00 00 00 00 +[ 33265ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 02 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33267ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 8f 83 f4 0b 00 +[ 33271ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 fc 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33913ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 0c 00 14 00 78 00 03 03 e8 00 00 00 00 00 00 00 00 +[ 33935ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 1c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33950ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 0c 01 0a 4b 0e 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33965ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 12 3c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33980ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 12 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33996ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 14 2c 00 03 e8 03 e8 00 00 00 00 00 00 00 00 00 00 00 +[ 34019ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0e 2c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34034ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0e 0c 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34049ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0e 0c 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34139ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 81 00 00 09 00 +[ 34153ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 05 0c 36 8f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34168ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 05 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34184ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 05 1c 00 2a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34199ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 52 22 00 52 0b 00 00 00 00 00 00 00 00 00 00 +[ 34220ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 53 22 00 53 0b 00 00 00 00 00 00 00 00 00 00 +[ 34235ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 56 22 00 56 0b 00 00 00 00 00 00 00 00 00 00 +[ 34250ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 c3 22 00 c3 0b 00 00 00 00 00 00 00 00 00 00 +[ 34274ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 c4 22 00 c4 0b 00 00 00 00 00 00 00 00 00 00 +[ 34295ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 01 a0 22 01 a0 0b 00 00 00 00 00 00 00 00 00 00 +[ 34319ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 2c 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34333ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 50 00 00 00 03 00 00 00 00 00 00 00 00 00 00 +[ 34348ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 2c 00 51 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34371ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 51 00 00 00 03 00 00 00 00 00 00 00 00 00 00 +[ 34386ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 14 3c 00 03 e8 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34400ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 0c 13 08 03 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34424ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 1c 00 01 05 01 05 18 00 00 00 00 00 00 00 00 00 00 +[ 34445ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 1c 00 01 05 01 05 18 00 00 00 00 00 00 00 00 00 00 +[ 34469ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 3c 00 00 55 4c 54 52 41 00 00 00 00 00 00 00 00 00 +[ 34491ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 7c 00 01 0b 00 00 66 58 00 00 00 00 00 00 00 00 00 +[ 34514ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 1c 01 00 00 00 00 18 00 00 00 00 00 00 00 00 00 00 +[ 34536ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 1c 01 00 00 00 00 18 00 00 00 00 00 00 00 00 00 00 +[ 34559ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 ff 0f 7c 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34581ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 1c 02 00 00 00 00 18 00 00 00 00 00 00 00 00 00 00 +[ 34604ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 1c 02 00 00 00 00 18 00 00 00 00 00 00 00 00 00 00 +[ 34625ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 ff 0f 7c 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34648ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 8c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34671ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 0c 13 08 03 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34694ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 1c 00 01 05 01 05 18 00 00 00 00 00 00 00 00 00 00 +[ 34715ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 7c 00 01 0b 00 00 66 58 00 00 00 00 00 00 00 00 00 +[ 34739ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 1c 01 00 00 00 00 18 00 00 00 00 00 00 00 00 00 00 +[ 34760ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 ff 0f 7c 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34784ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0f 1c 02 00 00 00 00 18 00 00 00 00 00 00 00 00 00 00 +[ 34806ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 ff 0f 7c 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34835ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 09 1c 1e 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34858ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0e 0c 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34873ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 09 1c 1e 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34889ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 09 1c 1e 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35218ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0c 3c 00 15 a3 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35240ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 53 23 00 53 0b 00 00 00 00 00 00 00 00 00 00 +[ 35264ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0b 2c 01 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35285ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 56 23 00 56 0b 00 00 00 00 00 00 00 00 00 00 +[ 35308ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 12 2c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35331ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 c3 33 00 c3 0b 00 00 00 00 00 00 00 00 00 00 +[ 35354ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 c4 23 00 c4 0b 00 00 00 00 00 00 00 00 00 00 +[ 35376ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 01 a0 23 01 a0 0b 00 00 00 00 00 00 00 00 00 00 +[ 35391ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 2c 00 50 00 00 00 01 00 00 00 00 00 00 00 00 00 00 +[ 35406ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 50 00 00 00 03 00 00 00 00 00 00 00 00 00 00 +[ 35429ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 2c 00 51 00 00 00 01 00 00 00 00 00 00 00 00 00 00 +[ 35444ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 51 00 00 00 03 00 00 00 00 00 00 00 00 00 00 +[ 35458ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 0c 01 0a 4b 0e 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35481ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 2c 00 50 00 00 00 01 00 00 00 00 00 00 00 00 00 00 +[ 35495ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 1c 02 0c 4b 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35511ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 50 00 00 00 03 00 00 00 00 00 00 00 00 00 00 +[ 35526ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 0c 01 0a 4b 0e 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35541ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 2c 00 51 00 00 00 01 00 00 00 00 00 00 00 00 00 00 +[ 35563ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 1c 02 0c 4b 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35579ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 51 00 00 00 03 00 00 00 00 00 00 00 00 00 00 +[ 35594ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35616ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 2c 00 50 00 00 00 01 00 00 00 00 00 00 00 00 00 00 +[ 35639ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 2c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35660ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 50 00 00 00 03 00 00 00 00 00 00 00 00 00 00 +[ 35683ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 1c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35705ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 2c 00 51 00 00 00 01 00 00 00 00 00 00 00 00 00 00 +[ 35729ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 1c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35744ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 51 00 00 00 03 00 00 00 00 00 00 00 00 00 00 +[ 35758ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0c 3c 00 15 a3 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35781ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 2c 00 50 00 00 00 01 00 00 00 00 00 00 00 00 00 00 +[ 35804ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0b 2c 01 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35826ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 50 00 00 00 03 00 00 00 00 00 00 00 00 00 00 +[ 35849ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 12 2c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35864ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 2c 00 51 00 00 00 01 00 00 00 00 00 00 00 00 00 00 +[ 35878ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 3c 00 51 00 00 00 03 00 00 00 00 00 00 00 00 00 00 +[ 35901ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 0c 01 0a 4b 0e 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35923ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 1c 02 0c 4b 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35946ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 0c 01 0a 4b 0e 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35969ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 1c 02 0c 4b 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35991ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 1c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36013ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 2c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36029ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 1c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36044ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 1c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36066ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0c 3c 00 15 a3 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36089ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0b 2c 01 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36111ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 12 2c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36134ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 0c 01 0a 4b 0e 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36149ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 1c 02 0c 4b 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36163ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 0c 01 0a 4b 0e 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36185ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 1c 02 0c 4b 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36208ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 1c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36231ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 2c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36253ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 1c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36276ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 1c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36298ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0c 3c 00 15 a3 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36320ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0b 2c 01 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36343ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 12 2c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36365ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 0c 01 0a 4b 0e 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36388ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 1c 02 0c 4b 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36410ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 0c 01 0a 4b 0e 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36433ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 11 1c 02 0c 4b 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36448ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 1c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36463ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 2c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36486ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 1c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36500ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 1c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 37055ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 +[ 37176ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 41196ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 41204ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 +[ 41248ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 42854ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 42929ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 43454ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 43596ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 43971ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 44061ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 44594ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 44684ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 45688ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 45756ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 46311ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 46409ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 46656ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 46761ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 52514ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 52595ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 53593ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 53699ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 54959ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 55018ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 56910ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 56976ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 57170ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 57284ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 59107ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 59182ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 63786ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 63892ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 66336ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 66426ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 67327ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 67372ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 67507ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 67567ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 67836ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 67927ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 70604ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 70687ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 72104ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 72217ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 73297ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 73394ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +raw-input tap closed diff --git a/docs/mx-master-4-panel-captures/optionsplus-rawinput.txt b/docs/mx-master-4-panel-captures/optionsplus-rawinput.txt new file mode 100644 index 00000000..5847da41 --- /dev/null +++ b/docs/mx-master-4-panel-captures/optionsplus-rawinput.txt @@ -0,0 +1,135 @@ +raw-input tap live for 300 s — pages 0x0D digitizer, 0x0E haptics, 0xFF00/0xFF43 vendor +device hdev=10094f: \\?\HID#VID_046D&PID_C539&MI_02&Col01#7&2071e0a2&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} +[ 9656ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 81 00 00 01 00 +device hdev=1006f: \\?\HID#VID_046D&PID_C548&MI_02&Col01#8&1ce49569&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} +[ 9656ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 81 00 00 01 00 +[ 9657ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 81 00 00 01 00 +[ 9659ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 81 02 00 01 00 +[ 9659ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 81 00 00 01 00 +[ 9661ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 01 41 0c 62 79 40 +[ 9662ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 80 02 00 00 00 +[ 9663ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 81 02 00 01 00 +[ 9676ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 02 41 10 02 42 b0 +[ 9677ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 80 02 00 00 00 +device hdev=1006b: \\?\HID#VID_046D&PID_C339&MI_01&Col03#9&17be02e2&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030} +[ 9696ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 00 1d 04 02 39 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 9699ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 02 0d 02 35 31 47 07 00 08 c3 39 00 00 00 00 04 00 00 +[ 9702ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 02 1d 00 55 31 20 13 04 00 19 01 c3 39 00 00 00 00 00 +[ 9705ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 02 1d 00 55 31 20 13 04 00 19 01 c3 39 00 00 00 00 00 +[ 9708ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff ff 02 2d 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 9722ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff ff 02 2d 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 9727ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 02 0d 02 35 31 47 07 00 08 c3 39 00 00 00 00 04 00 00 +[ 9730ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 02 1d 00 55 31 20 13 04 00 19 01 c3 39 00 00 00 00 00 +[ 9733ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 02 1d 00 55 31 20 13 04 00 19 01 c3 39 00 00 00 00 00 +[ 9736ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff 02 1d 01 42 4f 54 14 00 c4 b1 00 aa d0 00 00 00 00 00 +[ 9738ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 8f 00 1d 01 00 +device hdev=27909d3: \\?\HID#VID_046D&PID_C539&MI_02&Col02#7&2071e0a2&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030} +[ 9742ms] VID_046D&PID_C539&MI_02&Col02 len=20: 11 ff 83 b5 03 4b f5 94 dc 01 01 07 00 00 00 00 00 00 00 00 +[ 9744ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 81 f1 01 39 06 +[ 9746ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 81 f1 02 00 40 +[ 9761ms] VID_046D&PID_C539&MI_02&Col02 len=20: 11 ff 83 b5 40 06 47 20 50 72 6f 20 00 00 00 00 00 00 00 00 +[ 9764ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 8f 00 1d 01 00 +device hdev=10077: \\?\HID#VID_046D&PID_C548&MI_02&Col02#8&1ce49569&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030} +[ 9767ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 fb 39 37 42 37 36 39 34 38 41 38 34 36 43 35 35 41 +[ 9769ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 01 30 01 00 10 6e 3d 3d a0 00 00 00 00 00 00 00 +[ 9772ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 00 05 05 00 30 18 6a 26 ba 00 00 00 00 00 00 00 +[ 9774ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 05 00 00 01 3e 00 00 00 00 00 00 00 00 00 00 00 +[ 9775ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 02 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 9779ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 8f 83 f4 0b 00 +[ 9782ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 9784ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 fc 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 111626ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 111630ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 111633ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 fb 39 37 42 37 36 39 34 38 41 38 34 36 43 35 35 41 +[ 111635ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 01 30 01 00 10 6e 3d 3d a0 00 00 00 00 00 00 00 +[ 111638ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 00 05 05 00 30 18 6a 26 ba 00 00 00 00 00 00 00 +[ 111640ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 05 00 00 01 3e 00 00 00 00 00 00 00 00 00 00 00 +[ 111641ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 02 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 111644ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 8f 83 f4 0b 00 +[ 112309ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112332ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 39 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112354ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 0d 02 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112377ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 0d 04 12 c1 78 4d 00 02 b0 42 00 00 00 00 01 01 00 +[ 112399ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 01 4c 44 00 04 00 00 00 00 00 00 64 2b a1 a1 00 +[ 112422ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 00 52 42 4d 27 00 00 15 00 b0 42 f2 1a 37 9a 00 +[ 112437ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 00 52 42 4d 27 03 00 19 05 b0 42 03 ce 08 d8 00 +[ 112452ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 f3 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112475ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 0d 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112497ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 6e 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112519ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 0d 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112543ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 01 0d 2d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112565ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 01 4c 44 00 04 00 00 00 00 00 00 64 2b a1 a1 00 +[ 112587ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 00 52 42 4d 27 00 00 15 00 b0 42 f2 1a 37 9a 00 +[ 112609ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 00 52 42 4d 27 03 00 19 05 b0 42 03 ce 08 d8 00 +[ 112633ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 2d 32 35 33 30 5a 41 4c 35 51 47 4e 38 00 00 00 00 +[ 112654ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 74 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112669ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112692ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 e1 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112714ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 0d 03 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112737ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 03 2d 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112759ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 03 0d 0b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112782ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 03 1d 4d 58 20 4d 61 73 74 65 72 20 34 00 00 00 00 00 +[ 112804ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 8c 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112828ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112850ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 d6 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112872ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112902ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 01 4c 44 00 04 00 00 00 00 00 00 64 2b a1 a1 00 +[ 112925ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 00 52 42 4d 27 00 00 15 00 b0 42 f2 1a 37 9a 00 +[ 112940ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 00 52 42 4d 27 03 00 19 05 b0 42 03 ce 08 d8 00 +[ 112954ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 5e 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112977ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 0d 0e 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 112999ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0e 0d 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113022ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 62 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113044ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 0d 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113067ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113089ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 0d 06 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113104ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 c9 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113128ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 0d 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113142ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 06 0d 0d 33 21 0b e2 5e 89 8a b5 66 aa 24 cf f7 60 db +[ 113164ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 06 1d b2 c0 e0 33 ff f1 fb c7 19 47 5b 71 f8 79 a1 22 +[ 113177ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 b5 52 02 42 b0 12 c1 78 4d 02 01 80 14 01 00 00 00 +[ 113194ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 0d 04 12 c1 78 4d 00 02 b0 42 00 00 00 00 01 01 00 +[ 113210ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 01 4c 44 00 04 00 00 00 00 00 00 64 2b a1 a1 00 +[ 113224ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 00 52 42 4d 27 00 00 15 00 b0 42 f2 1a 37 9a 00 +[ 113247ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 00 52 42 4d 27 03 00 19 05 b0 42 03 ce 08 d8 00 +[ 113269ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 01 4c 44 00 04 00 00 00 00 00 00 64 2b a1 a1 00 +[ 113292ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 00 52 42 4d 27 00 00 15 00 b0 42 f2 1a 37 9a 00 +[ 113314ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 00 52 42 4d 27 03 00 19 05 b0 42 03 ce 08 d8 00 +[ 113337ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 02 48 57 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113359ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0a 0d 01 00 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113374ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 16 0d 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113448ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff ff 02 2d 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113454ms] VID_046D&PID_C339&MI_01&Col03 len=20: 11 ff ff 02 2d 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113463ms] VID_046D&PID_C539&MI_02&Col02 len=20: 11 ff 83 b5 03 4b f5 94 dc 01 01 07 00 00 00 00 00 00 00 00 +[ 113467ms] VID_046D&PID_C539&MI_02&Col01 len=7: 10 ff 8f 83 f5 02 00 +[ 113486ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 fb 39 37 42 37 36 39 34 38 41 38 34 36 43 35 35 41 +[ 113490ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113517ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 02 1d 02 48 57 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113539ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 51 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113562ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113577ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 11 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113592ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 0d 09 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113614ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 1d 04 05 2b 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113637ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 00 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113659ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 09 0d 0f 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113771ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 01 30 01 00 10 6e 3d 3d a0 00 00 00 00 00 00 00 +[ 113773ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 00 05 05 00 30 18 6a 26 ba 00 00 00 00 00 00 00 +[ 113776ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 05 00 00 01 3e 00 00 00 00 00 00 00 00 00 00 00 +[ 113779ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 02 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113782ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 8f 83 f4 0b 00 +[ 113784ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 01 30 01 00 10 6e 3d 3d a0 00 00 00 00 00 00 00 +[ 113786ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 00 05 05 00 30 18 6a 26 ba 00 00 00 00 00 00 00 +[ 113789ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 05 00 00 01 3e 00 00 00 00 00 00 00 00 00 00 00 +[ 113793ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 02 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113795ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 8f 83 f4 0b 00 +[ 113798ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 01 30 01 00 10 6e 3d 3d a0 00 00 00 00 00 00 00 +[ 113800ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 00 05 05 00 30 18 6a 26 ba 00 00 00 00 00 00 00 +[ 113801ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 05 00 00 01 3e 00 00 00 00 00 00 00 00 00 00 00 +[ 113803ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 02 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113806ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 8f 83 f4 0b 00 +[ 113809ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 01 30 01 00 10 6e 3d 3d a0 00 00 00 00 00 00 00 +[ 113812ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 00 05 05 00 30 18 6a 26 ba 00 00 00 00 00 00 00 +[ 113814ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 05 00 00 01 3e 00 00 00 00 00 00 00 00 00 00 00 +[ 113816ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 f4 02 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 113819ms] VID_046D&PID_C548&MI_02&Col01 len=7: 10 ff 8f 83 f4 0b 00 +[ 113823ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 ff 83 fc 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff --git a/docs/mx-master-4-panel-captures/panel-analytics-stream.txt b/docs/mx-master-4-panel-captures/panel-analytics-stream.txt new file mode 100644 index 00000000..55e4ee0a --- /dev/null +++ b/docs/mx-master-4-panel-captures/panel-analytics-stream.txt @@ -0,0 +1,115 @@ +raw-input tap live for 90 s — pages 0x0D digitizer, 0x0E haptics, 0xFF00/0xFF43 vendor +device hdev=10077: \\?\HID#VID_046D&PID_C548&MI_02&Col02#8&1ce49569&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030} +[ 490ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 551ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 1819ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 1939ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 2464ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 2524ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3101ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3184ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3986ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 4106ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 5645ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 5726ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 7205ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 7280ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 8179ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 8262ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 8697ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 8787ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 10197ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 10302ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 11082ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 11157ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 11884ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 11982ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 12454ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 12544ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 13602ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 13722ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 16160ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 16272ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 17637ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 17697ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 21477ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 21545ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 26697ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 26795ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 28040ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 28145ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 29292ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 29337ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 29435ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 29480ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 29570ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 29637ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 29907ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 29990ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 30305ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 30725ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 30867ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 30920ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 31235ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 31715ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 31850ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 31917ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 32360ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 32772ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 32892ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 32975ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33297ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33642ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33785ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 33912ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34287ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34550ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34662ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 34730ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35007ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35067ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 35960ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 36042ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 37257ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 37340ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 37572ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 37677ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 41570ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 41637ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 42042ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 42117ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 42560ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 42620ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 44052ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 44210ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 46010ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 46100ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 51207ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 51297ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 56585ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 56645ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 58482ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 58527ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 59841ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 59907ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 60425ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 60515ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 68090ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 71563ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 75860ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 75943ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 77360ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 77428ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 78845ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 78928ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 80060ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 80129ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 80736ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 80826ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 81741ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 81853ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 85896ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 86023ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 86698ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 01 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 86803ms] VID_046D&PID_C548&MI_02&Col02 len=20: 11 02 0d 20 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +raw-input tap closed diff --git a/docs/mx-master-4-panel-captures/panel-force-rawxy-stream.log b/docs/mx-master-4-panel-captures/panel-force-rawxy-stream.log new file mode 100644 index 00000000..1a9b9e03 --- /dev/null +++ b/docs/mx-master-4-panel-captures/panel-force-rawxy-stream.log @@ -0,0 +1,5797 @@ +2026-07-20T04:56:38.090954Z DEBUG openlogi_core::single_instance: single-instance lock acquired path=C:\Users\ultra\.config/openlogi\agent.lock +2026-07-20T04:56:38.092452Z DEBUG openlogi_agent::launch_agent: agent autostart registry value already absent +2026-07-20T04:56:38.092691Z INFO openlogi_agent: openlogi-agent started +2026-07-20T04:56:38.092728Z INFO openlogi_agent: accessibility granted — installing OS mouse hook +2026-07-20T04:56:38.092799Z INFO openlogi_agent::server: IPC server listening +2026-07-20T04:56:38.093241Z INFO openlogi_agent_core::hook_runtime: OS mouse hook installed +2026-07-20T04:56:38.093280Z DEBUG openlogi_agent_core::watchers::foreground_app: frontmost app changed current=Some("c:\\program files (x86)\\steam\\steamapps\\common\\command & conquer generals - zero hour\\game.dat") last=None +2026-07-20T04:56:38.102239Z INFO openlogi_agent::tray_windows: tray icon installed +2026-07-20T04:56:38.209488Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:56:38.209519Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:56:38.209522Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:38.209524Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:38.209526Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:38.209528Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:56:38.209530Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:56:38.209532Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:56:38.209534Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:38.209536Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:38.209538Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:38.209540Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:56:38.209542Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:56:38.209545Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:56:38.209547Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:56:38.209549Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:56:38.209558Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=2 +2026-07-20T04:56:38.247873Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=PRO Gaming Keyboard pid=c339 supports_short=false supports_long=true +2026-07-20T04:56:38.283015Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c548 +2026-07-20T04:56:38.283038Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c548 supports_short=true supports_long=true +2026-07-20T04:56:38.292313Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:56:38.348425Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:56:39.806737Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:56:39.808447Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:39.823349Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:56:40.825834Z DEBUG openlogi_hid::inventory::probe: Bolt slot probe timed out; using cached data if available slot=2 budget=1s +2026-07-20T04:56:40.828450Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:40.831341Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:40.833376Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:40.835436Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:40.835517Z DEBUG openlogi_agent_core::hardware: no target device — wheel mode write skipped resolution=None inverted=None +2026-07-20T04:56:40.910311Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:56:40.910365Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:56:40.910382Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:40.910384Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:40.910387Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:40.910389Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:56:40.910391Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:56:40.910393Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:56:40.910395Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:40.910397Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:40.910399Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:40.910402Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:56:40.910404Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:56:40.910406Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:56:40.910408Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:56:40.910410Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:56:40.951363Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=PRO Gaming Keyboard pid=c339 supports_short=false supports_long=true +2026-07-20T04:56:40.995321Z DEBUG openlogi_hid::write::lighting: set keyboard colour via typed 0x8070 index=255 zone_count=2 zones_to_write=2 r=52 g=199 b=89 +2026-07-20T04:56:40.995611Z DEBUG openlogi_agent_core::hardware: lighting written to keyboard r=52 g=199 b=89 +2026-07-20T04:56:41.141850Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:56:41.141873Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:56:41.141876Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:41.141879Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:41.141881Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:41.141883Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:56:41.141885Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:56:41.141887Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:56:41.141889Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:41.141891Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:41.141893Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:41.141895Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:56:41.141898Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:56:41.141900Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:56:41.141902Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:56:41.141904Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:56:41.187983Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=PRO Gaming Keyboard pid=c339 supports_short=false supports_long=true +2026-07-20T04:56:41.193385Z DEBUG openlogi_hid::gesture: no capturable controls — idle session slot=255 +2026-07-20T04:56:41.193406Z INFO openlogi_hid::gesture: control capture active index=255 gesture=false dpi_buttons=0 thumbwheel=false +2026-07-20T04:56:42.891082Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:56:42.891102Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:56:42.891105Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:42.891107Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:42.891109Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:42.891111Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:56:42.891113Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:56:42.891117Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:56:42.891121Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:42.891123Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:42.891125Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:42.891127Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:56:42.891129Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:56:42.891131Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:56:42.891133Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:56:42.891135Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:56:42.891141Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=2 +2026-07-20T04:56:42.891152Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:56:42.898424Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:56:44.412641Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:56:44.414436Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:44.428488Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:56:45.437360Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:45.440439Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:45.442329Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:45.445356Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:45.445491Z DEBUG openlogi_agent_core::hardware: no target device — wheel mode write skipped resolution=None inverted=None +2026-07-20T04:56:45.574293Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:56:45.574320Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:56:45.574323Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:45.574325Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:45.574327Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:45.574329Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:56:45.574331Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:56:45.574333Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:56:45.574379Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:45.574384Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:45.574386Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:45.574388Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:56:45.574390Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:56:45.574392Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:56:45.574394Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:56:45.574396Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:56:45.578684Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:56:45.578703Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:56:45.578706Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:45.578708Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:45.578710Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:45.578712Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:56:45.578714Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:56:45.578716Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:56:45.578718Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:45.578720Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:45.578722Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:45.578724Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:56:45.578726Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:56:45.578731Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:56:45.578733Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:56:45.578735Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:56:45.632366Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=PRO Gaming Keyboard pid=c339 supports_short=false supports_long=true +2026-07-20T04:56:45.635409Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 0, function_id: U4(1), software_id: U4(1) }, [4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:45.635909Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=PRO Gaming Keyboard pid=c339 supports_short=false supports_long=true +2026-07-20T04:56:45.638482Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 0, function_id: U4(0), software_id: U4(1) }, [13, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:45.641381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 13, function_id: U4(0), software_id: U4(1) }, [2, 0, 1, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:45.644361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 13, function_id: U4(3), software_id: U4(1) }, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:45.656328Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 13, function_id: U4(3), software_id: U4(1) }, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:45.669545Z DEBUG openlogi_hid::write::lighting: set keyboard colour via typed 0x8070 index=255 zone_count=2 zones_to_write=2 r=52 g=199 b=89 +2026-07-20T04:56:45.669733Z DEBUG openlogi_agent_core::hardware: lighting written to keyboard r=52 g=199 b=89 +2026-07-20T04:56:45.680171Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c548 +2026-07-20T04:56:45.680185Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c548 supports_short=true supports_long=true +2026-07-20T04:56:45.756442Z DEBUG openlogi_hid::hires_wheel: native wheel mode already set; skipping index=2 desired=ScrollWheelMode { resolution: Low, inverted: false, target: Native } +2026-07-20T04:56:45.756603Z DEBUG openlogi_agent_core::hardware: native wheel mode written index=2 resolution=None inverted=Some(false) reused=false +2026-07-20T04:56:46.100538Z DEBUG openlogi_hid::gesture: control capture stopped index=255 +2026-07-20T04:56:47.142293Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:56:47.142318Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:56:47.142321Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:47.142323Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:47.142325Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:47.142327Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:56:47.142329Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:56:47.142331Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:56:47.142333Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:47.142335Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:47.142337Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:47.142339Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:56:47.142341Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:56:47.142348Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:56:47.142352Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:56:47.142354Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:56:47.182951Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=PRO Gaming Keyboard pid=c339 supports_short=false supports_long=true +2026-07-20T04:56:47.220414Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c548 +2026-07-20T04:56:47.220432Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c548 supports_short=true supports_long=true +2026-07-20T04:56:47.495743Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:56:47.495761Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:56:47.495764Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:47.495766Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:47.495768Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:47.495770Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:56:47.495772Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:56:47.495774Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:56:47.495776Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:47.495778Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:47.495780Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:47.495782Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:56:47.495784Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:56:47.495786Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:56:47.495788Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:56:47.495790Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:56:47.495795Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=2 +2026-07-20T04:56:47.495806Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:56:47.496425Z INFO openlogi_hid::gesture: haptic sense panel diverted (with force-raw-xy) +2026-07-20T04:56:47.503337Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:56:47.515409Z INFO openlogi_hid::gesture: control capture active index=2 gesture=true dpi_buttons=1 thumbwheel=false +2026-07-20T04:56:47.631414Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.631455Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:47.639381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.639396Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:47.646361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.646375Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-2 +2026-07-20T04:56:47.654313Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.654331Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-6 +2026-07-20T04:56:47.661405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.661438Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-5 +2026-07-20T04:56:47.669423Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.669454Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-6 +2026-07-20T04:56:47.676426Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.676434Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-8 +2026-07-20T04:56:47.684643Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.684658Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-6 +2026-07-20T04:56:47.691459Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.691491Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-7 +2026-07-20T04:56:47.699486Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.699500Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-8 +2026-07-20T04:56:47.706385Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.706398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-7 +2026-07-20T04:56:47.714445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.714458Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-8 +2026-07-20T04:56:47.721372Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.721398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-8 +2026-07-20T04:56:47.729393Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.729530Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-6 +2026-07-20T04:56:47.736521Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.736535Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-5 +2026-07-20T04:56:47.744345Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.744360Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-3 +2026-07-20T04:56:47.751318Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.751333Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-4 +2026-07-20T04:56:47.759384Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.759397Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-2 +2026-07-20T04:56:47.766432Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.766466Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-4 +2026-07-20T04:56:47.774370Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.774384Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-3 +2026-07-20T04:56:47.781454Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:47.781470Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.021469Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.021500Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.029430Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.029450Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:48.036436Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.036458Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:48.044383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.044399Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:48.051458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.051494Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:48.059438Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.059454Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.066460Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.066503Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.074383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.074399Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.096382Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.096405Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.119511Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.119535Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.126451Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.126474Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.141448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.141478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.149493Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.149503Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:48.156458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.156478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.164389Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.164403Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:48.171368Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.171384Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.179477Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.179516Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:48.186433Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.186461Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:48.194529Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.194559Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:48.201360Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.201424Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:56:48.209477Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.209491Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:56:48.216494Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.216531Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:48.224486Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.224502Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:48.231493Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.231522Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-2 +2026-07-20T04:56:48.239522Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.239539Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:48.246393Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.246407Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.254401Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.254414Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:48.261418Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.261456Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:48.269440Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.269458Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:48.276458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.276471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.284423Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.284434Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.291426Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.291436Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.299397Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.299486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.306310Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.306322Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.344368Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.352639Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.381468Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.381487Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:56:48.389399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.389415Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.779474Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.779491Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:48.786382Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.786398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:48.794467Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.794482Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-2 +2026-07-20T04:56:48.801419Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.801451Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-6 +2026-07-20T04:56:48.809326Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.809341Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-2 +2026-07-20T04:56:48.816372Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.816413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-3 +2026-07-20T04:56:48.824377Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.824395Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-3 +2026-07-20T04:56:48.831446Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.831460Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-4 +2026-07-20T04:56:48.839454Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.839473Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-4 +2026-07-20T04:56:48.846404Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.846427Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-4 +2026-07-20T04:56:48.854454Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.854475Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-4 +2026-07-20T04:56:48.861468Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.861486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-4 +2026-07-20T04:56:48.869437Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.869477Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-5 +2026-07-20T04:56:48.876431Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.876449Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-6 +2026-07-20T04:56:48.884479Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.884490Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-8 +2026-07-20T04:56:48.891473Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.891486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-7 +2026-07-20T04:56:48.899381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.899406Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-10 +2026-07-20T04:56:48.906391Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.906404Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-9 +2026-07-20T04:56:48.914430Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.914445Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-9 +2026-07-20T04:56:48.921416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.921442Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-13 +2026-07-20T04:56:48.929505Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.929546Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-8 +2026-07-20T04:56:48.936384Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.936398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-8 +2026-07-20T04:56:48.944420Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.944439Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-8 +2026-07-20T04:56:48.951406Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.951435Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-7 +2026-07-20T04:56:48.959431Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.959445Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-4 +2026-07-20T04:56:48.966457Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.966471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-4 +2026-07-20T04:56:48.974396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.974412Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-3 +2026-07-20T04:56:48.981424Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:48.981438Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:49.025311Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:56:49.027326Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:49.027445Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:49.037408Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:56:49.041338Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:56:49.041400Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:56:49.326321Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.326344Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:56:49.334334Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.334353Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:56:49.341318Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.341335Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:56:49.349341Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.353392Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:49.353451Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:49.355388Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:49.355397Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:49.356335Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.356347Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-3 +2026-07-20T04:56:49.358351Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:49.358440Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:49.361350Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:49.361362Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:49.364321Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.364337Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-7 +2026-07-20T04:56:49.371329Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.371364Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-5 +2026-07-20T04:56:49.386381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.386404Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-7 +2026-07-20T04:56:49.394329Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.394354Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-16 +2026-07-20T04:56:49.409357Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.409409Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-10 +2026-07-20T04:56:49.416289Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.416307Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-22 +2026-07-20T04:56:49.431304Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.431328Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-9 +2026-07-20T04:56:49.439299Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.439319Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-27 +2026-07-20T04:56:49.446393Z DEBUG openlogi_hid::hires_wheel: native wheel mode already set; skipping index=2 desired=ScrollWheelMode { resolution: Low, inverted: false, target: Native } +2026-07-20T04:56:49.446422Z DEBUG openlogi_agent_core::hardware: native wheel mode written index=2 resolution=None inverted=Some(false) reused=true +2026-07-20T04:56:49.454349Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.454370Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-11 +2026-07-20T04:56:49.461387Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.461406Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-20 +2026-07-20T04:56:49.469308Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.469340Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-14 +2026-07-20T04:56:49.476307Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.476328Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-9 +2026-07-20T04:56:49.484445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.484467Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-8 +2026-07-20T04:56:49.491356Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.491375Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-7 +2026-07-20T04:56:49.499321Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.499338Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-5 +2026-07-20T04:56:49.506426Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.506458Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-5 +2026-07-20T04:56:49.514455Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.514472Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-3 +2026-07-20T04:56:49.521535Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.521555Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-3 +2026-07-20T04:56:49.529426Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.529444Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-2 +2026-07-20T04:56:49.536431Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.536448Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-1 +2026-07-20T04:56:49.544496Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.544526Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-1 +2026-07-20T04:56:49.551396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.551413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=0 +2026-07-20T04:56:49.559432Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.559450Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=0 +2026-07-20T04:56:49.566366Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.566382Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-1 +2026-07-20T04:56:49.754350Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.754378Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:56:49.761440Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.761473Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:49.769384Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.769414Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-2 +2026-07-20T04:56:49.776471Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.776487Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-1 +2026-07-20T04:56:49.784561Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.784602Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=0 +2026-07-20T04:56:49.799402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.799420Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-2 +2026-07-20T04:56:49.806373Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.806390Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=0 +2026-07-20T04:56:49.814478Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.814494Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-1 +2026-07-20T04:56:49.821450Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.821475Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-1 +2026-07-20T04:56:49.829420Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.829432Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-1 +2026-07-20T04:56:49.836452Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.836497Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-1 +2026-07-20T04:56:49.844408Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.844424Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-1 +2026-07-20T04:56:49.851483Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.851511Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-1 +2026-07-20T04:56:49.859443Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.859459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-2 +2026-07-20T04:56:49.866433Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.866460Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-3 +2026-07-20T04:56:49.874375Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.874393Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-2 +2026-07-20T04:56:49.881492Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.881508Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-2 +2026-07-20T04:56:49.889505Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.889519Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-2 +2026-07-20T04:56:49.896499Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.896511Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-2 +2026-07-20T04:56:49.904419Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.904434Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-2 +2026-07-20T04:56:49.911368Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.911408Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-2 +2026-07-20T04:56:49.919421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.919436Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-6 +2026-07-20T04:56:49.926523Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.926538Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-3 +2026-07-20T04:56:49.934415Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.934437Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-2 +2026-07-20T04:56:49.941448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.941464Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-1 +2026-07-20T04:56:49.949324Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.949357Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:49.956408Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.956424Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:56:49.971432Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.971448Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=2 +2026-07-20T04:56:49.979349Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.979365Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=1 +2026-07-20T04:56:49.994402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:49.994420Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=2 +2026-07-20T04:56:50.271491Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.271538Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.294402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.294436Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.301403Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.301424Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.309401Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.309416Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.316461Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.316478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.324426Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.324452Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.331394Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.331412Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:50.339454Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.339492Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.346399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.346415Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:50.354417Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.354432Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.361411Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.361426Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:56:50.369416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.369431Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.376416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.376443Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:56:50.384462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.384482Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:50.391331Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.391348Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-3 +2026-07-20T04:56:50.399405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.399420Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-3 +2026-07-20T04:56:50.406349Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.406378Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:56:50.414365Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.414378Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-3 +2026-07-20T04:56:50.421415Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.421431Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:56:50.429369Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.429383Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-5 +2026-07-20T04:56:50.436330Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.436372Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-7 +2026-07-20T04:56:50.444464Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.444486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-5 +2026-07-20T04:56:50.451412Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.451426Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:56:50.459426Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.459445Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-5 +2026-07-20T04:56:50.466399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.466414Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-5 +2026-07-20T04:56:50.474417Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.474429Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-5 +2026-07-20T04:56:50.481459Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.481481Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-5 +2026-07-20T04:56:50.489425Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.489434Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-6 +2026-07-20T04:56:50.496384Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.496400Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-2 +2026-07-20T04:56:50.504329Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.504342Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-5 +2026-07-20T04:56:50.511470Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.511500Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-4 +2026-07-20T04:56:50.519314Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.519329Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-2 +2026-07-20T04:56:50.526442Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.526473Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-3 +2026-07-20T04:56:50.534370Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.534390Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-2 +2026-07-20T04:56:50.541371Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.541386Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.556366Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.556380Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.789451Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.789472Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.796414Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.796432Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:50.804325Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.804338Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-3 +2026-07-20T04:56:50.811391Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.811419Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:50.819388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.819403Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-3 +2026-07-20T04:56:50.826337Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.826349Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-3 +2026-07-20T04:56:50.834301Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.834311Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:50.841320Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.841334Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-2 +2026-07-20T04:56:50.849337Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.849364Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-3 +2026-07-20T04:56:50.856374Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.856404Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:50.864405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.864447Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:50.871386Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.871398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.879413Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.879426Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.894409Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.894439Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.901399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.901411Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:50.909462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.909489Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.931370Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.931387Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:50.954440Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:50.954473Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:51.480697Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:56:51.480717Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:56:51.480721Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:51.480723Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:51.480725Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:51.480727Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:56:51.480729Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:56:51.480731Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:56:51.480733Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:51.480735Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:51.480737Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:51.480740Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:56:51.480742Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:56:51.480746Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:56:51.480750Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:56:51.480752Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:56:51.480758Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=2 +2026-07-20T04:56:51.480769Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:56:51.484408Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:56:51.488355Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:56:51.488382Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:56:51.494444Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:56:51.496391Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:56:52.274447Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.274490Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:52.281538Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.281551Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:56:52.289501Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.289530Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:56:52.296439Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.296454Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-10 +2026-07-20T04:56:52.304414Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.304428Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-5 +2026-07-20T04:56:52.311479Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.311492Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-4 +2026-07-20T04:56:52.319468Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.319494Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-4 +2026-07-20T04:56:52.326458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.326505Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-5 +2026-07-20T04:56:52.334383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.334398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:52.341429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.341442Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-4 +2026-07-20T04:56:52.349445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.349459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:56:52.356386Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.356405Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-3 +2026-07-20T04:56:52.364422Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.364434Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-3 +2026-07-20T04:56:52.371371Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.371389Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-3 +2026-07-20T04:56:52.379380Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.379406Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-3 +2026-07-20T04:56:52.386616Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.386660Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:52.394424Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.394452Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:52.671460Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:52.671485Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=0 +2026-07-20T04:56:53.008901Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:56:53.012318Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:53.012380Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:53.021336Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:56:53.027303Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:56:53.027327Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:56:53.219430Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.219453Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-3 +2026-07-20T04:56:53.226400Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.226432Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-3 +2026-07-20T04:56:53.234384Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.234411Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-3 +2026-07-20T04:56:53.241471Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.244468Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:53.244484Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:53.247369Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:53.247401Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:53.249446Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:53.249464Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:53.251424Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.251440Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-15 +2026-07-20T04:56:53.253446Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:53.253459Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:53.256399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.256410Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=-14 +2026-07-20T04:56:53.264498Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.264513Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-6 +2026-07-20T04:56:53.271471Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.271486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=-10 +2026-07-20T04:56:53.279373Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.279390Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-6 +2026-07-20T04:56:53.286446Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.286475Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=-8 +2026-07-20T04:56:53.294456Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.294468Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-7 +2026-07-20T04:56:53.301448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.301478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-7 +2026-07-20T04:56:53.309413Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.309428Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-5 +2026-07-20T04:56:53.316354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.316361Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-3 +2026-07-20T04:56:53.324459Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.324489Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-1 +2026-07-20T04:56:53.331449Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.331462Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-2 +2026-07-20T04:56:53.339406Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.339418Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-2 +2026-07-20T04:56:53.346475Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.346493Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:53.676419Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.676444Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=0 +2026-07-20T04:56:53.684393Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.684426Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-1 +2026-07-20T04:56:53.691437Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.691471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=0 +2026-07-20T04:56:53.706361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.706409Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:56:53.714503Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.714546Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:56:53.721485Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.721517Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:53.729488Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.729534Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-5 +2026-07-20T04:56:53.736421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.736436Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-8 +2026-07-20T04:56:53.744393Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.744411Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-6 +2026-07-20T04:56:53.751435Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.751450Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-8 +2026-07-20T04:56:53.759473Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.759503Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-9 +2026-07-20T04:56:53.766333Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.766348Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-10 +2026-07-20T04:56:53.774385Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.774400Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-12 +2026-07-20T04:56:53.781400Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.781432Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-8 +2026-07-20T04:56:53.789573Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.792661Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-14 +2026-07-20T04:56:53.796390Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.796404Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-10 +2026-07-20T04:56:53.804404Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.804418Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-17 +2026-07-20T04:56:53.811458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.811475Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-11 +2026-07-20T04:56:53.819458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.819478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-12 +2026-07-20T04:56:53.826396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.826411Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-17 +2026-07-20T04:56:53.834342Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.834356Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-13 +2026-07-20T04:56:53.841344Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.841358Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-12 +2026-07-20T04:56:53.849394Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.849410Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-12 +2026-07-20T04:56:53.856415Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.856431Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-12 +2026-07-20T04:56:53.864435Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.864465Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-12 +2026-07-20T04:56:53.871488Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.871504Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-12 +2026-07-20T04:56:53.879357Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.879367Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-12 +2026-07-20T04:56:53.886369Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.886401Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-5 +2026-07-20T04:56:53.894376Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.894392Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-9 +2026-07-20T04:56:53.901414Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.901430Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-9 +2026-07-20T04:56:53.909453Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.909489Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-9 +2026-07-20T04:56:53.916398Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.916432Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-7 +2026-07-20T04:56:53.924471Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.924487Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-4 +2026-07-20T04:56:53.931564Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.931580Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-6 +2026-07-20T04:56:53.939482Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.939519Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-6 +2026-07-20T04:56:53.946489Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.946498Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-4 +2026-07-20T04:56:53.954415Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.954433Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-6 +2026-07-20T04:56:53.961471Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.961488Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-3 +2026-07-20T04:56:53.969384Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.969400Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-5 +2026-07-20T04:56:53.976409Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.976425Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-6 +2026-07-20T04:56:53.984482Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.984499Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-3 +2026-07-20T04:56:53.991478Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.991495Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-3 +2026-07-20T04:56:53.999491Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:53.999507Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-5 +2026-07-20T04:56:54.006389Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.006404Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-3 +2026-07-20T04:56:54.014458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.014479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-5 +2026-07-20T04:56:54.021438Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.021454Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-3 +2026-07-20T04:56:54.029467Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.029499Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-5 +2026-07-20T04:56:54.036408Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.036425Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-2 +2026-07-20T04:56:54.044351Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.044367Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-6 +2026-07-20T04:56:54.051548Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.051566Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-2 +2026-07-20T04:56:54.059427Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.059443Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-3 +2026-07-20T04:56:54.066395Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.066424Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-5 +2026-07-20T04:56:54.074429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.074441Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-2 +2026-07-20T04:56:54.081453Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.081490Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-3 +2026-07-20T04:56:54.089484Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.089505Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-7 +2026-07-20T04:56:54.096397Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.096413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-3 +2026-07-20T04:56:54.104471Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.104486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-3 +2026-07-20T04:56:54.111429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.111447Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-6 +2026-07-20T04:56:54.119413Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.119426Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-3 +2026-07-20T04:56:54.126381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.126397Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-3 +2026-07-20T04:56:54.134448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.134466Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-3 +2026-07-20T04:56:54.141441Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.141455Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-2 +2026-07-20T04:56:54.149415Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.149428Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-4 +2026-07-20T04:56:54.156416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.156439Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-2 +2026-07-20T04:56:54.164398Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.164411Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:54.171508Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.171537Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:54.179492Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.179505Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-2 +2026-07-20T04:56:54.186526Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.186539Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:54.194468Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.194478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:54.201518Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.201547Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:54.209363Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.209392Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:54.216455Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.216473Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-2 +2026-07-20T04:56:54.224388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.224400Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-2 +2026-07-20T04:56:54.231391Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.231403Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-4 +2026-07-20T04:56:54.239584Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.239606Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-2 +2026-07-20T04:56:54.269386Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.269421Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:56:54.284465Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.284494Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=5 +2026-07-20T04:56:54.291457Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.291474Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=6 +2026-07-20T04:56:54.299529Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.299543Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=10 +2026-07-20T04:56:54.306475Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.306504Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=8 +2026-07-20T04:56:54.314420Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.314430Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=11 +2026-07-20T04:56:54.321426Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.321435Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=14 +2026-07-20T04:56:54.329447Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.329468Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=14 +2026-07-20T04:56:54.336416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.336445Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=19 +2026-07-20T04:56:54.344451Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.344490Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=14 +2026-07-20T04:56:54.351390Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.351427Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=22 +2026-07-20T04:56:54.359446Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.359459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=15 +2026-07-20T04:56:54.366421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.366459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=22 +2026-07-20T04:56:54.374467Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.374479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=22 +2026-07-20T04:56:54.381469Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.381493Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=15 +2026-07-20T04:56:54.389455Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.389479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=21 +2026-07-20T04:56:54.396397Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.396409Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=14 +2026-07-20T04:56:54.404330Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.404344Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=18 +2026-07-20T04:56:54.411418Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.411431Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=11 +2026-07-20T04:56:54.419453Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.419465Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=16 +2026-07-20T04:56:54.426381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.426395Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=8 +2026-07-20T04:56:54.434382Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.434395Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=5 +2026-07-20T04:56:54.441487Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 27, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.441522Z INFO openlogi_hid::gesture: SPIKE raw xy dx=27 dy=5 +2026-07-20T04:56:54.449443Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.449520Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=1 +2026-07-20T04:56:54.456506Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.456537Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=-1 +2026-07-20T04:56:54.464449Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 30, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.464463Z INFO openlogi_hid::gesture: SPIKE raw xy dx=30 dy=-3 +2026-07-20T04:56:54.471510Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 26, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.471543Z INFO openlogi_hid::gesture: SPIKE raw xy dx=26 dy=-4 +2026-07-20T04:56:54.479405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 26, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.479419Z INFO openlogi_hid::gesture: SPIKE raw xy dx=26 dy=-4 +2026-07-20T04:56:54.486387Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.486401Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=-4 +2026-07-20T04:56:54.494375Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.494389Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=-5 +2026-07-20T04:56:54.501357Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.501372Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=-5 +2026-07-20T04:56:54.509398Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.509436Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=-4 +2026-07-20T04:56:54.516518Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.516544Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=-5 +2026-07-20T04:56:54.524409Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.524424Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=-4 +2026-07-20T04:56:54.531464Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.531474Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-3 +2026-07-20T04:56:54.539326Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.539349Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-2 +2026-07-20T04:56:54.546344Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.546359Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-2 +2026-07-20T04:56:54.554398Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.554425Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=0 +2026-07-20T04:56:54.561458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.561474Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=0 +2026-07-20T04:56:54.569460Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.569482Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=0 +2026-07-20T04:56:54.576432Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.576445Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:56:54.584354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.584366Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:56:54.591352Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.591365Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=2 +2026-07-20T04:56:54.599522Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.599537Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=3 +2026-07-20T04:56:54.606511Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.606549Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=7 +2026-07-20T04:56:54.614504Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.614534Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=7 +2026-07-20T04:56:54.621456Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.621491Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=9 +2026-07-20T04:56:54.629453Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.629466Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=9 +2026-07-20T04:56:54.636356Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.636382Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=9 +2026-07-20T04:56:54.644477Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.644495Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=8 +2026-07-20T04:56:54.651392Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.651420Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=8 +2026-07-20T04:56:54.659419Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.659432Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=5 +2026-07-20T04:56:54.666466Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.666479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:56:54.689401Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.689431Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:54.696383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.696397Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:56:54.704389Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.704412Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-3 +2026-07-20T04:56:54.711456Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.711469Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-19 +2026-07-20T04:56:54.719418Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.719432Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-18 +2026-07-20T04:56:54.726467Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.726479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-14 +2026-07-20T04:56:54.734477Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.734490Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=-17 +2026-07-20T04:56:54.741345Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.741373Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=-18 +2026-07-20T04:56:54.749347Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 236, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.749362Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-20 dy=-19 +2026-07-20T04:56:54.756317Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 234, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.756331Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-22 dy=-20 +2026-07-20T04:56:54.764370Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.764384Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=-19 +2026-07-20T04:56:54.771586Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 231, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.771620Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-25 dy=-19 +2026-07-20T04:56:54.779395Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 224, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.779421Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-32 dy=-20 +2026-07-20T04:56:54.786370Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.786383Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=-11 +2026-07-20T04:56:54.801521Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 222, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.801552Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-34 dy=-12 +2026-07-20T04:56:54.809531Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 226, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.809569Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-30 dy=-6 +2026-07-20T04:56:54.816441Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 187, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.816471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-69 dy=-4 +2026-07-20T04:56:54.824421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.824450Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-25 dy=0 +2026-07-20T04:56:54.831347Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 227, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.831365Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-29 dy=3 +2026-07-20T04:56:54.839427Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 223, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.839450Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-33 dy=7 +2026-07-20T04:56:54.846428Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.846458Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=9 +2026-07-20T04:56:54.854374Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.854413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=12 +2026-07-20T04:56:54.861426Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.861448Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=13 +2026-07-20T04:56:54.869451Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 236, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.869477Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-20 dy=20 +2026-07-20T04:56:54.876414Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.876437Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=18 +2026-07-20T04:56:54.884443Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.884475Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=22 +2026-07-20T04:56:54.891481Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.891495Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=25 +2026-07-20T04:56:54.899445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.899459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=25 +2026-07-20T04:56:54.906352Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.906365Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=27 +2026-07-20T04:56:54.914299Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.914313Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=19 +2026-07-20T04:56:54.921386Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.921410Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=23 +2026-07-20T04:56:54.929417Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.929431Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=15 +2026-07-20T04:56:54.936436Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.936450Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=14 +2026-07-20T04:56:54.944373Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.944386Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=13 +2026-07-20T04:56:54.951311Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.951327Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=11 +2026-07-20T04:56:54.959381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.959398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=9 +2026-07-20T04:56:54.966375Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.966386Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=7 +2026-07-20T04:56:54.974410Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.974420Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=4 +2026-07-20T04:56:54.981416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.981433Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=1 +2026-07-20T04:56:54.989510Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.989536Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=0 +2026-07-20T04:56:54.996408Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:54.996421Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-1 +2026-07-20T04:56:55.004415Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.004428Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-2 +2026-07-20T04:56:55.011524Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.011554Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-2 +2026-07-20T04:56:55.019433Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.019470Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-4 +2026-07-20T04:56:55.026351Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.026357Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-1 +2026-07-20T04:56:55.041359Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.041373Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:55.049708Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.049720Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:55.199492Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.199554Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:56:55.206421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.206429Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:56:55.214465Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.214483Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-4 +2026-07-20T04:56:55.221464Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.221497Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-5 +2026-07-20T04:56:55.236372Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.236386Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-6 +2026-07-20T04:56:55.244454Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.244468Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=-10 +2026-07-20T04:56:55.251457Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.251486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-9 +2026-07-20T04:56:55.259495Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.259513Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=-15 +2026-07-20T04:56:55.266452Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.266466Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-13 +2026-07-20T04:56:55.274480Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.274519Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-22 +2026-07-20T04:56:55.281490Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.281530Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-17 +2026-07-20T04:56:55.289485Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.289498Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-17 +2026-07-20T04:56:55.296373Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.296386Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-26 +2026-07-20T04:56:55.304374Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.304400Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-24 +2026-07-20T04:56:55.311403Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.311443Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=-20 +2026-07-20T04:56:55.319428Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.319460Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=-15 +2026-07-20T04:56:55.326419Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.326458Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=-11 +2026-07-20T04:56:55.331982Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:56:55.331995Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:56:55.331997Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:55.331999Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:55.332001Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:55.332003Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:56:55.332005Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:56:55.332007Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:56:55.332009Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:55.332011Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:55.332013Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:55.332015Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:56:55.332017Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:56:55.332019Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:56:55.332021Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:56:55.332023Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:56:55.332028Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=2 +2026-07-20T04:56:55.332042Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:56:55.333408Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:56:55.334344Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 234, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.334378Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-22 dy=-5 +2026-07-20T04:56:55.340392Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:56:55.340493Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:56:55.341354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 222, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.341367Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-34 dy=-2 +2026-07-20T04:56:55.348325Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:56:55.349435Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:56:55.351282Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.351294Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-35 dy=0 +2026-07-20T04:56:55.356338Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 220, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.356373Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-36 dy=5 +2026-07-20T04:56:55.364381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 214, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.364397Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-42 dy=9 +2026-07-20T04:56:55.371416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 218, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.371429Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-38 dy=13 +2026-07-20T04:56:55.379497Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 219, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.379538Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-37 dy=14 +2026-07-20T04:56:55.386325Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 221, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.386345Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-35 dy=18 +2026-07-20T04:56:55.394421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 216, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.394463Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-40 dy=27 +2026-07-20T04:56:55.401507Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.401520Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=24 +2026-07-20T04:56:55.409339Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 230, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.409351Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-26 dy=29 +2026-07-20T04:56:55.416337Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 233, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.416350Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-23 dy=33 +2026-07-20T04:56:55.424484Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.424498Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=29 +2026-07-20T04:56:55.431522Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.431545Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=26 +2026-07-20T04:56:55.439390Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.439407Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=31 +2026-07-20T04:56:55.446355Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.446368Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=21 +2026-07-20T04:56:55.454383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.454407Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=18 +2026-07-20T04:56:55.461427Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.461443Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=16 +2026-07-20T04:56:55.469455Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 23, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.469492Z INFO openlogi_hid::gesture: SPIKE raw xy dx=23 dy=12 +2026-07-20T04:56:55.476402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 35, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.476415Z INFO openlogi_hid::gesture: SPIKE raw xy dx=35 dy=10 +2026-07-20T04:56:55.484383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 34, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.484396Z INFO openlogi_hid::gesture: SPIKE raw xy dx=34 dy=6 +2026-07-20T04:56:55.491467Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 37, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.491504Z INFO openlogi_hid::gesture: SPIKE raw xy dx=37 dy=4 +2026-07-20T04:56:55.499453Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.499467Z INFO openlogi_hid::gesture: SPIKE raw xy dx=40 dy=0 +2026-07-20T04:56:55.506511Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 48, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.506544Z INFO openlogi_hid::gesture: SPIKE raw xy dx=48 dy=-3 +2026-07-20T04:56:55.514420Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 45, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.514436Z INFO openlogi_hid::gesture: SPIKE raw xy dx=45 dy=-8 +2026-07-20T04:56:55.521472Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 37, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.521485Z INFO openlogi_hid::gesture: SPIKE raw xy dx=37 dy=-9 +2026-07-20T04:56:55.529435Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 45, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.529454Z INFO openlogi_hid::gesture: SPIKE raw xy dx=45 dy=-15 +2026-07-20T04:56:55.536412Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 35, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.536431Z INFO openlogi_hid::gesture: SPIKE raw xy dx=35 dy=-15 +2026-07-20T04:56:55.544535Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 31, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.544548Z INFO openlogi_hid::gesture: SPIKE raw xy dx=31 dy=-19 +2026-07-20T04:56:55.551419Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 255, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.551432Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=-25 +2026-07-20T04:56:55.559487Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.559500Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-24 +2026-07-20T04:56:55.566418Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 255, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.566432Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=-26 +2026-07-20T04:56:55.574469Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.574554Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-27 +2026-07-20T04:56:55.581452Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.581465Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-27 +2026-07-20T04:56:55.589465Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.589479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-26 +2026-07-20T04:56:55.596354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.596377Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-24 +2026-07-20T04:56:55.604451Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 236, 255, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.604488Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-20 dy=-27 +2026-07-20T04:56:55.611395Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 236, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.611408Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-20 dy=-18 +2026-07-20T04:56:55.619401Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 225, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.619417Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-31 dy=-19 +2026-07-20T04:56:55.626404Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 226, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.626419Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-30 dy=-14 +2026-07-20T04:56:55.634486Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 216, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.634504Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-40 dy=-11 +2026-07-20T04:56:55.641474Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 220, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.641491Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-36 dy=-5 +2026-07-20T04:56:55.649453Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 212, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.649485Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-44 dy=-2 +2026-07-20T04:56:55.656341Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.656355Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-36 dy=0 +2026-07-20T04:56:55.664466Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 222, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.664480Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-34 dy=3 +2026-07-20T04:56:55.671310Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 224, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.671323Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-32 dy=6 +2026-07-20T04:56:55.679478Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 222, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.679491Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-34 dy=8 +2026-07-20T04:56:55.686396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 234, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.686417Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-22 dy=8 +2026-07-20T04:56:55.694363Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.694378Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=8 +2026-07-20T04:56:55.701421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.701433Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=9 +2026-07-20T04:56:55.709410Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.709427Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=8 +2026-07-20T04:56:55.716357Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.716379Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=8 +2026-07-20T04:56:55.724475Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.724489Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=7 +2026-07-20T04:56:55.731403Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.731417Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=9 +2026-07-20T04:56:55.739402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.739417Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=7 +2026-07-20T04:56:55.746427Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.746440Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=9 +2026-07-20T04:56:55.754388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.754401Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=5 +2026-07-20T04:56:55.761419Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 32, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.761444Z INFO openlogi_hid::gesture: SPIKE raw xy dx=32 dy=6 +2026-07-20T04:56:55.769330Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 26, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.769347Z INFO openlogi_hid::gesture: SPIKE raw xy dx=26 dy=3 +2026-07-20T04:56:55.776417Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 33, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.776438Z INFO openlogi_hid::gesture: SPIKE raw xy dx=33 dy=3 +2026-07-20T04:56:55.784345Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 40, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.784359Z INFO openlogi_hid::gesture: SPIKE raw xy dx=40 dy=4 +2026-07-20T04:56:55.791375Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 34, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.791388Z INFO openlogi_hid::gesture: SPIKE raw xy dx=34 dy=3 +2026-07-20T04:56:55.799634Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 30, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.799648Z INFO openlogi_hid::gesture: SPIKE raw xy dx=30 dy=2 +2026-07-20T04:56:55.806550Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.806579Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=3 +2026-07-20T04:56:55.814445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 27, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.814459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=27 dy=3 +2026-07-20T04:56:55.821495Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 26, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.821508Z INFO openlogi_hid::gesture: SPIKE raw xy dx=26 dy=4 +2026-07-20T04:56:55.829468Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.829480Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=3 +2026-07-20T04:56:55.836376Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.836392Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=5 +2026-07-20T04:56:55.844457Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.844474Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=3 +2026-07-20T04:56:55.851291Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.851305Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=4 +2026-07-20T04:56:55.859399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.859425Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=4 +2026-07-20T04:56:55.866436Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.866457Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=3 +2026-07-20T04:56:55.874381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.874396Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=4 +2026-07-20T04:56:55.881456Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.881469Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=4 +2026-07-20T04:56:55.889344Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.889361Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=4 +2026-07-20T04:56:55.896429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.896448Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=4 +2026-07-20T04:56:55.904390Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.904413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=2 +2026-07-20T04:56:55.919486Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.919524Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=2 +2026-07-20T04:56:55.926491Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 224, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.926512Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-32 dy=1 +2026-07-20T04:56:55.934441Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.934454Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=0 +2026-07-20T04:56:55.941464Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.941496Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=0 +2026-07-20T04:56:55.949354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.949369Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=-2 +2026-07-20T04:56:55.964417Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.964439Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=0 +2026-07-20T04:56:55.971543Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.971566Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-1 +2026-07-20T04:56:55.979421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.979439Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=0 +2026-07-20T04:56:55.986472Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:55.986492Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:56.001487Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.001521Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=0 +2026-07-20T04:56:56.009434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.009464Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=0 +2026-07-20T04:56:56.016476Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.016510Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=0 +2026-07-20T04:56:56.024432Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.024480Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=0 +2026-07-20T04:56:56.031422Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.031447Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=0 +2026-07-20T04:56:56.046374Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.046403Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=1 +2026-07-20T04:56:56.054537Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.054568Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=0 +2026-07-20T04:56:56.061380Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.061396Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:56:56.069416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.069450Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:56:56.121410Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.121430Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:56:56.129422Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.129440Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=2 +2026-07-20T04:56:56.136407Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.136421Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=3 +2026-07-20T04:56:56.144394Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.144407Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=3 +2026-07-20T04:56:56.151407Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.151422Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=3 +2026-07-20T04:56:56.159378Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.159405Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=3 +2026-07-20T04:56:56.166372Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.166403Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=1 +2026-07-20T04:56:56.174485Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.174499Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=4 +2026-07-20T04:56:56.181418Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.181443Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=3 +2026-07-20T04:56:56.189476Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.189501Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=4 +2026-07-20T04:56:56.196455Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.196469Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=5 +2026-07-20T04:56:56.204462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.204475Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=5 +2026-07-20T04:56:56.211497Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.211533Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=2 +2026-07-20T04:56:56.219430Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.219443Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=6 +2026-07-20T04:56:56.226427Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.226441Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=5 +2026-07-20T04:56:56.234379Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.234393Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=3 +2026-07-20T04:56:56.241435Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.241451Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=6 +2026-07-20T04:56:56.249497Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.249514Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=7 +2026-07-20T04:56:56.256395Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.256426Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=2 +2026-07-20T04:56:56.264462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.264471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=5 +2026-07-20T04:56:56.271406Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.271417Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=2 +2026-07-20T04:56:56.279354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.279381Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=3 +2026-07-20T04:56:56.286399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.286429Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=1 +2026-07-20T04:56:56.294445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.294472Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=1 +2026-07-20T04:56:56.301390Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.301402Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=0 +2026-07-20T04:56:56.309407Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.309444Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-1 +2026-07-20T04:56:56.324404Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.324422Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-2 +2026-07-20T04:56:56.331396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.331420Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-4 +2026-07-20T04:56:56.339444Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 34, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.339479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=34 dy=-12 +2026-07-20T04:56:56.346403Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.346418Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=-7 +2026-07-20T04:56:56.354464Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.354479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=-7 +2026-07-20T04:56:56.361397Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.361413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=-8 +2026-07-20T04:56:56.369458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.369472Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-7 +2026-07-20T04:56:56.376355Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.376368Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=-5 +2026-07-20T04:56:56.384496Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.384536Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-7 +2026-07-20T04:56:56.391398Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.391413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-5 +2026-07-20T04:56:56.399445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.399459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-3 +2026-07-20T04:56:56.414467Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.414481Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-2 +2026-07-20T04:56:56.421395Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.421419Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-2 +2026-07-20T04:56:56.429398Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.429418Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=-7 +2026-07-20T04:56:56.436481Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.436526Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-5 +2026-07-20T04:56:56.444340Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 228, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.444352Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-28 dy=-7 +2026-07-20T04:56:56.451394Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.451408Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=-6 +2026-07-20T04:56:56.459479Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 223, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.459494Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-33 dy=-10 +2026-07-20T04:56:56.466395Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 227, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.466408Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-29 dy=-8 +2026-07-20T04:56:56.474447Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 228, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.474459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-28 dy=-10 +2026-07-20T04:56:56.481489Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 231, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.481503Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-25 dy=-9 +2026-07-20T04:56:56.489468Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.489495Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=-13 +2026-07-20T04:56:56.496521Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.496562Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=-9 +2026-07-20T04:56:56.504468Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.504496Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-12 +2026-07-20T04:56:56.511466Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.511479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-7 +2026-07-20T04:56:56.519493Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.526502Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-8 +2026-07-20T04:56:56.526545Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.526555Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-9 +2026-07-20T04:56:56.534498Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.534513Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-7 +2026-07-20T04:56:56.541424Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.541436Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-9 +2026-07-20T04:56:56.549549Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.549562Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-6 +2026-07-20T04:56:56.556304Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 24, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.556333Z INFO openlogi_hid::gesture: SPIKE raw xy dx=24 dy=-6 +2026-07-20T04:56:56.564400Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 21, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.564427Z INFO openlogi_hid::gesture: SPIKE raw xy dx=21 dy=-2 +2026-07-20T04:56:56.571387Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.571413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=29 dy=0 +2026-07-20T04:56:56.579335Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 29, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.579348Z INFO openlogi_hid::gesture: SPIKE raw xy dx=29 dy=4 +2026-07-20T04:56:56.586485Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 37, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.586523Z INFO openlogi_hid::gesture: SPIKE raw xy dx=37 dy=10 +2026-07-20T04:56:56.594361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 32, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.594375Z INFO openlogi_hid::gesture: SPIKE raw xy dx=32 dy=13 +2026-07-20T04:56:56.601373Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 34, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.601388Z INFO openlogi_hid::gesture: SPIKE raw xy dx=34 dy=19 +2026-07-20T04:56:56.609515Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.609531Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=21 +2026-07-20T04:56:56.616419Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.616456Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=24 +2026-07-20T04:56:56.625498Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.625528Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=21 +2026-07-20T04:56:56.631413Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.631437Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=29 +2026-07-20T04:56:56.639471Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.639485Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=21 +2026-07-20T04:56:56.646473Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.646511Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=25 +2026-07-20T04:56:56.654331Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.654347Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=17 +2026-07-20T04:56:56.661377Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.661396Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=19 +2026-07-20T04:56:56.669390Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.669404Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=10 +2026-07-20T04:56:56.676373Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.676386Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=7 +2026-07-20T04:56:56.684464Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.684494Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=4 +2026-07-20T04:56:56.691480Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.691492Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=0 +2026-07-20T04:56:56.699438Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 225, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.699446Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-31 dy=-6 +2026-07-20T04:56:56.706388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 231, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.706401Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-25 dy=-7 +2026-07-20T04:56:56.714456Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 224, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.714469Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-32 dy=-14 +2026-07-20T04:56:56.721461Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 220, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.721475Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-36 dy=-19 +2026-07-20T04:56:56.729468Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 230, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.729488Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-26 dy=-18 +2026-07-20T04:56:56.736371Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.736386Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=-20 +2026-07-20T04:56:56.744367Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 255, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.744380Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=-21 +2026-07-20T04:56:56.751346Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.751374Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=-18 +2026-07-20T04:56:56.759456Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 255, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.759494Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=-23 +2026-07-20T04:56:56.766341Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.766353Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-15 +2026-07-20T04:56:56.774342Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.774363Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-20 +2026-07-20T04:56:56.781343Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.781377Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-12 +2026-07-20T04:56:56.789333Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.789348Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-12 +2026-07-20T04:56:56.796359Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.796375Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-6 +2026-07-20T04:56:56.804493Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.804515Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-1 +2026-07-20T04:56:56.811492Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.811522Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=1 +2026-07-20T04:56:56.819358Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.819371Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=4 +2026-07-20T04:56:56.826387Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.826400Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=9 +2026-07-20T04:56:56.834514Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.834545Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=9 +2026-07-20T04:56:56.841434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 21, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.841479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=21 dy=12 +2026-07-20T04:56:56.849498Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 23, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.849538Z INFO openlogi_hid::gesture: SPIKE raw xy dx=23 dy=16 +2026-07-20T04:56:56.856445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.856463Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=18 +2026-07-20T04:56:56.858505Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:56:56.861415Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:56.861485Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:56.870397Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:56:56.871454Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.871467Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=13 +2026-07-20T04:56:56.878385Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:56:56.878422Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:56:56.879451Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.879477Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=18 +2026-07-20T04:56:56.880462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.880475Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=13 +2026-07-20T04:56:56.887339Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.887358Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=10 +2026-07-20T04:56:56.894331Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.894344Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=8 +2026-07-20T04:56:56.901388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.903425Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:56.903495Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:56.906352Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:56.906352Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:56.908461Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:56.908473Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:56.909508Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.909521Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=5 +2026-07-20T04:56:56.911459Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:56:56.911476Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:56:56.916445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.916458Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=3 +2026-07-20T04:56:56.924399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 236, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.924412Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-20 dy=-2 +2026-07-20T04:56:56.931453Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.931466Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-6 +2026-07-20T04:56:56.939418Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.939430Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=-10 +2026-07-20T04:56:56.946503Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.946533Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=-10 +2026-07-20T04:56:56.954466Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.954481Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-13 +2026-07-20T04:56:56.961396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.961422Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-15 +2026-07-20T04:56:56.969402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.969420Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=-15 +2026-07-20T04:56:56.976345Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.976366Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-15 +2026-07-20T04:56:56.984368Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.984382Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-12 +2026-07-20T04:56:56.991460Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.991472Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-8 +2026-07-20T04:56:56.999498Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:56.999525Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-4 +2026-07-20T04:56:57.006392Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.006407Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-2 +2026-07-20T04:56:57.014418Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.014433Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=0 +2026-07-20T04:56:57.021390Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.021403Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=0 +2026-07-20T04:56:57.029510Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.029522Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=4 +2026-07-20T04:56:57.036465Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.036478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=6 +2026-07-20T04:56:57.044581Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.044626Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=11 +2026-07-20T04:56:57.051532Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.051553Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=10 +2026-07-20T04:56:57.059472Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.059505Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=14 +2026-07-20T04:56:57.066416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.066430Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=9 +2026-07-20T04:56:57.074407Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.074423Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=17 +2026-07-20T04:56:57.081366Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.081403Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=11 +2026-07-20T04:56:57.089469Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.089477Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=12 +2026-07-20T04:56:57.096398Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.096435Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=11 +2026-07-20T04:56:57.104446Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.104459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=7 +2026-07-20T04:56:57.111464Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.111486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=5 +2026-07-20T04:56:57.119354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.119367Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=4 +2026-07-20T04:56:57.126366Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.126379Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=2 +2026-07-20T04:56:57.134370Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.134390Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=0 +2026-07-20T04:56:57.141319Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.141332Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=-2 +2026-07-20T04:56:57.149371Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.149384Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-3 +2026-07-20T04:56:57.156290Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.156304Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=-5 +2026-07-20T04:56:57.164421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.164433Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-5 +2026-07-20T04:56:57.171515Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.171550Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=-8 +2026-07-20T04:56:57.179410Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.179432Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-6 +2026-07-20T04:56:57.186444Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.186464Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-9 +2026-07-20T04:56:57.194392Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.194423Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-8 +2026-07-20T04:56:57.201430Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.201449Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-5 +2026-07-20T04:56:57.209539Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.209562Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-9 +2026-07-20T04:56:57.216423Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.216446Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-8 +2026-07-20T04:56:57.224478Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.224514Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-4 +2026-07-20T04:56:57.231411Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.231428Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-5 +2026-07-20T04:56:57.239386Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.239399Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=-2 +2026-07-20T04:56:57.246335Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.246350Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=0 +2026-07-20T04:56:57.254347Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.254373Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=0 +2026-07-20T04:56:57.261392Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.261409Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=3 +2026-07-20T04:56:57.269380Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.269406Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=3 +2026-07-20T04:56:57.276385Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.276403Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=7 +2026-07-20T04:56:57.284342Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.284367Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=6 +2026-07-20T04:56:57.291382Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.291394Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=7 +2026-07-20T04:56:57.299344Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.299371Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=7 +2026-07-20T04:56:57.306351Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.306357Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=8 +2026-07-20T04:56:57.314380Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.314393Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=5 +2026-07-20T04:56:57.321389Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.321402Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=6 +2026-07-20T04:56:57.329444Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.329497Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=3 +2026-07-20T04:56:57.336375Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.336413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=2 +2026-07-20T04:56:57.344396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.344409Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=2 +2026-07-20T04:56:57.351384Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.351398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=2 +2026-07-20T04:56:57.359423Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.359442Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=1 +2026-07-20T04:56:57.366393Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.366405Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=0 +2026-07-20T04:56:57.374405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.374437Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=0 +2026-07-20T04:56:57.381397Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.381423Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=0 +2026-07-20T04:56:57.389338Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.389351Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-1 +2026-07-20T04:56:57.396383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.396396Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-2 +2026-07-20T04:56:57.404342Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.404363Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-3 +2026-07-20T04:56:57.411454Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.411469Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-2 +2026-07-20T04:56:57.419395Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.419423Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-3 +2026-07-20T04:56:57.426352Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.426365Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-2 +2026-07-20T04:56:57.434605Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.434620Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-4 +2026-07-20T04:56:57.441365Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.441378Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-3 +2026-07-20T04:56:57.449508Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.449521Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-3 +2026-07-20T04:56:57.456413Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.456427Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-2 +2026-07-20T04:56:57.464482Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.464495Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-1 +2026-07-20T04:56:57.471522Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.471542Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-2 +2026-07-20T04:56:57.479441Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.479480Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-1 +2026-07-20T04:56:57.486408Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.486421Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:57.501366Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.501380Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-1 +2026-07-20T04:56:57.509298Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.509310Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:57.531474Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:57.531500Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:58.927376Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:58.927442Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:56:58.934313Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:58.934336Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:56:58.941312Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:56:58.949307Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:58.949331Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-8 +2026-07-20T04:56:58.956309Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:58.956334Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-18 +2026-07-20T04:56:58.964315Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:56:58.971362Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:58.971401Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-10 +2026-07-20T04:56:58.979368Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:58.979402Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=-18 +2026-07-20T04:56:58.986329Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:58.986466Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-10 +2026-07-20T04:56:58.994317Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:58.994344Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-11 +2026-07-20T04:56:59.001302Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.001332Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-8 +2026-07-20T04:56:59.010336Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.010408Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=-15 +2026-07-20T04:56:59.017388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.017420Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-11 +2026-07-20T04:56:59.024308Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.024332Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=-11 +2026-07-20T04:56:59.032317Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.032344Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=-13 +2026-07-20T04:56:59.034336Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:56:59.034367Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:56:59.034376Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:59.034383Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:59.034389Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:59.034395Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:56:59.034401Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:56:59.034407Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:56:59.034413Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:56:59.034419Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:59.034425Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:56:59.034431Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:56:59.034437Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:56:59.034548Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:56:59.034557Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:56:59.034564Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:56:59.034576Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=2 +2026-07-20T04:56:59.034595Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:56:59.037305Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:56:59.043329Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:56:59.043409Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:56:59.045294Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.045312Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=-8 +2026-07-20T04:56:59.052425Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:56:59.053311Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:56:59.054288Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.054315Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=-8 +2026-07-20T04:56:59.056326Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.056353Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=-4 +2026-07-20T04:56:59.061339Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 231, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.061370Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-25 dy=-6 +2026-07-20T04:56:59.069339Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.069374Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-3 +2026-07-20T04:56:59.076300Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.076323Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=-4 +2026-07-20T04:56:59.084439Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.084463Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-2 +2026-07-20T04:56:59.091357Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.091380Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-1 +2026-07-20T04:56:59.099353Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.099479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=0 +2026-07-20T04:56:59.103905Z DEBUG openlogi_agent_core::watchers::foreground_app: frontmost app changed current=Some("c:\\program files\\windowsapps\\claude_1.22209.3.0_x64__pzs8sxrjxfjjc\\app\\claude.exe") last=Some("c:\\program files (x86)\\steam\\steamapps\\common\\command & conquer generals - zero hour\\game.dat") +2026-07-20T04:56:59.106300Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.106319Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=0 +2026-07-20T04:56:59.114325Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.114349Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=2 +2026-07-20T04:56:59.121313Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.121338Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=3 +2026-07-20T04:56:59.129311Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.129337Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=3 +2026-07-20T04:56:59.136330Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.136362Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=5 +2026-07-20T04:56:59.144317Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.144349Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=7 +2026-07-20T04:56:59.151324Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.151356Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=8 +2026-07-20T04:56:59.159406Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.159475Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=8 +2026-07-20T04:56:59.166312Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.166337Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=9 +2026-07-20T04:56:59.174340Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.174370Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=16 +2026-07-20T04:56:59.181342Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.181367Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=12 +2026-07-20T04:56:59.189351Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.189467Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=14 +2026-07-20T04:56:59.196355Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.196388Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=15 +2026-07-20T04:56:59.204345Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.204367Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=18 +2026-07-20T04:56:59.211324Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.211344Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=18 +2026-07-20T04:56:59.219332Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.219380Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=18 +2026-07-20T04:56:59.226388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.226414Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=18 +2026-07-20T04:56:59.234322Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.234352Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=19 +2026-07-20T04:56:59.241317Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.241349Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=27 +2026-07-20T04:56:59.249307Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.249340Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=17 +2026-07-20T04:56:59.256334Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.256368Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=16 +2026-07-20T04:56:59.264349Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.264398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=15 +2026-07-20T04:56:59.271322Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.271344Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=16 +2026-07-20T04:56:59.279386Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.279410Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=8 +2026-07-20T04:56:59.286303Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.286329Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=12 +2026-07-20T04:56:59.294335Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.294361Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=7 +2026-07-20T04:56:59.301374Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.301418Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=4 +2026-07-20T04:56:59.309371Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.309402Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=4 +2026-07-20T04:56:59.316309Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.316332Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=2 +2026-07-20T04:56:59.324370Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.324396Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=0 +2026-07-20T04:56:59.331368Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.331386Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=0 +2026-07-20T04:56:59.339398Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.339413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-3 +2026-07-20T04:56:59.346303Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 27, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.346360Z INFO openlogi_hid::gesture: SPIKE raw xy dx=27 dy=-4 +2026-07-20T04:56:59.354359Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 23, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.354376Z INFO openlogi_hid::gesture: SPIKE raw xy dx=23 dy=-6 +2026-07-20T04:56:59.361392Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 26, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.361409Z INFO openlogi_hid::gesture: SPIKE raw xy dx=26 dy=-8 +2026-07-20T04:56:59.369350Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 21, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.369404Z INFO openlogi_hid::gesture: SPIKE raw xy dx=21 dy=-7 +2026-07-20T04:56:59.376374Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 23, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.376403Z INFO openlogi_hid::gesture: SPIKE raw xy dx=23 dy=-8 +2026-07-20T04:56:59.384367Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 26, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.384415Z INFO openlogi_hid::gesture: SPIKE raw xy dx=26 dy=-11 +2026-07-20T04:56:59.391295Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 26, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.391319Z INFO openlogi_hid::gesture: SPIKE raw xy dx=26 dy=-13 +2026-07-20T04:56:59.399340Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.399374Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=-11 +2026-07-20T04:56:59.406331Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.406362Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-10 +2026-07-20T04:56:59.414360Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.414387Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=-18 +2026-07-20T04:56:59.421313Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.421337Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-13 +2026-07-20T04:56:59.429305Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.429324Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-13 +2026-07-20T04:56:59.436307Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 21, 255, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.436329Z INFO openlogi_hid::gesture: SPIKE raw xy dx=21 dy=-22 +2026-07-20T04:56:59.444315Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.444348Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-8 +2026-07-20T04:56:59.451364Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.451382Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=-24 +2026-07-20T04:56:59.459382Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.459406Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-13 +2026-07-20T04:56:59.466292Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.466307Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-19 +2026-07-20T04:56:59.474330Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.474346Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-14 +2026-07-20T04:56:59.481383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.481401Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-15 +2026-07-20T04:56:59.489360Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.489396Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-15 +2026-07-20T04:56:59.496381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.496413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-9 +2026-07-20T04:56:59.504453Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.504487Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-15 +2026-07-20T04:56:59.511564Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.511619Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-9 +2026-07-20T04:56:59.519367Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.519395Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-8 +2026-07-20T04:56:59.526355Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.526387Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-9 +2026-07-20T04:56:59.534435Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.534474Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=-7 +2026-07-20T04:56:59.541374Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.541406Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-3 +2026-07-20T04:56:59.549393Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.549424Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=-3 +2026-07-20T04:56:59.556368Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.556392Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=-2 +2026-07-20T04:56:59.564406Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.564429Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=-2 +2026-07-20T04:56:59.571336Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.571364Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-1 +2026-07-20T04:56:59.579402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.579428Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-2 +2026-07-20T04:56:59.586455Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.586489Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=-1 +2026-07-20T04:56:59.594461Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.594490Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-1 +2026-07-20T04:56:59.601365Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.601390Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=-2 +2026-07-20T04:56:59.609309Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.609356Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-1 +2026-07-20T04:56:59.616323Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.616345Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=-2 +2026-07-20T04:56:59.624358Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.624394Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=-1 +2026-07-20T04:56:59.631317Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.631338Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=-2 +2026-07-20T04:56:59.639304Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.639330Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=0 +2026-07-20T04:56:59.646323Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.646359Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=-1 +2026-07-20T04:56:59.654292Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.654315Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=0 +2026-07-20T04:56:59.661333Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.661356Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=0 +2026-07-20T04:56:59.669292Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.669327Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=1 +2026-07-20T04:56:59.676284Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.676303Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=1 +2026-07-20T04:56:59.684414Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.684430Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=2 +2026-07-20T04:56:59.691325Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.691340Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=2 +2026-07-20T04:56:59.699323Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.699341Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=1 +2026-07-20T04:56:59.706460Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.706477Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=2 +2026-07-20T04:56:59.714428Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.714443Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=3 +2026-07-20T04:56:59.721331Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.721349Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=3 +2026-07-20T04:56:59.729374Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.729396Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=5 +2026-07-20T04:56:59.736414Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.736437Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=6 +2026-07-20T04:56:59.744517Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.744534Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=5 +2026-07-20T04:56:59.751466Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.751495Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=10 +2026-07-20T04:56:59.759506Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.759528Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=8 +2026-07-20T04:56:59.766464Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.766487Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=9 +2026-07-20T04:56:59.774526Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.774559Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=15 +2026-07-20T04:56:59.781401Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.781427Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=11 +2026-07-20T04:56:59.789561Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.789608Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=11 +2026-07-20T04:56:59.796499Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.796529Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=6 +2026-07-20T04:56:59.804585Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.804615Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=13 +2026-07-20T04:56:59.811580Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.811611Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=12 +2026-07-20T04:56:59.819483Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.819513Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=14 +2026-07-20T04:56:59.826388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.826424Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=14 +2026-07-20T04:56:59.834597Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.834636Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=9 +2026-07-20T04:56:59.841576Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.841620Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=14 +2026-07-20T04:56:59.849377Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.849396Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=10 +2026-07-20T04:56:59.856421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.856452Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=11 +2026-07-20T04:56:59.864494Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.864511Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=10 +2026-07-20T04:56:59.871392Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.871413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=15 +2026-07-20T04:56:59.879391Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.879420Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=9 +2026-07-20T04:56:59.886669Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.886713Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=9 +2026-07-20T04:56:59.894577Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.894609Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=12 +2026-07-20T04:56:59.901498Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.901518Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=9 +2026-07-20T04:56:59.909528Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.909546Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=8 +2026-07-20T04:56:59.916578Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.916615Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=7 +2026-07-20T04:56:59.924405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.924419Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=8 +2026-07-20T04:56:59.931488Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.931505Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=7 +2026-07-20T04:56:59.939462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.939503Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=6 +2026-07-20T04:56:59.946332Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.946367Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=5 +2026-07-20T04:56:59.954486Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.954527Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=4 +2026-07-20T04:56:59.961486Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.961527Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=4 +2026-07-20T04:56:59.969493Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.969539Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=4 +2026-07-20T04:56:59.976651Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.976686Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=4 +2026-07-20T04:56:59.984362Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.984400Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=4 +2026-07-20T04:56:59.991507Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.991517Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=3 +2026-07-20T04:56:59.999489Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:56:59.999506Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=1 +2026-07-20T04:57:00.006362Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.006382Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=2 +2026-07-20T04:57:00.014516Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.014548Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=0 +2026-07-20T04:57:00.021405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.021434Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-2 +2026-07-20T04:57:00.029377Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.029400Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:57:00.036390Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.036426Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-3 +2026-07-20T04:57:00.044511Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.044544Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-5 +2026-07-20T04:57:00.051491Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.051532Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-6 +2026-07-20T04:57:00.059374Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.059394Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-8 +2026-07-20T04:57:00.066486Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.066522Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=-9 +2026-07-20T04:57:00.074481Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.074517Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-7 +2026-07-20T04:57:00.081482Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.081515Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=-12 +2026-07-20T04:57:00.089480Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.089516Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=-9 +2026-07-20T04:57:00.096469Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.096499Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=-9 +2026-07-20T04:57:00.104412Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.104438Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-8 +2026-07-20T04:57:00.111477Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.111495Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=-11 +2026-07-20T04:57:00.119532Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.119557Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=-6 +2026-07-20T04:57:00.126357Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 30, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.126373Z INFO openlogi_hid::gesture: SPIKE raw xy dx=30 dy=-7 +2026-07-20T04:57:00.134449Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.134472Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=-4 +2026-07-20T04:57:00.141308Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.141321Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=-2 +2026-07-20T04:57:00.149512Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 27, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.149550Z INFO openlogi_hid::gesture: SPIKE raw xy dx=27 dy=-3 +2026-07-20T04:57:00.156377Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.156389Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=-1 +2026-07-20T04:57:00.164505Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.164518Z INFO openlogi_hid::gesture: SPIKE raw xy dx=21 dy=0 +2026-07-20T04:57:00.171465Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.171484Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=-1 +2026-07-20T04:57:00.179588Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.179610Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=0 +2026-07-20T04:57:00.186365Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.186384Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=0 +2026-07-20T04:57:00.194477Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.194515Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=0 +2026-07-20T04:57:00.201532Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.201549Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=1 +2026-07-20T04:57:00.209402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.209424Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:57:00.404412Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.404449Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:57:00.419625Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.419661Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-2 +2026-07-20T04:57:00.426644Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.426679Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-3 +2026-07-20T04:57:00.434776Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.434846Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-2 +2026-07-20T04:57:00.441518Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.441538Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-6 +2026-07-20T04:57:00.449393Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.449411Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-5 +2026-07-20T04:57:00.456472Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.456506Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=-10 +2026-07-20T04:57:00.464438Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.464474Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-8 +2026-07-20T04:57:00.471436Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.471471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-9 +2026-07-20T04:57:00.479513Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.479550Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-12 +2026-07-20T04:57:00.486439Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.486482Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-12 +2026-07-20T04:57:00.494350Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.494379Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=-20 +2026-07-20T04:57:00.501321Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.501336Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-14 +2026-07-20T04:57:00.509335Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.509375Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-14 +2026-07-20T04:57:00.516412Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.516446Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-16 +2026-07-20T04:57:00.524439Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.524470Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-19 +2026-07-20T04:57:00.531412Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.531430Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-15 +2026-07-20T04:57:00.539432Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.539454Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-14 +2026-07-20T04:57:00.546434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.546466Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-15 +2026-07-20T04:57:00.554436Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.554462Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-10 +2026-07-20T04:57:00.561510Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.561546Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=-8 +2026-07-20T04:57:00.567680Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:00.569518Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.569551Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=-6 +2026-07-20T04:57:00.571448Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:00.571573Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:00.582527Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:00.583437Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.583461Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=-6 +2026-07-20T04:57:00.590474Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:00.590539Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:00.591590Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.591619Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=-3 +2026-07-20T04:57:00.592449Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 236, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.592476Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-20 dy=-1 +2026-07-20T04:57:00.599434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 231, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.608391Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-25 dy=-1 +2026-07-20T04:57:00.608492Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 218, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.608501Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-38 dy=1 +2026-07-20T04:57:00.614437Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.617386Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:00.617474Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:00.619467Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:00.619549Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:00.620468Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:00.620485Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:00.621453Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 226, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.621490Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-30 dy=3 +2026-07-20T04:57:00.622468Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:00.622470Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:00.629359Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 191, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.629385Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-65 dy=12 +2026-07-20T04:57:00.636481Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 217, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.636500Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-39 dy=9 +2026-07-20T04:57:00.644643Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 228, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.644669Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-28 dy=7 +2026-07-20T04:57:00.651503Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 218, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.651528Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-38 dy=11 +2026-07-20T04:57:00.659472Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 230, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.659497Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-26 dy=9 +2026-07-20T04:57:00.666458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 222, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.666478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-34 dy=13 +2026-07-20T04:57:00.674588Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 231, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.674625Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-25 dy=10 +2026-07-20T04:57:00.681493Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 233, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.681514Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-23 dy=11 +2026-07-20T04:57:00.689366Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 234, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.689389Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-22 dy=11 +2026-07-20T04:57:00.696443Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.696481Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=8 +2026-07-20T04:57:00.704503Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.704539Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=10 +2026-07-20T04:57:00.711429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.711464Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=6 +2026-07-20T04:57:00.719553Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.719578Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=5 +2026-07-20T04:57:00.726643Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.726681Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=3 +2026-07-20T04:57:00.734559Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.734595Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=2 +2026-07-20T04:57:00.741527Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.741552Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=0 +2026-07-20T04:57:00.749489Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.749523Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=0 +2026-07-20T04:57:00.756428Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.756455Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=0 +2026-07-20T04:57:00.764560Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.764586Z INFO openlogi_hid::gesture: SPIKE raw xy dx=23 dy=0 +2026-07-20T04:57:00.771555Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.771572Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=0 +2026-07-20T04:57:00.779469Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.779516Z INFO openlogi_hid::gesture: SPIKE raw xy dx=32 dy=0 +2026-07-20T04:57:00.786395Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.786410Z INFO openlogi_hid::gesture: SPIKE raw xy dx=31 dy=0 +2026-07-20T04:57:00.794478Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 39, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.794505Z INFO openlogi_hid::gesture: SPIKE raw xy dx=39 dy=2 +2026-07-20T04:57:00.801700Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 40, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.801714Z INFO openlogi_hid::gesture: SPIKE raw xy dx=40 dy=4 +2026-07-20T04:57:00.809509Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 38, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.809522Z INFO openlogi_hid::gesture: SPIKE raw xy dx=38 dy=5 +2026-07-20T04:57:00.816549Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 36, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.816574Z INFO openlogi_hid::gesture: SPIKE raw xy dx=36 dy=6 +2026-07-20T04:57:00.824487Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 44, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.824517Z INFO openlogi_hid::gesture: SPIKE raw xy dx=44 dy=10 +2026-07-20T04:57:00.831557Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 34, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.831573Z INFO openlogi_hid::gesture: SPIKE raw xy dx=34 dy=9 +2026-07-20T04:57:00.839592Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 29, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.839606Z INFO openlogi_hid::gesture: SPIKE raw xy dx=29 dy=10 +2026-07-20T04:57:00.846489Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 36, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.846505Z INFO openlogi_hid::gesture: SPIKE raw xy dx=36 dy=12 +2026-07-20T04:57:00.854673Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.854726Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=11 +2026-07-20T04:57:00.861692Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 27, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.861743Z INFO openlogi_hid::gesture: SPIKE raw xy dx=27 dy=14 +2026-07-20T04:57:00.869767Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.869815Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=16 +2026-07-20T04:57:00.876421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 23, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.876442Z INFO openlogi_hid::gesture: SPIKE raw xy dx=23 dy=18 +2026-07-20T04:57:00.884489Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.884510Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=14 +2026-07-20T04:57:00.891512Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.891535Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=16 +2026-07-20T04:57:00.899509Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.899548Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=15 +2026-07-20T04:57:00.906556Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.906589Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=10 +2026-07-20T04:57:00.914521Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.914564Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=13 +2026-07-20T04:57:00.921656Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.921745Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=10 +2026-07-20T04:57:00.929455Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.929473Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=8 +2026-07-20T04:57:00.936557Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.936599Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=9 +2026-07-20T04:57:00.944542Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.944557Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=8 +2026-07-20T04:57:00.951465Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.951500Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=6 +2026-07-20T04:57:00.959785Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.959819Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=4 +2026-07-20T04:57:00.966518Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 227, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.966557Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-29 dy=2 +2026-07-20T04:57:00.974473Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 219, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.974525Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-37 dy=2 +2026-07-20T04:57:00.981476Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.981497Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-28 dy=0 +2026-07-20T04:57:00.989425Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 218, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.989464Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-38 dy=-1 +2026-07-20T04:57:00.996412Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 218, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:00.996449Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-38 dy=-3 +2026-07-20T04:57:01.004498Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 227, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.004522Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-29 dy=-4 +2026-07-20T04:57:01.011444Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 218, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.011465Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-38 dy=-7 +2026-07-20T04:57:01.019487Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 220, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.019509Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-36 dy=-10 +2026-07-20T04:57:01.026463Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 230, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.026500Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-26 dy=-10 +2026-07-20T04:57:01.034471Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 230, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.034484Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-26 dy=-12 +2026-07-20T04:57:01.041654Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 230, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.041693Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-26 dy=-16 +2026-07-20T04:57:01.049557Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.049587Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=-20 +2026-07-20T04:57:01.056530Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.056569Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=-20 +2026-07-20T04:57:01.064403Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.064423Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-21 +2026-07-20T04:57:01.071460Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 255, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.071486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=-25 +2026-07-20T04:57:01.079486Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.079513Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-23 +2026-07-20T04:57:01.086460Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.086497Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-20 +2026-07-20T04:57:01.094415Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.094444Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-22 +2026-07-20T04:57:01.101433Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.101464Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-24 +2026-07-20T04:57:01.109382Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.109410Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-26 +2026-07-20T04:57:01.116526Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.116545Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-16 +2026-07-20T04:57:01.124401Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 227, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.124428Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-29 +2026-07-20T04:57:01.131464Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.131476Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-14 +2026-07-20T04:57:01.139512Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.139533Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=-17 +2026-07-20T04:57:01.146474Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.146497Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=-11 +2026-07-20T04:57:01.154376Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.154408Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-7 +2026-07-20T04:57:01.161489Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 26, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.161549Z INFO openlogi_hid::gesture: SPIKE raw xy dx=26 dy=-7 +2026-07-20T04:57:01.169665Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.169715Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=-2 +2026-07-20T04:57:01.176620Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.176669Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=-1 +2026-07-20T04:57:01.184527Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.184571Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=2 +2026-07-20T04:57:01.191440Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 29, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.191461Z INFO openlogi_hid::gesture: SPIKE raw xy dx=29 dy=5 +2026-07-20T04:57:01.199432Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.199452Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=8 +2026-07-20T04:57:01.206446Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.206478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=12 +2026-07-20T04:57:01.214419Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.214435Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=13 +2026-07-20T04:57:01.221468Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.221484Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=20 +2026-07-20T04:57:01.229458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.229480Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=23 +2026-07-20T04:57:01.236494Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 21, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.236536Z INFO openlogi_hid::gesture: SPIKE raw xy dx=21 dy=21 +2026-07-20T04:57:01.244605Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.244653Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=35 +2026-07-20T04:57:01.251383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.251422Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=19 +2026-07-20T04:57:01.259420Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.259433Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=29 +2026-07-20T04:57:01.266384Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.266397Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=29 +2026-07-20T04:57:01.274498Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.274545Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=21 +2026-07-20T04:57:01.281504Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.281540Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=27 +2026-07-20T04:57:01.289383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.289407Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=20 +2026-07-20T04:57:01.296394Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.296417Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=20 +2026-07-20T04:57:01.304322Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.304345Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=15 +2026-07-20T04:57:01.311650Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.311687Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=11 +2026-07-20T04:57:01.319418Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.319440Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=13 +2026-07-20T04:57:01.326543Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.326591Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=7 +2026-07-20T04:57:01.334551Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.334583Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=5 +2026-07-20T04:57:01.341499Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.341527Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=5 +2026-07-20T04:57:01.349490Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.349514Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=1 +2026-07-20T04:57:01.356431Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 223, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.356464Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-33 dy=-2 +2026-07-20T04:57:01.364541Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 233, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.364573Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-23 dy=-4 +2026-07-20T04:57:01.371546Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 230, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.371579Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-26 dy=-7 +2026-07-20T04:57:01.379441Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 233, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.379480Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-23 dy=-8 +2026-07-20T04:57:01.386688Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.386739Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=-12 +2026-07-20T04:57:01.394491Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.394533Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-12 +2026-07-20T04:57:01.401475Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.401502Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=-14 +2026-07-20T04:57:01.409499Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.409530Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-14 +2026-07-20T04:57:01.416391Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.416410Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-15 +2026-07-20T04:57:01.424436Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.424479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-12 +2026-07-20T04:57:01.431432Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.431458Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-13 +2026-07-20T04:57:01.439445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.439478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-9 +2026-07-20T04:57:01.446401Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.446445Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-9 +2026-07-20T04:57:01.454500Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.454526Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=-10 +2026-07-20T04:57:01.461418Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.461443Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-6 +2026-07-20T04:57:01.469483Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.469509Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=-7 +2026-07-20T04:57:01.476630Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 24, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.476667Z INFO openlogi_hid::gesture: SPIKE raw xy dx=24 dy=-3 +2026-07-20T04:57:01.484481Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.484532Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=-1 +2026-07-20T04:57:01.491687Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.491781Z INFO openlogi_hid::gesture: SPIKE raw xy dx=31 dy=0 +2026-07-20T04:57:01.499621Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 29, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.499656Z INFO openlogi_hid::gesture: SPIKE raw xy dx=29 dy=2 +2026-07-20T04:57:01.508582Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 29, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.508620Z INFO openlogi_hid::gesture: SPIKE raw xy dx=29 dy=5 +2026-07-20T04:57:01.514438Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 38, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.514471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=38 dy=8 +2026-07-20T04:57:01.521529Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.521551Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=7 +2026-07-20T04:57:01.529379Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 27, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.529404Z INFO openlogi_hid::gesture: SPIKE raw xy dx=27 dy=9 +2026-07-20T04:57:01.536334Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.536384Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=7 +2026-07-20T04:57:01.544448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 29, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.544486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=29 dy=13 +2026-07-20T04:57:01.551415Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.551447Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=9 +2026-07-20T04:57:01.559459Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.559488Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=10 +2026-07-20T04:57:01.566518Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.566553Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=12 +2026-07-20T04:57:01.574543Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.574582Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=10 +2026-07-20T04:57:01.581841Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.581910Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=8 +2026-07-20T04:57:01.589590Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.589641Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=8 +2026-07-20T04:57:01.596520Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.596565Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=9 +2026-07-20T04:57:01.604502Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.604531Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=10 +2026-07-20T04:57:01.611425Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.611455Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=6 +2026-07-20T04:57:01.619557Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.619587Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=9 +2026-07-20T04:57:01.626423Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.626452Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=6 +2026-07-20T04:57:01.634434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.634459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=5 +2026-07-20T04:57:01.641380Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.641406Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=5 +2026-07-20T04:57:01.649487Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.649514Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=5 +2026-07-20T04:57:01.656668Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.656705Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=4 +2026-07-20T04:57:01.664481Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.664513Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=4 +2026-07-20T04:57:01.671628Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.671663Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=2 +2026-07-20T04:57:01.679474Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.679493Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=0 +2026-07-20T04:57:01.686401Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.686425Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=0 +2026-07-20T04:57:01.694416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.694431Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-4 +2026-07-20T04:57:01.701486Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.701500Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-4 +2026-07-20T04:57:01.709350Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.709391Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=-8 +2026-07-20T04:57:01.716333Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.716350Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-7 +2026-07-20T04:57:01.724349Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.724371Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-10 +2026-07-20T04:57:01.731309Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.731333Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-11 +2026-07-20T04:57:01.739341Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.739364Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-15 +2026-07-20T04:57:01.746291Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.746317Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-18 +2026-07-20T04:57:01.754373Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.754395Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-12 +2026-07-20T04:57:01.761349Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.761365Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-13 +2026-07-20T04:57:01.769322Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.769344Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-21 +2026-07-20T04:57:01.776314Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.776353Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-13 +2026-07-20T04:57:01.784355Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.784384Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-14 +2026-07-20T04:57:01.791363Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.791393Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-12 +2026-07-20T04:57:01.799396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.799422Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-11 +2026-07-20T04:57:01.806349Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.806370Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-8 +2026-07-20T04:57:01.814346Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.814368Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-7 +2026-07-20T04:57:01.821347Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.821371Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-5 +2026-07-20T04:57:01.829295Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.829331Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-5 +2026-07-20T04:57:01.836297Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.836331Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-3 +2026-07-20T04:57:01.844491Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.844511Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-2 +2026-07-20T04:57:01.851424Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.851447Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-1 +2026-07-20T04:57:01.859455Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.859482Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-1 +2026-07-20T04:57:01.866353Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:01.866383Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=0 +2026-07-20T04:57:02.061529Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.061559Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=1 +2026-07-20T04:57:02.069382Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.069400Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=1 +2026-07-20T04:57:02.076347Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.076362Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=1 +2026-07-20T04:57:02.084532Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.084544Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=0 +2026-07-20T04:57:02.091292Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.091305Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=0 +2026-07-20T04:57:02.099494Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.099520Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=0 +2026-07-20T04:57:02.106527Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.106536Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=0 +2026-07-20T04:57:02.114462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.114478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-1 +2026-07-20T04:57:02.121397Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.121426Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-1 +2026-07-20T04:57:02.129492Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.129506Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-2 +2026-07-20T04:57:02.136443Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.136462Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-3 +2026-07-20T04:57:02.144496Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.144512Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-3 +2026-07-20T04:57:02.151499Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.151512Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-5 +2026-07-20T04:57:02.159546Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.159559Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-2 +2026-07-20T04:57:02.166549Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.166585Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-6 +2026-07-20T04:57:02.174459Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.174471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-6 +2026-07-20T04:57:02.181435Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.181446Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-7 +2026-07-20T04:57:02.189441Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.189455Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-3 +2026-07-20T04:57:02.196445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.196458Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-7 +2026-07-20T04:57:02.204544Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.204555Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-7 +2026-07-20T04:57:02.211549Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.211564Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-4 +2026-07-20T04:57:02.219538Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.219558Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-7 +2026-07-20T04:57:02.226549Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.226562Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-6 +2026-07-20T04:57:02.234468Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.234513Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-6 +2026-07-20T04:57:02.241449Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.241480Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-5 +2026-07-20T04:57:02.249426Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.249441Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-2 +2026-07-20T04:57:02.256386Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.256406Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-5 +2026-07-20T04:57:02.264438Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.264464Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=-3 +2026-07-20T04:57:02.271450Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.271474Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-2 +2026-07-20T04:57:02.279331Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.279350Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=-1 +2026-07-20T04:57:02.286365Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.286393Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=0 +2026-07-20T04:57:02.294465Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.294480Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=2 +2026-07-20T04:57:02.301486Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.301506Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=4 +2026-07-20T04:57:02.309388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.309406Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=4 +2026-07-20T04:57:02.316501Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.316530Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=7 +2026-07-20T04:57:02.324620Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.324656Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=8 +2026-07-20T04:57:02.331552Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.331590Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=9 +2026-07-20T04:57:02.339526Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.339561Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=12 +2026-07-20T04:57:02.346386Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.346399Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=9 +2026-07-20T04:57:02.354414Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.354428Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=19 +2026-07-20T04:57:02.361442Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.361457Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=12 +2026-07-20T04:57:02.369606Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.369625Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=21 +2026-07-20T04:57:02.376501Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.376526Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=17 +2026-07-20T04:57:02.384457Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.384496Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=27 +2026-07-20T04:57:02.391452Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.391472Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=15 +2026-07-20T04:57:02.399440Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.399462Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=22 +2026-07-20T04:57:02.406376Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.406398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=27 +2026-07-20T04:57:02.414350Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.414423Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=19 +2026-07-20T04:57:02.421506Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.421521Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=17 +2026-07-20T04:57:02.429328Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.429367Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=14 +2026-07-20T04:57:02.436457Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.436495Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=15 +2026-07-20T04:57:02.444567Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.444595Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=11 +2026-07-20T04:57:02.451610Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 21, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.451656Z INFO openlogi_hid::gesture: SPIKE raw xy dx=21 dy=15 +2026-07-20T04:57:02.459491Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.459505Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=7 +2026-07-20T04:57:02.466528Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 21, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.466543Z INFO openlogi_hid::gesture: SPIKE raw xy dx=21 dy=10 +2026-07-20T04:57:02.474527Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.474545Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=8 +2026-07-20T04:57:02.481389Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.481406Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=5 +2026-07-20T04:57:02.489483Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.489499Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=3 +2026-07-20T04:57:02.496464Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.496495Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=1 +2026-07-20T04:57:02.504521Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 32, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.504539Z INFO openlogi_hid::gesture: SPIKE raw xy dx=32 dy=-1 +2026-07-20T04:57:02.511518Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.511539Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-4 +2026-07-20T04:57:02.519405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.519423Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=-4 +2026-07-20T04:57:02.526399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.526415Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-6 +2026-07-20T04:57:02.534495Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.534519Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=-9 +2026-07-20T04:57:02.541576Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.541590Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-9 +2026-07-20T04:57:02.549462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.549512Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=-12 +2026-07-20T04:57:02.556671Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.556716Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=-9 +2026-07-20T04:57:02.564395Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.564410Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=-16 +2026-07-20T04:57:02.571383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.571415Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-14 +2026-07-20T04:57:02.579493Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 255, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.579528Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=-22 +2026-07-20T04:57:02.586533Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.586546Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-17 +2026-07-20T04:57:02.594509Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.594524Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-24 +2026-07-20T04:57:02.601435Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.601450Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-20 +2026-07-20T04:57:02.609429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.609446Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-22 +2026-07-20T04:57:02.616357Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.616388Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-16 +2026-07-20T04:57:02.624536Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.624553Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-25 +2026-07-20T04:57:02.631672Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.631688Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-24 +2026-07-20T04:57:02.639413Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.639434Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-17 +2026-07-20T04:57:02.646392Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.646410Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-17 +2026-07-20T04:57:02.654404Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.654440Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=-17 +2026-07-20T04:57:02.661431Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.661465Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=-18 +2026-07-20T04:57:02.669565Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.669586Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=-12 +2026-07-20T04:57:02.676330Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 233, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.676345Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-23 dy=-19 +2026-07-20T04:57:02.686321Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.686358Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-11 +2026-07-20T04:57:02.691508Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 236, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.691539Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-20 dy=-10 +2026-07-20T04:57:02.699344Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 225, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.699358Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-31 dy=-14 +2026-07-20T04:57:02.707353Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.707366Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=-8 +2026-07-20T04:57:02.712446Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:02.712460Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:02.712465Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:02.712467Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:02.712469Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:02.712471Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:02.712473Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:02.712475Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:02.712477Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:02.712479Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:02.712481Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:02.712483Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:02.712485Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:02.712486Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:02.712488Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:02.712490Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:02.712495Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=2 +2026-07-20T04:57:02.712505Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:02.713317Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:02.714412Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 226, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.714441Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-30 dy=-9 +2026-07-20T04:57:02.721414Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:02.721425Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:02.722428Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.722441Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-4 +2026-07-20T04:57:02.728425Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:02.729407Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:02.731398Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.731425Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=-4 +2026-07-20T04:57:02.736326Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.736341Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=-2 +2026-07-20T04:57:02.744543Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.744563Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-1 +2026-07-20T04:57:02.751480Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.751502Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-25 dy=0 +2026-07-20T04:57:02.759526Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.759548Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=2 +2026-07-20T04:57:02.766565Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.766596Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=2 +2026-07-20T04:57:02.774736Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.774771Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=4 +2026-07-20T04:57:02.781721Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.781759Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=8 +2026-07-20T04:57:02.789707Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.789748Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=7 +2026-07-20T04:57:02.796714Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 230, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.796752Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-26 dy=13 +2026-07-20T04:57:02.804586Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.804621Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=11 +2026-07-20T04:57:02.811448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.811485Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=20 +2026-07-20T04:57:02.819425Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.819477Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=12 +2026-07-20T04:57:02.826517Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.826536Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=23 +2026-07-20T04:57:02.834573Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.834588Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=19 +2026-07-20T04:57:02.841404Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.841417Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=23 +2026-07-20T04:57:02.849386Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.849402Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=16 +2026-07-20T04:57:02.856544Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.856567Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=26 +2026-07-20T04:57:02.864382Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.864424Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=25 +2026-07-20T04:57:02.871405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.871436Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=18 +2026-07-20T04:57:02.879681Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.879700Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=17 +2026-07-20T04:57:02.886421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.886458Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=10 +2026-07-20T04:57:02.894400Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.894414Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=7 +2026-07-20T04:57:02.901441Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.901458Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=4 +2026-07-20T04:57:02.909334Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.909353Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=3 +2026-07-20T04:57:02.916611Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.916661Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=2 +2026-07-20T04:57:02.924461Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.924503Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=1 +2026-07-20T04:57:02.931599Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.931626Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=2 +2026-07-20T04:57:02.939349Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.939381Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=3 +2026-07-20T04:57:02.946354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.946388Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=3 +2026-07-20T04:57:02.954420Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.954440Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=4 +2026-07-20T04:57:02.961603Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.961625Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=1 +2026-07-20T04:57:02.969550Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:02.969595Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=1 +2026-07-20T04:57:03.824450Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.824489Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:57:03.831308Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.831328Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-1 +2026-07-20T04:57:03.839338Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.839365Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:57:03.846321Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.846335Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-4 +2026-07-20T04:57:03.854338Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.854389Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-2 +2026-07-20T04:57:03.861434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.861465Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-2 +2026-07-20T04:57:03.869337Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.869349Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-2 +2026-07-20T04:57:03.876294Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.876312Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-2 +2026-07-20T04:57:03.884289Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.884307Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-1 +2026-07-20T04:57:03.891477Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.891506Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-2 +2026-07-20T04:57:03.899409Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.899433Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-2 +2026-07-20T04:57:03.906363Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.906392Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-2 +2026-07-20T04:57:03.914466Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.914489Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=0 +2026-07-20T04:57:03.921513Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.921543Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-1 +2026-07-20T04:57:03.929418Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.929452Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=0 +2026-07-20T04:57:03.936498Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:03.936528Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:57:04.004630Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.004666Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:57:04.094572Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.094613Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:57:04.101630Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.101651Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-3 +2026-07-20T04:57:04.109611Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.109661Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-3 +2026-07-20T04:57:04.124613Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.124687Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-6 +2026-07-20T04:57:04.132478Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.132506Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-4 +2026-07-20T04:57:04.139581Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.139610Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-8 +2026-07-20T04:57:04.147713Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.147748Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-5 +2026-07-20T04:57:04.154389Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.154427Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-13 +2026-07-20T04:57:04.162591Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.162612Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-7 +2026-07-20T04:57:04.169476Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.169514Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-16 +2026-07-20T04:57:04.177440Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.177454Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-19 +2026-07-20T04:57:04.184608Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.184622Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-10 +2026-07-20T04:57:04.192503Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.192516Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-19 +2026-07-20T04:57:04.199429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.199444Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-9 +2026-07-20T04:57:04.207421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.207434Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-16 +2026-07-20T04:57:04.214553Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.214567Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-12 +2026-07-20T04:57:04.222392Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.222414Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-5 +2026-07-20T04:57:04.229480Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.229497Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-8 +2026-07-20T04:57:04.237409Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.237447Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-3 +2026-07-20T04:57:04.244289Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:04.244405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.244432Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-4 +2026-07-20T04:57:04.247536Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:04.247538Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:04.257545Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:04.258617Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.258649Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-3 +2026-07-20T04:57:04.266472Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:04.266493Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:04.268664Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.268696Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=0 +2026-07-20T04:57:04.269506Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.269537Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=0 +2026-07-20T04:57:04.274436Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.274470Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=1 +2026-07-20T04:57:04.282423Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.282438Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=4 +2026-07-20T04:57:04.289367Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.292379Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:04.292411Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:04.294320Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:04.294377Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:04.295302Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:04.295339Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:04.296380Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:04.296402Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:04.297399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.297412Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=6 +2026-07-20T04:57:04.304401Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 231, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.304415Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-25 dy=12 +2026-07-20T04:57:04.312698Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.312725Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=10 +2026-07-20T04:57:04.319571Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.319608Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=12 +2026-07-20T04:57:04.327520Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.327583Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=6 +2026-07-20T04:57:04.334456Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.334476Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=12 +2026-07-20T04:57:04.342411Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.342425Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=13 +2026-07-20T04:57:04.349485Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.349498Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=6 +2026-07-20T04:57:04.357445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.357465Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=12 +2026-07-20T04:57:04.364525Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.364547Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=11 +2026-07-20T04:57:04.372515Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.372533Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=8 +2026-07-20T04:57:04.379489Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.379527Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=3 +2026-07-20T04:57:04.387448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.387467Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=4 +2026-07-20T04:57:04.394432Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.394471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=2 +2026-07-20T04:57:04.402377Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.402398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=1 +2026-07-20T04:57:04.409462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.409479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:57:04.657529Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.657571Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:57:04.664429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.664466Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-4 +2026-07-20T04:57:04.679483Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.679503Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-5 +2026-07-20T04:57:04.687420Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.687446Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-8 +2026-07-20T04:57:04.694321Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.703126Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-7 +2026-07-20T04:57:04.703187Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.703195Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-7 +2026-07-20T04:57:04.709462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.709481Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-7 +2026-07-20T04:57:04.717332Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.717365Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-7 +2026-07-20T04:57:04.724481Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.724511Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-7 +2026-07-20T04:57:04.732487Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.732507Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-7 +2026-07-20T04:57:04.739369Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.739385Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-6 +2026-07-20T04:57:04.747450Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.747491Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-6 +2026-07-20T04:57:04.754426Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.754450Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-6 +2026-07-20T04:57:04.762534Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.762558Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-5 +2026-07-20T04:57:04.769485Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.769527Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-4 +2026-07-20T04:57:04.777444Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.777474Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-5 +2026-07-20T04:57:04.784490Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.784518Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-5 +2026-07-20T04:57:04.792660Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.792694Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-3 +2026-07-20T04:57:04.799486Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.799519Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-4 +2026-07-20T04:57:04.807446Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.807487Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-3 +2026-07-20T04:57:04.814450Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.814482Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-5 +2026-07-20T04:57:04.822458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.822473Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-3 +2026-07-20T04:57:04.829322Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.829337Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-2 +2026-07-20T04:57:04.837469Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.837487Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-1 +2026-07-20T04:57:04.844721Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.844754Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=0 +2026-07-20T04:57:04.852795Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.852846Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=1 +2026-07-20T04:57:04.859620Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.859656Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=3 +2026-07-20T04:57:04.867471Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.867510Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=5 +2026-07-20T04:57:04.874705Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.874755Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=7 +2026-07-20T04:57:04.882535Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.882582Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=13 +2026-07-20T04:57:04.889707Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.889743Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=10 +2026-07-20T04:57:04.897833Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.897895Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=10 +2026-07-20T04:57:04.904685Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.904699Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=18 +2026-07-20T04:57:04.912533Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.912550Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=12 +2026-07-20T04:57:04.919471Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.919484Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=12 +2026-07-20T04:57:04.927389Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.927409Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=19 +2026-07-20T04:57:04.934444Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.934476Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=12 +2026-07-20T04:57:04.942388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.942423Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=12 +2026-07-20T04:57:04.949467Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.949488Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=14 +2026-07-20T04:57:04.957399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.957420Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=22 +2026-07-20T04:57:04.964413Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.964425Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=15 +2026-07-20T04:57:04.972359Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.972398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=15 +2026-07-20T04:57:04.979498Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 23, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.979510Z INFO openlogi_hid::gesture: SPIKE raw xy dx=23 dy=20 +2026-07-20T04:57:04.987497Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.987510Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=13 +2026-07-20T04:57:04.994845Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:04.994908Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=11 +2026-07-20T04:57:05.002410Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.002445Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=14 +2026-07-20T04:57:05.009541Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 27, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.009557Z INFO openlogi_hid::gesture: SPIKE raw xy dx=27 dy=11 +2026-07-20T04:57:05.017450Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.017477Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=8 +2026-07-20T04:57:05.024469Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.024508Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=9 +2026-07-20T04:57:05.032463Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.032480Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=8 +2026-07-20T04:57:05.039574Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 21, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.039589Z INFO openlogi_hid::gesture: SPIKE raw xy dx=21 dy=7 +2026-07-20T04:57:05.047438Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.047473Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=6 +2026-07-20T04:57:05.054476Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.054493Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=4 +2026-07-20T04:57:05.062420Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.062440Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=3 +2026-07-20T04:57:05.069382Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.069398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=0 +2026-07-20T04:57:05.077388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.077415Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-2 +2026-07-20T04:57:05.084359Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.084376Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-3 +2026-07-20T04:57:05.092330Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.092350Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-5 +2026-07-20T04:57:05.099371Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.099387Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-11 +2026-07-20T04:57:05.107392Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.107410Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-10 +2026-07-20T04:57:05.114562Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.114666Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-13 +2026-07-20T04:57:05.122554Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.122587Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-21 +2026-07-20T04:57:05.129422Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.129436Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-16 +2026-07-20T04:57:05.137382Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.137409Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-23 +2026-07-20T04:57:05.144396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.144412Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-16 +2026-07-20T04:57:05.152489Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.152508Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-25 +2026-07-20T04:57:05.159520Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.159543Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-23 +2026-07-20T04:57:05.167414Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.167442Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-21 +2026-07-20T04:57:05.174433Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.174457Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-21 +2026-07-20T04:57:05.182386Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.182409Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-19 +2026-07-20T04:57:05.189329Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.189349Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-17 +2026-07-20T04:57:05.197395Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.197419Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-15 +2026-07-20T04:57:05.204341Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.204364Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-9 +2026-07-20T04:57:05.212475Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.212502Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=-11 +2026-07-20T04:57:05.219457Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.219489Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=-7 +2026-07-20T04:57:05.227504Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.227541Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-3 +2026-07-20T04:57:05.234510Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.234544Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=-2 +2026-07-20T04:57:05.242522Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.242543Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=0 +2026-07-20T04:57:05.249518Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.249537Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=1 +2026-07-20T04:57:05.257498Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 234, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.257514Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-22 dy=4 +2026-07-20T04:57:05.264582Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.264598Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=4 +2026-07-20T04:57:05.272647Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 233, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.272671Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-23 dy=8 +2026-07-20T04:57:05.279534Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 234, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.279554Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-22 dy=12 +2026-07-20T04:57:05.287401Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 236, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.287458Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-20 dy=11 +2026-07-20T04:57:05.294480Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 236, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.294509Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-20 dy=14 +2026-07-20T04:57:05.302601Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.302665Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=9 +2026-07-20T04:57:05.309616Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.309640Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=16 +2026-07-20T04:57:05.317408Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.317434Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=15 +2026-07-20T04:57:05.324538Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.324558Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=9 +2026-07-20T04:57:05.332374Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.332395Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=13 +2026-07-20T04:57:05.339523Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.339539Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=7 +2026-07-20T04:57:05.347479Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.347520Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=7 +2026-07-20T04:57:05.354569Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.354591Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=4 +2026-07-20T04:57:05.362690Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.362755Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=3 +2026-07-20T04:57:05.369568Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.369584Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=1 +2026-07-20T04:57:05.377514Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 27, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.377552Z INFO openlogi_hid::gesture: SPIKE raw xy dx=27 dy=2 +2026-07-20T04:57:05.384607Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.384621Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=4 +2026-07-20T04:57:05.392488Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 35, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.392505Z INFO openlogi_hid::gesture: SPIKE raw xy dx=35 dy=5 +2026-07-20T04:57:05.399491Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 30, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.399513Z INFO openlogi_hid::gesture: SPIKE raw xy dx=30 dy=5 +2026-07-20T04:57:05.407387Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 29, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.407401Z INFO openlogi_hid::gesture: SPIKE raw xy dx=29 dy=7 +2026-07-20T04:57:05.415625Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 27, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.415667Z INFO openlogi_hid::gesture: SPIKE raw xy dx=27 dy=9 +2026-07-20T04:57:05.422563Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.422596Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=10 +2026-07-20T04:57:05.429624Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.429661Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=9 +2026-07-20T04:57:05.437468Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.437506Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=12 +2026-07-20T04:57:05.444380Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.444427Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=7 +2026-07-20T04:57:05.452672Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.452718Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=9 +2026-07-20T04:57:05.459635Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.459686Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=5 +2026-07-20T04:57:05.467471Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.467506Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=6 +2026-07-20T04:57:05.474410Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.474444Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=4 +2026-07-20T04:57:05.482897Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 233, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.482934Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-23 dy=2 +2026-07-20T04:57:05.489759Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.489794Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-20 dy=0 +2026-07-20T04:57:05.497482Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 226, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.497516Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-30 dy=-2 +2026-07-20T04:57:05.504557Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 227, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.504599Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-29 dy=-4 +2026-07-20T04:57:05.512526Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 225, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.512567Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-31 dy=-6 +2026-07-20T04:57:05.519473Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 223, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.519489Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-33 dy=-9 +2026-07-20T04:57:05.527432Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 218, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.527457Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-38 dy=-12 +2026-07-20T04:57:05.534559Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 227, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.534607Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-29 dy=-11 +2026-07-20T04:57:05.542546Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 233, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.542560Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-23 dy=-11 +2026-07-20T04:57:05.549463Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 233, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.549478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-23 dy=-13 +2026-07-20T04:57:05.557395Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.557415Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=-17 +2026-07-20T04:57:05.564448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.564477Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-14 +2026-07-20T04:57:05.572561Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.572600Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-15 +2026-07-20T04:57:05.579495Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.579511Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-12 +2026-07-20T04:57:05.587389Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.587413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-17 +2026-07-20T04:57:05.594574Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.594617Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-13 +2026-07-20T04:57:05.602459Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.602476Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=-13 +2026-07-20T04:57:05.609469Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.609501Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=-11 +2026-07-20T04:57:05.617374Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.617402Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=-10 +2026-07-20T04:57:05.624384Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.624409Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=-5 +2026-07-20T04:57:05.632612Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 29, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.632650Z INFO openlogi_hid::gesture: SPIKE raw xy dx=29 dy=-1 +2026-07-20T04:57:05.639601Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.639650Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=0 +2026-07-20T04:57:05.647707Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.647756Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=3 +2026-07-20T04:57:05.654419Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 38, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.654459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=38 dy=7 +2026-07-20T04:57:05.662756Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 32, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.662805Z INFO openlogi_hid::gesture: SPIKE raw xy dx=32 dy=9 +2026-07-20T04:57:05.669708Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 30, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.669748Z INFO openlogi_hid::gesture: SPIKE raw xy dx=30 dy=11 +2026-07-20T04:57:05.677445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 35, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.677487Z INFO openlogi_hid::gesture: SPIKE raw xy dx=35 dy=17 +2026-07-20T04:57:05.684457Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 26, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.684481Z INFO openlogi_hid::gesture: SPIKE raw xy dx=26 dy=15 +2026-07-20T04:57:05.692443Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.692464Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=15 +2026-07-20T04:57:05.699467Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 23, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.699488Z INFO openlogi_hid::gesture: SPIKE raw xy dx=23 dy=21 +2026-07-20T04:57:05.707410Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.707439Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=15 +2026-07-20T04:57:05.714491Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.714526Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=17 +2026-07-20T04:57:05.722430Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.722455Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=16 +2026-07-20T04:57:05.729380Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.729412Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=14 +2026-07-20T04:57:05.737447Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.737472Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=12 +2026-07-20T04:57:05.744380Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.744399Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=10 +2026-07-20T04:57:05.752416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.752436Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=7 +2026-07-20T04:57:05.759484Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.759508Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=6 +2026-07-20T04:57:05.767391Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.767414Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=3 +2026-07-20T04:57:05.774343Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.774365Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=2 +2026-07-20T04:57:05.782366Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.782382Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=0 +2026-07-20T04:57:05.789425Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.789438Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-2 +2026-07-20T04:57:05.797302Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.797337Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=-5 +2026-07-20T04:57:05.804448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.804466Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-5 +2026-07-20T04:57:05.812769Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.812813Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-7 +2026-07-20T04:57:05.819603Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.819639Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-10 +2026-07-20T04:57:05.827461Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.827499Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-11 +2026-07-20T04:57:05.834429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.834455Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-14 +2026-07-20T04:57:05.842435Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.842465Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-22 +2026-07-20T04:57:05.849370Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.849390Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-15 +2026-07-20T04:57:05.857436Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.857448Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-15 +2026-07-20T04:57:05.864448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.864464Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-23 +2026-07-20T04:57:05.872455Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.872471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-15 +2026-07-20T04:57:05.879487Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.879506Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-18 +2026-07-20T04:57:05.887439Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.887459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-11 +2026-07-20T04:57:05.894462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.894480Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=-15 +2026-07-20T04:57:05.902416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.902439Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-9 +2026-07-20T04:57:05.909556Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.909571Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=-11 +2026-07-20T04:57:05.917403Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.917426Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-5 +2026-07-20T04:57:05.924376Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.924404Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=-4 +2026-07-20T04:57:05.932366Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.932390Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=-1 +2026-07-20T04:57:05.939597Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.939640Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=0 +2026-07-20T04:57:05.947523Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.947556Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=2 +2026-07-20T04:57:05.954728Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.954762Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=6 +2026-07-20T04:57:05.962568Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.962600Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=4 +2026-07-20T04:57:05.969584Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 231, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.969610Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-25 dy=9 +2026-07-20T04:57:05.977444Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.977465Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=7 +2026-07-20T04:57:05.984520Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 234, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.984557Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-22 dy=11 +2026-07-20T04:57:05.992651Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.992695Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=11 +2026-07-20T04:57:05.999724Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:05.999764Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=12 +2026-07-20T04:57:06.007537Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.007583Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=14 +2026-07-20T04:57:06.014532Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.014579Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=11 +2026-07-20T04:57:06.022509Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.022547Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=15 +2026-07-20T04:57:06.029709Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.029745Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=16 +2026-07-20T04:57:06.037339Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.037394Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=11 +2026-07-20T04:57:06.044320Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.044342Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=14 +2026-07-20T04:57:06.052365Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.052381Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=13 +2026-07-20T04:57:06.059436Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.059455Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=7 +2026-07-20T04:57:06.067342Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.067363Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=8 +2026-07-20T04:57:06.074427Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.074447Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=3 +2026-07-20T04:57:06.082509Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 23, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.082579Z INFO openlogi_hid::gesture: SPIKE raw xy dx=23 dy=2 +2026-07-20T04:57:06.089481Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.089516Z INFO openlogi_hid::gesture: SPIKE raw xy dx=24 dy=0 +2026-07-20T04:57:06.097548Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.097601Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=-2 +2026-07-20T04:57:06.104405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 27, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.104469Z INFO openlogi_hid::gesture: SPIKE raw xy dx=27 dy=-4 +2026-07-20T04:57:06.112595Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 31, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.112661Z INFO openlogi_hid::gesture: SPIKE raw xy dx=31 dy=-6 +2026-07-20T04:57:06.119466Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 23, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.119520Z INFO openlogi_hid::gesture: SPIKE raw xy dx=23 dy=-6 +2026-07-20T04:57:06.127411Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 26, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.127474Z INFO openlogi_hid::gesture: SPIKE raw xy dx=26 dy=-8 +2026-07-20T04:57:06.134460Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 27, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.134518Z INFO openlogi_hid::gesture: SPIKE raw xy dx=27 dy=-10 +2026-07-20T04:57:06.142458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.142519Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-8 +2026-07-20T04:57:06.149537Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.149588Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=-12 +2026-07-20T04:57:06.157528Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.157567Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-10 +2026-07-20T04:57:06.164577Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.164599Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-12 +2026-07-20T04:57:06.172441Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.172455Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-12 +2026-07-20T04:57:06.179486Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.179499Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-12 +2026-07-20T04:57:06.187353Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.187397Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-11 +2026-07-20T04:57:06.194478Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.194486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-10 +2026-07-20T04:57:06.202448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.202465Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-10 +2026-07-20T04:57:06.209411Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.209433Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-6 +2026-07-20T04:57:06.217417Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.217452Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-9 +2026-07-20T04:57:06.224497Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.224536Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-6 +2026-07-20T04:57:06.232497Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.232525Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-4 +2026-07-20T04:57:06.239464Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.239487Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-1 +2026-07-20T04:57:06.247403Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.247427Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-22 dy=0 +2026-07-20T04:57:06.254465Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.254487Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=1 +2026-07-20T04:57:06.262459Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.262496Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=4 +2026-07-20T04:57:06.269432Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.269450Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=4 +2026-07-20T04:57:06.277362Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 234, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.277387Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-22 dy=9 +2026-07-20T04:57:06.284505Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.284534Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=7 +2026-07-20T04:57:06.292446Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.292470Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=12 +2026-07-20T04:57:06.299496Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.299533Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=13 +2026-07-20T04:57:06.307434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.307463Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=9 +2026-07-20T04:57:06.314389Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.314426Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=12 +2026-07-20T04:57:06.322458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.322481Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=9 +2026-07-20T04:57:06.329494Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.329527Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=7 +2026-07-20T04:57:06.337458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.337487Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=7 +2026-07-20T04:57:06.344441Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.344457Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=9 +2026-07-20T04:57:06.352518Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.352532Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=6 +2026-07-20T04:57:06.359581Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.359600Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=5 +2026-07-20T04:57:06.367376Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.367387Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=5 +2026-07-20T04:57:06.374480Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.374492Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=2 +2026-07-20T04:57:06.382327Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.382345Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=1 +2026-07-20T04:57:06.393489Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.393511Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=0 +2026-07-20T04:57:06.397698Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.397721Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-1 +2026-07-20T04:57:06.404596Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 21, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.404617Z INFO openlogi_hid::gesture: SPIKE raw xy dx=21 dy=-2 +2026-07-20T04:57:06.412339Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.412381Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=-2 +2026-07-20T04:57:06.420366Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.420387Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-4 +2026-07-20T04:57:06.425683Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:06.425706Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:06.425711Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:06.425714Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:06.425717Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:06.425721Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:06.425724Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:06.425727Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:06.425731Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:06.425734Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:06.425737Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:06.425741Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:06.425744Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:06.425747Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:06.425751Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:06.425754Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:06.425762Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=2 +2026-07-20T04:57:06.425776Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:06.427322Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.427336Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-2 +2026-07-20T04:57:06.429397Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:06.434341Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:06.434462Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:06.436284Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.436302Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-4 +2026-07-20T04:57:06.442449Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:06.444399Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:06.445641Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.445657Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-2 +2026-07-20T04:57:06.449558Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.449578Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-2 +2026-07-20T04:57:06.457429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.457451Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-2 +2026-07-20T04:57:06.464533Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.464557Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-1 +2026-07-20T04:57:06.472510Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:06.472531Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:57:07.199503Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.199538Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-1 +2026-07-20T04:57:07.207626Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.207693Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-2 +2026-07-20T04:57:07.214688Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.214724Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-6 +2026-07-20T04:57:07.222763Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.222856Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-7 +2026-07-20T04:57:07.229630Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.229665Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=-9 +2026-07-20T04:57:07.237437Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.237471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=-9 +2026-07-20T04:57:07.244818Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.244859Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=-9 +2026-07-20T04:57:07.252413Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.252452Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-11 +2026-07-20T04:57:07.259482Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.259497Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=-13 +2026-07-20T04:57:07.267385Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.267403Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=-11 +2026-07-20T04:57:07.274459Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.274476Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-14 +2026-07-20T04:57:07.282383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.282400Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=-15 +2026-07-20T04:57:07.289473Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.289487Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=-18 +2026-07-20T04:57:07.297473Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.297512Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-13 +2026-07-20T04:57:07.304505Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.304522Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=-19 +2026-07-20T04:57:07.312575Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.312598Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-12 +2026-07-20T04:57:07.319466Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.319505Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-15 +2026-07-20T04:57:07.327447Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.327473Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-12 +2026-07-20T04:57:07.334396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.334422Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-8 +2026-07-20T04:57:07.342329Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.342346Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-4 +2026-07-20T04:57:07.349353Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.349368Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-5 +2026-07-20T04:57:07.357396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.357416Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-2 +2026-07-20T04:57:07.364476Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.364500Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-2 +2026-07-20T04:57:07.372433Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.372457Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:57:07.379368Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.379398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-1 +2026-07-20T04:57:07.387383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.387412Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=0 +2026-07-20T04:57:07.394435Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.394462Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=3 +2026-07-20T04:57:07.402484Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.402528Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=5 +2026-07-20T04:57:07.409502Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.409522Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=12 +2026-07-20T04:57:07.417322Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.417345Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=14 +2026-07-20T04:57:07.424491Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.433664Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=15 +2026-07-20T04:57:07.433694Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.433701Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=21 +2026-07-20T04:57:07.439383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.439406Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=27 +2026-07-20T04:57:07.447416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 21, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.447464Z INFO openlogi_hid::gesture: SPIKE raw xy dx=21 dy=27 +2026-07-20T04:57:07.454462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 24, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.454484Z INFO openlogi_hid::gesture: SPIKE raw xy dx=24 dy=33 +2026-07-20T04:57:07.462458Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.462480Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=29 +2026-07-20T04:57:07.469469Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.469496Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=30 +2026-07-20T04:57:07.477423Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.477453Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=27 +2026-07-20T04:57:07.484495Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.484531Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=26 +2026-07-20T04:57:07.492486Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.492520Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=23 +2026-07-20T04:57:07.499494Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.499531Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=26 +2026-07-20T04:57:07.507502Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.507539Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=28 +2026-07-20T04:57:07.514482Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.514517Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=21 +2026-07-20T04:57:07.522816Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.522844Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=18 +2026-07-20T04:57:07.529605Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.529637Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=16 +2026-07-20T04:57:07.537383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.537406Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=11 +2026-07-20T04:57:07.544343Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.544367Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=13 +2026-07-20T04:57:07.552408Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.552437Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=6 +2026-07-20T04:57:07.559614Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.559631Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=3 +2026-07-20T04:57:07.567434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 217, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.567453Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-39 dy=0 +2026-07-20T04:57:07.574534Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 228, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.574559Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-28 dy=-1 +2026-07-20T04:57:07.582472Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 216, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.582495Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-40 dy=-6 +2026-07-20T04:57:07.589515Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 217, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.589537Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-39 dy=-8 +2026-07-20T04:57:07.597369Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 219, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.597405Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-37 dy=-9 +2026-07-20T04:57:07.604620Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 211, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.604656Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-45 dy=-13 +2026-07-20T04:57:07.612608Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 219, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.612632Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-37 dy=-13 +2026-07-20T04:57:07.619506Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 220, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.619528Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-36 dy=-14 +2026-07-20T04:57:07.627403Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 217, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.627429Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-39 dy=-17 +2026-07-20T04:57:07.634456Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 217, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.634500Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-39 dy=-20 +2026-07-20T04:57:07.642419Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.642434Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=-16 +2026-07-20T04:57:07.649543Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 228, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.649576Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-28 dy=-18 +2026-07-20T04:57:07.657400Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 227, 255, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.657424Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-29 dy=-25 +2026-07-20T04:57:07.664643Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 255, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.664679Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=-22 +2026-07-20T04:57:07.672595Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.672608Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=-18 +2026-07-20T04:57:07.679594Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.679628Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-20 +2026-07-20T04:57:07.687397Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.687421Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-15 +2026-07-20T04:57:07.694640Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.694653Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-16 +2026-07-20T04:57:07.702581Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.702594Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-18 +2026-07-20T04:57:07.709383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.709397Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-12 +2026-07-20T04:57:07.717354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.717377Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-13 +2026-07-20T04:57:07.724304Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.724332Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-12 +2026-07-20T04:57:07.732485Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.732500Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-13 +2026-07-20T04:57:07.739534Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.739550Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-11 +2026-07-20T04:57:07.747388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.747404Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=-10 +2026-07-20T04:57:07.754512Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.754531Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=-9 +2026-07-20T04:57:07.762427Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.762446Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=-7 +2026-07-20T04:57:07.769467Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.769486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=-6 +2026-07-20T04:57:07.777428Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.777461Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=-2 +2026-07-20T04:57:07.784500Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 27, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.784539Z INFO openlogi_hid::gesture: SPIKE raw xy dx=27 dy=-4 +2026-07-20T04:57:07.792499Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 26, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.792530Z INFO openlogi_hid::gesture: SPIKE raw xy dx=26 dy=-1 +2026-07-20T04:57:07.799446Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.799471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-1 +2026-07-20T04:57:07.807602Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.807623Z INFO openlogi_hid::gesture: SPIKE raw xy dx=24 dy=0 +2026-07-20T04:57:07.814331Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.814346Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=0 +2026-07-20T04:57:07.822529Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.822543Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=0 +2026-07-20T04:57:07.829489Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.829514Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=1 +2026-07-20T04:57:07.837376Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.837391Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=1 +2026-07-20T04:57:07.852461Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.852491Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=0 +2026-07-20T04:57:07.919519Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.919548Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:57:07.951086Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:07.954384Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:07.954433Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:07.963422Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:07.970383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:07.970432Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:07.987448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:07.991393Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:07.991410Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:07.993380Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:07.993382Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:07.995324Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:07.995351Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:07.998375Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:07.998445Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:08.144437Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.144479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=0 +2026-07-20T04:57:08.152434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.152470Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=0 +2026-07-20T04:57:08.159581Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.159614Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:57:08.167416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.167437Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=-2 +2026-07-20T04:57:08.174517Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.174537Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-1 +2026-07-20T04:57:08.182469Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.182486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=-2 +2026-07-20T04:57:08.189434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.189452Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=-2 +2026-07-20T04:57:08.197400Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.197423Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=-2 +2026-07-20T04:57:08.204447Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.204494Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-1 +2026-07-20T04:57:08.212442Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.212457Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-1 +2026-07-20T04:57:08.219517Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 27, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.219532Z INFO openlogi_hid::gesture: SPIKE raw xy dx=27 dy=-2 +2026-07-20T04:57:08.227307Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.227324Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=0 +2026-07-20T04:57:08.234452Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.234481Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=1 +2026-07-20T04:57:08.242456Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 24, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.242480Z INFO openlogi_hid::gesture: SPIKE raw xy dx=24 dy=5 +2026-07-20T04:57:08.249337Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.249381Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=6 +2026-07-20T04:57:08.257378Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.257408Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=9 +2026-07-20T04:57:08.264435Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.264459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=8 +2026-07-20T04:57:08.272361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.272372Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=11 +2026-07-20T04:57:08.279517Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.279528Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=9 +2026-07-20T04:57:08.287399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.287418Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=15 +2026-07-20T04:57:08.294366Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.294392Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=17 +2026-07-20T04:57:08.302460Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.302476Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=13 +2026-07-20T04:57:08.309395Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.309413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=22 +2026-07-20T04:57:08.317432Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.317458Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=19 +2026-07-20T04:57:08.324520Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.324547Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=13 +2026-07-20T04:57:08.332399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.332431Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=19 +2026-07-20T04:57:08.339288Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.339320Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=19 +2026-07-20T04:57:08.347331Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.347371Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=10 +2026-07-20T04:57:08.354354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.354391Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=14 +2026-07-20T04:57:08.362596Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.362621Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=8 +2026-07-20T04:57:08.369508Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.369531Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=4 +2026-07-20T04:57:08.377551Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 236, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.377576Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-20 dy=1 +2026-07-20T04:57:08.384460Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.384508Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=-2 +2026-07-20T04:57:08.392511Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.392529Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=-5 +2026-07-20T04:57:08.399741Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.399754Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-7 +2026-07-20T04:57:08.407327Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.407340Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-9 +2026-07-20T04:57:08.414575Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.414588Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-8 +2026-07-20T04:57:08.422528Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.422543Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-7 +2026-07-20T04:57:08.429396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.429444Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=-13 +2026-07-20T04:57:08.437363Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.437395Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-9 +2026-07-20T04:57:08.444399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.444463Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-6 +2026-07-20T04:57:08.452654Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.452692Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-8 +2026-07-20T04:57:08.459577Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.459611Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-8 +2026-07-20T04:57:08.467341Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.467383Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-5 +2026-07-20T04:57:08.474352Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.474376Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:57:08.482488Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.482509Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-4 +2026-07-20T04:57:08.497332Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.497353Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-2 +2026-07-20T04:57:08.504460Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.504479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-2 +2026-07-20T04:57:08.512462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.512485Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:57:08.519389Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.519415Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:57:08.527402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:08.527424Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:57:09.022540Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.022576Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:57:09.029753Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.029787Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=0 +2026-07-20T04:57:09.037377Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.037410Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=0 +2026-07-20T04:57:09.044380Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.044407Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=0 +2026-07-20T04:57:09.052314Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.052331Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-1 +2026-07-20T04:57:09.059277Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.059295Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-1 +2026-07-20T04:57:09.067278Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.067293Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=0 +2026-07-20T04:57:09.074455Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.074471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-1 +2026-07-20T04:57:09.082493Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.082506Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-1 +2026-07-20T04:57:09.089393Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.089417Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-1 +2026-07-20T04:57:09.097361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.097389Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-1 +2026-07-20T04:57:09.104409Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.104431Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-1 +2026-07-20T04:57:09.112637Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.112664Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=0 +2026-07-20T04:57:09.119442Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.119455Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-1 +2026-07-20T04:57:09.127326Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.127341Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=0 +2026-07-20T04:57:09.134413Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.134441Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=0 +2026-07-20T04:57:09.322531Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.322586Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:57:09.329582Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.329626Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-3 +2026-07-20T04:57:09.337504Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.337556Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:57:09.344474Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.344520Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=-14 +2026-07-20T04:57:09.352481Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.352500Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-9 +2026-07-20T04:57:09.359354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.359370Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-9 +2026-07-20T04:57:09.367468Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.367488Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-6 +2026-07-20T04:57:09.374381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.374411Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-7 +2026-07-20T04:57:09.382401Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.382424Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-6 +2026-07-20T04:57:09.389453Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.389472Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-5 +2026-07-20T04:57:09.397419Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.397457Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-3 +2026-07-20T04:57:09.404480Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.404495Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=-2 +2026-07-20T04:57:09.412424Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.412466Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=0 +2026-07-20T04:57:09.419428Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.419441Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=1 +2026-07-20T04:57:09.427320Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.427333Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=6 +2026-07-20T04:57:09.434457Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.434475Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=7 +2026-07-20T04:57:09.442371Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.442405Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=12 +2026-07-20T04:57:09.449429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.449445Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=14 +2026-07-20T04:57:09.457379Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.457398Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=16 +2026-07-20T04:57:09.464475Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.464517Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=15 +2026-07-20T04:57:09.472522Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.472540Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=17 +2026-07-20T04:57:09.479429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.479467Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=18 +2026-07-20T04:57:09.487443Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.487460Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=12 +2026-07-20T04:57:09.494409Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.494436Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=18 +2026-07-20T04:57:09.502285Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.502298Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=16 +2026-07-20T04:57:09.509364Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.509376Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=12 +2026-07-20T04:57:09.517318Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.517334Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=13 +2026-07-20T04:57:09.524331Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.524346Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=7 +2026-07-20T04:57:09.532434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.532448Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=11 +2026-07-20T04:57:09.539409Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.539444Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=10 +2026-07-20T04:57:09.547357Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.547384Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=9 +2026-07-20T04:57:09.554488Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.554535Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=8 +2026-07-20T04:57:09.562402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.562431Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=4 +2026-07-20T04:57:09.569381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.569415Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=3 +2026-07-20T04:57:09.577338Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.577359Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=1 +2026-07-20T04:57:09.584471Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.584491Z INFO openlogi_hid::gesture: SPIKE raw xy dx=13 dy=0 +2026-07-20T04:57:09.592418Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.592438Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=-1 +2026-07-20T04:57:09.599443Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.599462Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=-3 +2026-07-20T04:57:09.607354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.607367Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=-2 +2026-07-20T04:57:09.614457Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.614475Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-2 +2026-07-20T04:57:09.622399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.622413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=-3 +2026-07-20T04:57:09.629405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.629444Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=0 +2026-07-20T04:57:09.644386Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.644405Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=0 +2026-07-20T04:57:09.652375Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.652396Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=1 +2026-07-20T04:57:09.659292Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.659311Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=3 +2026-07-20T04:57:09.667354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:09.667369Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=0 +2026-07-20T04:57:10.085488Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:10.085518Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:10.085521Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:10.085523Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:10.085539Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:10.085541Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:10.085544Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:10.085546Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:10.085549Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:10.085551Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:10.085553Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:10.085556Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:10.085559Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:10.085561Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:10.085564Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:10.085566Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:10.085572Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=2 +2026-07-20T04:57:10.085590Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:10.087394Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:10.093302Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:10.093310Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:10.101428Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:10.102374Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:11.212573Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.212604Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=0 +2026-07-20T04:57:11.219583Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.219601Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-1 +2026-07-20T04:57:11.227330Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.227346Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-1 +2026-07-20T04:57:11.234481Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:57:11.242478Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.242493Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-2 +2026-07-20T04:57:11.249569Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.249609Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-7 +2026-07-20T04:57:11.257351Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:57:11.264558Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.264574Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-5 +2026-07-20T04:57:11.276714Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.276747Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-10 +2026-07-20T04:57:11.279491Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.279505Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-3 +2026-07-20T04:57:11.287411Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.287423Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-4 +2026-07-20T04:57:11.294370Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.294410Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-4 +2026-07-20T04:57:11.302516Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.302584Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-5 +2026-07-20T04:57:11.309546Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.309559Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=-6 +2026-07-20T04:57:11.317354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.317381Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-4 +2026-07-20T04:57:11.324429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.324442Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=-9 +2026-07-20T04:57:11.332437Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.332453Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=-9 +2026-07-20T04:57:11.339448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.339476Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=-8 +2026-07-20T04:57:11.347446Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 231, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.347463Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-25 dy=-11 +2026-07-20T04:57:11.354308Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.354320Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=-8 +2026-07-20T04:57:11.362372Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 228, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.362404Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-28 dy=-12 +2026-07-20T04:57:11.369392Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 228, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.369408Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-28 dy=-11 +2026-07-20T04:57:11.377438Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 227, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.377469Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-29 dy=-11 +2026-07-20T04:57:11.384490Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 219, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.384504Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-37 dy=-11 +2026-07-20T04:57:11.392436Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.392459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=-6 +2026-07-20T04:57:11.399564Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 223, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.399597Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-33 dy=-8 +2026-07-20T04:57:11.407332Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 228, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.407345Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-28 dy=-5 +2026-07-20T04:57:11.414482Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.414492Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=-5 +2026-07-20T04:57:11.422414Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 230, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.422429Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-26 dy=-3 +2026-07-20T04:57:11.429445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 225, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.429484Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-31 dy=-1 +2026-07-20T04:57:11.437361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.437384Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-21 dy=0 +2026-07-20T04:57:11.444442Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.444471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=3 +2026-07-20T04:57:11.452395Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.452408Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=5 +2026-07-20T04:57:11.459543Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 236, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.459572Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-20 dy=9 +2026-07-20T04:57:11.467372Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.467390Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=11 +2026-07-20T04:57:11.474465Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.474506Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=14 +2026-07-20T04:57:11.482540Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.482554Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=11 +2026-07-20T04:57:11.489543Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.489558Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=21 +2026-07-20T04:57:11.497482Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.497533Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=15 +2026-07-20T04:57:11.504530Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.504570Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=23 +2026-07-20T04:57:11.512538Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.512572Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=22 +2026-07-20T04:57:11.519403Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.519419Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=23 +2026-07-20T04:57:11.527469Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.527492Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=27 +2026-07-20T04:57:11.534493Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.534516Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=19 +2026-07-20T04:57:11.542369Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.542391Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=25 +2026-07-20T04:57:11.549509Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.549543Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=19 +2026-07-20T04:57:11.557396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.557418Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=23 +2026-07-20T04:57:11.564618Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.564638Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=17 +2026-07-20T04:57:11.572476Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.572498Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=17 +2026-07-20T04:57:11.579479Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.579494Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=15 +2026-07-20T04:57:11.587411Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.587434Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=9 +2026-07-20T04:57:11.594466Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.594501Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=12 +2026-07-20T04:57:11.602472Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.602501Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=8 +2026-07-20T04:57:11.609465Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.609504Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=3 +2026-07-20T04:57:11.615826Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:11.617449Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 21, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.617479Z INFO openlogi_hid::gesture: SPIKE raw xy dx=21 dy=2 +2026-07-20T04:57:11.619425Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:11.619498Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:11.630455Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:11.631376Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.631406Z INFO openlogi_hid::gesture: SPIKE raw xy dx=20 dy=0 +2026-07-20T04:57:11.638416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:11.638515Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:11.639490Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.639498Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=-1 +2026-07-20T04:57:11.641369Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.641382Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=-3 +2026-07-20T04:57:11.647413Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 23, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.647437Z INFO openlogi_hid::gesture: SPIKE raw xy dx=23 dy=-5 +2026-07-20T04:57:11.654424Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 23, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.654447Z INFO openlogi_hid::gesture: SPIKE raw xy dx=23 dy=-7 +2026-07-20T04:57:11.662321Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.665424Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:11.665523Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:11.668480Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:11.668546Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:11.669550Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 28, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.669564Z INFO openlogi_hid::gesture: SPIKE raw xy dx=28 dy=-9 +2026-07-20T04:57:11.671482Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:11.671511Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:11.674489Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:11.674492Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:11.677415Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 47, 255, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.677428Z INFO openlogi_hid::gesture: SPIKE raw xy dx=47 dy=-22 +2026-07-20T04:57:11.684445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.684462Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=-12 +2026-07-20T04:57:11.692374Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.692394Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=-16 +2026-07-20T04:57:11.699406Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.699426Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=-16 +2026-07-20T04:57:11.707385Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.707415Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-18 +2026-07-20T04:57:11.714396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.714426Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-18 +2026-07-20T04:57:11.722321Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.722362Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=-19 +2026-07-20T04:57:11.729315Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.729340Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-20 +2026-07-20T04:57:11.737492Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.737528Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-20 +2026-07-20T04:57:11.744394Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.744444Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-14 +2026-07-20T04:57:11.752434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.752460Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-21 +2026-07-20T04:57:11.759407Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.759427Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-20 +2026-07-20T04:57:11.767327Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.767342Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-20 +2026-07-20T04:57:11.774366Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.774379Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-19 +2026-07-20T04:57:11.782543Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.782557Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-19 +2026-07-20T04:57:11.789522Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.789543Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-19 +2026-07-20T04:57:11.797368Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.797402Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-19 +2026-07-20T04:57:11.804455Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.804485Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-12 +2026-07-20T04:57:11.812493Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.812508Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-17 +2026-07-20T04:57:11.819418Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.819435Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-11 +2026-07-20T04:57:11.827433Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.827492Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-9 +2026-07-20T04:57:11.834438Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.834457Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-10 +2026-07-20T04:57:11.842452Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.842478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-5 +2026-07-20T04:57:11.849351Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.849374Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=-4 +2026-07-20T04:57:11.857361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.857391Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-3 +2026-07-20T04:57:11.864381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.864404Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-2 +2026-07-20T04:57:11.872469Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.872490Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-1 +2026-07-20T04:57:11.879453Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.879476Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-1 +2026-07-20T04:57:11.887524Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.887570Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=0 +2026-07-20T04:57:11.894473Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.894522Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=0 +2026-07-20T04:57:11.902528Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.902551Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=0 +2026-07-20T04:57:11.909423Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.909448Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=1 +2026-07-20T04:57:11.924400Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.924419Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=1 +2026-07-20T04:57:11.932434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.932451Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=4 +2026-07-20T04:57:11.939581Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.939596Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=2 +2026-07-20T04:57:11.947396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.947438Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:57:11.954386Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.954422Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=2 +2026-07-20T04:57:11.962587Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.962618Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=2 +2026-07-20T04:57:11.969617Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.969635Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:57:11.984561Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.984635Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:57:11.992613Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.992627Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=0 +2026-07-20T04:57:11.999649Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:11.999684Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:57:12.007401Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:12.007457Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:57:12.014453Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:12.014469Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:57:12.029462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:12.029478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:57:12.037388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:12.037430Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:57:12.059293Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:12.059314Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:57:12.067425Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:12.067444Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:57:12.074399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:12.074413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:57:12.089461Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:12.089486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=2 +2026-07-20T04:57:12.097464Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:12.097492Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:57:12.104381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:12.104411Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=2 +2026-07-20T04:57:12.112430Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:12.112454Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=1 +2026-07-20T04:57:12.119493Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:12.119510Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=1 +2026-07-20T04:57:12.127355Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:12.127381Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=0 +2026-07-20T04:57:12.337420Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:12.337450Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=1 +2026-07-20T04:57:13.797364Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:13.797397Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:13.797401Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:13.797404Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:13.797407Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:13.797410Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:13.797413Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:13.797415Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:13.797418Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:13.797421Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:13.797424Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:13.797427Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:13.797430Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:13.797433Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:13.797440Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:13.797445Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:13.797452Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=2 +2026-07-20T04:57:13.797466Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:13.798373Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:13.805400Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:13.805470Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:13.812508Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:13.813434Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:15.202703Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:57:15.224804Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:57:15.316421Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:15.319498Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:15.319522Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:15.328456Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:15.336380Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:15.336381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:15.359504Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:15.362445Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:15.362509Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:15.365449Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:15.365634Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:15.367393Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:15.367440Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:15.369357Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:15.369416Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:17.457849Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:17.457898Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:17.457903Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:17.457907Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:17.457911Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:17.457915Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:17.457919Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:17.457923Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:17.457927Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:17.457931Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:17.457935Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:17.457939Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:17.457944Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:17.457948Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:17.457952Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:17.457956Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:17.457966Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=2 +2026-07-20T04:57:17.457987Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:17.459360Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:17.465351Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:17.465442Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:17.472412Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:17.474400Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:18.990205Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:18.992452Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:18.992512Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:19.002492Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:19.008465Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:19.008468Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:19.402388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:57:19.410295Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:19.413332Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:19.413393Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:19.416316Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:19.416345Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:19.419330Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:19.419429Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:19.422353Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:19.422400Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:19.422445Z DEBUG openlogi_agent_core::watchers::inventory: hotplug event — enumerating early event=Connected +2026-07-20T04:57:19.425384Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:57:19.877396Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:19.877421Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:19.877424Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:19.877427Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:57:19.877429Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:19.877431Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:19.877438Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:19.877442Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:19.877444Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:19.877446Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:19.877448Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:19.877451Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:19.877453Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:19.877455Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:19.877457Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:19.877460Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:19.877462Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:19.877464Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:19.877467Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:19.877469Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:19.877472Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:57:19.877474Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:19.877476Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:19.877479Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:19.877481Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:19.877488Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:57:19.925832Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:57:19.925855Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:57:19.925973Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:19.927237Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:57:19.927256Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:57:19.928525Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:19.934340Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:19.934394Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:19.941418Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:19.943331Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:21.455407Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:21.456369Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:21.456415Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:21.466307Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:21.472449Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:21.472461Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:21.735779Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:21.735814Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=0 +2026-07-20T04:57:21.742472Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:21.742511Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-1 +2026-07-20T04:57:21.750660Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:57:21.757478Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:21.757510Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-1 +2026-07-20T04:57:21.765730Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:21.769780Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:21.769804Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:21.771487Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:21.771510Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:21.772437Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 180, 255, 217, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:21.772468Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-76 dy=-39 +2026-07-20T04:57:21.774365Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:21.774397Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:21.777272Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:21.777348Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:21.780331Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:57:21.787321Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 186, 255, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:21.787335Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-70 dy=-72 +2026-07-20T04:57:21.795343Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 179, 255, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:21.795378Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-77 dy=-104 +2026-07-20T04:57:21.802569Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 217, 255, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:21.802601Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-39 dy=-55 +2026-07-20T04:57:21.810564Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 217, 255, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:21.810584Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-39 dy=-50 +2026-07-20T04:57:21.817356Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 219, 255, 215, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:21.817388Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-37 dy=-41 +2026-07-20T04:57:21.825340Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 225, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:21.825353Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-31 dy=-32 +2026-07-20T04:57:22.042509Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 255, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.042555Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=-23 +2026-07-20T04:57:22.050481Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 255, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.050511Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=-33 +2026-07-20T04:57:22.057437Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.057468Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-6 +2026-07-20T04:57:22.065359Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 182, 255, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.065386Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-74 dy=-72 +2026-07-20T04:57:22.072413Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 223, 255, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.072446Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-33 dy=-31 +2026-07-20T04:57:22.080385Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 228, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.080419Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-28 dy=-24 +2026-07-20T04:57:22.087432Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 255, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.087459Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=-22 +2026-07-20T04:57:22.095360Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.095386Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=-17 +2026-07-20T04:57:22.102433Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 233, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.102458Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-23 dy=-14 +2026-07-20T04:57:22.110435Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.110537Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=-10 +2026-07-20T04:57:22.117421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 230, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.117436Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-26 dy=-11 +2026-07-20T04:57:22.125348Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.125373Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=-7 +2026-07-20T04:57:22.132530Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 234, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.132552Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-22 dy=-10 +2026-07-20T04:57:22.140369Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 241, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.140395Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-15 dy=-6 +2026-07-20T04:57:22.147381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.147397Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=-4 +2026-07-20T04:57:22.155470Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.155492Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=-4 +2026-07-20T04:57:22.162548Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.162576Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-4 +2026-07-20T04:57:22.170464Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.170599Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-2 +2026-07-20T04:57:22.177380Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.177404Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-3 +2026-07-20T04:57:22.185414Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.185433Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-1 +2026-07-20T04:57:22.192469Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.192492Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-1 +2026-07-20T04:57:22.200446Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.200463Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=0 +2026-07-20T04:57:22.207362Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.207383Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=0 +2026-07-20T04:57:22.215331Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.215348Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=0 +2026-07-20T04:57:22.477461Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:22.477522Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-1 +2026-07-20T04:57:23.826685Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:23.826711Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:23.826714Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:23.826716Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:57:23.826718Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:23.826720Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:23.826722Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:23.826724Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:23.826726Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:23.826728Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:23.826730Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:23.826735Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:23.826739Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:23.826741Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:23.826743Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:23.826745Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:23.826747Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:23.826749Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:23.826751Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:23.826753Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:23.826755Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:57:23.826757Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:23.826759Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:23.826761Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:23.826763Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:23.826769Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:57:23.826800Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:23.828324Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:57:23.828355Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:57:23.828407Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:23.834279Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:23.834304Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:23.841383Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:23.842273Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:25.351692Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:25.354484Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:25.354576Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:25.363460Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:25.371343Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:25.371374Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:25.807334Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:57:25.815459Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:25.819300Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:25.819356Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:25.821339Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:25.821403Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:25.824296Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:25.824371Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:25.827334Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:25.827372Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:25.827550Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:57:25.827584Z DEBUG openlogi_agent_core::watchers::inventory: hotplug event — enumerating early event=Disconnected +2026-07-20T04:57:25.830376Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:57:26.287953Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:26.287980Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:26.287983Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:26.287986Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:57:26.287989Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:26.287991Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:26.287994Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:26.287996Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:26.288004Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:26.288009Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:26.288012Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:26.288015Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:26.288017Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:26.288020Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:26.288023Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:26.288025Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:26.288028Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:26.288031Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:26.288033Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:26.288036Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:26.288038Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:57:26.288041Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:26.288043Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:26.288046Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:26.288049Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:26.288058Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:57:26.341588Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:57:26.341617Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:57:26.341712Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:26.343235Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:57:26.343255Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:57:26.344323Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:26.347287Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:26.347387Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:26.354320Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:26.355327Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:27.867389Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:27.869464Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:27.869482Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:27.887412Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:27.892364Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:27.892413Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:28.357340Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:57:28.372343Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:28.374323Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:28.374329Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:28.377296Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:28.377296Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:28.379538Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:28.379632Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:28.381288Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:57:28.383291Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:28.383292Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:28.383465Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:57:30.516708Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:30.516732Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:30.516736Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:30.516738Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:57:30.516745Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:30.516749Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:30.516752Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:30.516755Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:30.516757Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:30.516760Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:30.516762Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:30.516765Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:30.516767Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:30.516770Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:30.516772Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:30.516775Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:30.516778Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:30.516780Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:30.516783Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:30.516785Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:30.516788Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:57:30.516790Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:30.516793Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:30.516795Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:30.516798Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:30.516806Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:57:30.561683Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:57:30.561703Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:57:30.561789Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:30.563225Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:57:30.563240Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:57:30.564294Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:30.569308Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:30.569350Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:30.576340Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:30.577335Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:32.082859Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:32.084381Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:32.084397Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:32.093453Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:32.099283Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:32.099313Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:32.430343Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:57:32.437323Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:32.439284Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:32.439304Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:32.441335Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:32.441355Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:32.444319Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:32.444353Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:32.446281Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:32.446315Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:32.446461Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:57:32.452300Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:57:34.534330Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:34.534364Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:34.534367Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:34.534369Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:57:34.534371Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:34.534373Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:34.534375Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:34.534377Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:34.534379Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:34.534381Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:34.534383Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:34.534385Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:34.534387Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:34.534389Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:34.534390Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:34.534392Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:34.534394Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:34.534396Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:34.534398Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:34.534401Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:34.534402Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:57:34.534404Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:34.534406Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:34.534408Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:34.534410Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:34.534417Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:57:34.581693Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:57:34.581723Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:57:34.583381Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:57:34.583402Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:57:34.585286Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:34.589568Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:34.589593Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:34.596444Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:34.597459Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:34.647426Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:36.099495Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:36.102353Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:36.102415Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:36.110538Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:36.117354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:36.117441Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:36.494309Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:57:36.502345Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:36.504349Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:36.504446Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:36.507391Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:36.507411Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:36.508333Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:36.508365Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:36.509269Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:36.509297Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:36.509411Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:57:36.510282Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:57:38.630922Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:38.630950Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:38.630953Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:38.630955Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:57:38.630957Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:38.630959Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:38.630961Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:38.630963Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:38.630965Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:38.630968Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:38.630969Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:38.630971Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:38.630973Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:38.630975Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:38.630977Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:38.630980Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:38.630982Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:38.630984Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:38.630986Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:38.630988Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:38.630990Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:57:38.630992Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:38.630997Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:38.631000Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:38.631002Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:38.631008Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:57:38.675350Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:57:38.675374Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:57:38.675459Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:38.676325Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:38.677284Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:57:38.677304Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:57:38.682444Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:38.682449Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:38.687293Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:38.688311Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:40.201549Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:40.204415Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:40.204447Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:40.213350Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:40.220415Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:40.220421Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:40.559365Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:57:40.567446Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 0, function_id: U4(1), software_id: U4(1) }, [4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.582487Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:57:40.589584Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 0, function_id: U4(0), software_id: U4(1) }, [1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.613774Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(0), software_id: U4(1) }, [45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.627507Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.642528Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 3, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.664361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 5, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.687420Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [29, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.709514Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 32, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.732455Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 33, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.754309Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.777405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.792379Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [16, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.807375Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [23, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.829407Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [25, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.844405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [25, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.859352Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [27, 4, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.882402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 20, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.897365Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 21, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.912542Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [34, 80, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.927470Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [33, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.942349Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [33, 33, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.964334Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [33, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.979352Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [34, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:40.994434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [34, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:41.017388Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:41.039426Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 2, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:41.062448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 3, 112, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:41.084369Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 7, 112, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:41.107351Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 22, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:41.129404Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 5, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:41.144576Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 48, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:41.159309Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 145, 104, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:41.182361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 161, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:41.197384Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [30, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:41.212397Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [30, 2, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:41.226390Z DEBUG openlogi_hid::inventory::probe: Bolt slot probe timed out; using cached data if available slot=2 budget=1s +2026-07-20T04:57:41.228493Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:41.228531Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:41.230437Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:41.230545Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:41.232441Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:41.232461Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:41.233335Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:41.233410Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:41.233510Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:57:41.234422Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [30, 34, 112, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.318965Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:43.318993Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:43.318996Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:43.318998Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:57:43.319000Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:43.319002Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:43.319004Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:43.319005Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:43.319007Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:43.319009Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:43.319011Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:43.319013Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:43.319015Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:43.319017Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:43.319019Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:43.319021Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:43.319023Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:43.319024Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:43.319026Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:43.319028Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:43.319033Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:57:43.319038Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:43.319040Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:43.319041Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:43.319043Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:43.319049Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:57:43.362800Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:57:43.362824Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:57:43.362946Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:43.364200Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:57:43.364217Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:57:43.364352Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:43.371339Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:43.371371Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:43.378408Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:43.379332Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:43.883559Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.883590Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-1 +2026-07-20T04:57:43.889555Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.889614Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=-10 +2026-07-20T04:57:43.897382Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 7, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.897431Z INFO openlogi_hid::gesture: SPIKE raw xy dx=7 dy=-4 +2026-07-20T04:57:43.904362Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 42, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.904405Z INFO openlogi_hid::gesture: SPIKE raw xy dx=42 dy=-32 +2026-07-20T04:57:43.912580Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.912620Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=-16 +2026-07-20T04:57:43.919583Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.919614Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=-15 +2026-07-20T04:57:43.927810Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.927841Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=-11 +2026-07-20T04:57:43.934688Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.934713Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-7 +2026-07-20T04:57:43.942422Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.942449Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=-2 +2026-07-20T04:57:43.949494Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.949527Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-1 +2026-07-20T04:57:43.957466Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.957489Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=0 +2026-07-20T04:57:43.964376Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.964422Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=1 +2026-07-20T04:57:43.972537Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 244, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.972558Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-12 dy=1 +2026-07-20T04:57:43.979542Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.979573Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=3 +2026-07-20T04:57:43.987440Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.987464Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=4 +2026-07-20T04:57:43.994540Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:43.994570Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=3 +2026-07-20T04:57:44.002553Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.002586Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=8 +2026-07-20T04:57:44.009526Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 242, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.009551Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-14 dy=9 +2026-07-20T04:57:44.017425Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.017520Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=8 +2026-07-20T04:57:44.024621Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.024640Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=11 +2026-07-20T04:57:44.032402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.032439Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=10 +2026-07-20T04:57:44.039462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.039494Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=12 +2026-07-20T04:57:44.047386Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.047419Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=9 +2026-07-20T04:57:44.054438Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.054462Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=8 +2026-07-20T04:57:44.062493Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.062527Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=10 +2026-07-20T04:57:44.069389Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.069422Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=7 +2026-07-20T04:57:44.077400Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.077420Z INFO openlogi_hid::gesture: SPIKE raw xy dx=8 dy=8 +2026-07-20T04:57:44.084414Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.084436Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=7 +2026-07-20T04:57:44.092549Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.092573Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=8 +2026-07-20T04:57:44.099506Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.099543Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=4 +2026-07-20T04:57:44.107429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.107451Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=6 +2026-07-20T04:57:44.114548Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.114619Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=3 +2026-07-20T04:57:44.122376Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 22, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.122411Z INFO openlogi_hid::gesture: SPIKE raw xy dx=22 dy=3 +2026-07-20T04:57:44.129378Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 24, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.129394Z INFO openlogi_hid::gesture: SPIKE raw xy dx=24 dy=1 +2026-07-20T04:57:44.137424Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.137449Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=0 +2026-07-20T04:57:44.144444Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 27, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.144461Z INFO openlogi_hid::gesture: SPIKE raw xy dx=27 dy=-4 +2026-07-20T04:57:44.152519Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 24, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.152564Z INFO openlogi_hid::gesture: SPIKE raw xy dx=24 dy=-5 +2026-07-20T04:57:44.159381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 24, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.159399Z INFO openlogi_hid::gesture: SPIKE raw xy dx=24 dy=-7 +2026-07-20T04:57:44.167327Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 23, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.167348Z INFO openlogi_hid::gesture: SPIKE raw xy dx=23 dy=-8 +2026-07-20T04:57:44.174462Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 25, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.174483Z INFO openlogi_hid::gesture: SPIKE raw xy dx=25 dy=-12 +2026-07-20T04:57:44.182401Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.182420Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=-11 +2026-07-20T04:57:44.189465Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 17, 255, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.189487Z INFO openlogi_hid::gesture: SPIKE raw xy dx=17 dy=-13 +2026-07-20T04:57:44.197429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.197478Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=-15 +2026-07-20T04:57:44.204511Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 12, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.204544Z INFO openlogi_hid::gesture: SPIKE raw xy dx=12 dy=-16 +2026-07-20T04:57:44.212693Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 255, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.212715Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=-17 +2026-07-20T04:57:44.219374Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 4, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.219416Z INFO openlogi_hid::gesture: SPIKE raw xy dx=4 dy=-12 +2026-07-20T04:57:44.227459Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.236659Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-16 +2026-07-20T04:57:44.236730Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.236740Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-14 +2026-07-20T04:57:44.242347Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.242390Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-8 +2026-07-20T04:57:44.249332Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.249383Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-10 +2026-07-20T04:57:44.257391Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.257408Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=-5 +2026-07-20T04:57:44.264581Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 237, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.264600Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-19 dy=-8 +2026-07-20T04:57:44.272381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 233, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.272399Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-23 dy=-5 +2026-07-20T04:57:44.279525Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 239, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.279557Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-17 dy=-2 +2026-07-20T04:57:44.287317Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.287335Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=-2 +2026-07-20T04:57:44.294467Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.294486Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-26 dy=0 +2026-07-20T04:57:44.302673Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 231, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.302698Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-25 dy=3 +2026-07-20T04:57:44.309716Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 232, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.309740Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-24 dy=5 +2026-07-20T04:57:44.317421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 229, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.317444Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-27 dy=7 +2026-07-20T04:57:44.324421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.324441Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=7 +2026-07-20T04:57:44.332417Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 238, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.332438Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-18 dy=8 +2026-07-20T04:57:44.339383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 240, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.339403Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-16 dy=11 +2026-07-20T04:57:44.347453Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.347487Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=11 +2026-07-20T04:57:44.354434Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.354465Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=13 +2026-07-20T04:57:44.362546Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.362580Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=14 +2026-07-20T04:57:44.369531Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 254, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.369551Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-2 dy=14 +2026-07-20T04:57:44.377354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.377372Z INFO openlogi_hid::gesture: SPIKE raw xy dx=0 dy=14 +2026-07-20T04:57:44.384592Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.384613Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=13 +2026-07-20T04:57:44.392572Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 6, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.392590Z INFO openlogi_hid::gesture: SPIKE raw xy dx=6 dy=13 +2026-07-20T04:57:44.399446Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.399482Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=12 +2026-07-20T04:57:44.407353Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 9, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.407389Z INFO openlogi_hid::gesture: SPIKE raw xy dx=9 dy=8 +2026-07-20T04:57:44.414321Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 16, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.414345Z INFO openlogi_hid::gesture: SPIKE raw xy dx=16 dy=10 +2026-07-20T04:57:44.422344Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.422364Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=8 +2026-07-20T04:57:44.429343Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.429377Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=4 +2026-07-20T04:57:44.437345Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 21, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.437361Z INFO openlogi_hid::gesture: SPIKE raw xy dx=21 dy=4 +2026-07-20T04:57:44.444447Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 15, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.444464Z INFO openlogi_hid::gesture: SPIKE raw xy dx=15 dy=2 +2026-07-20T04:57:44.452477Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.452495Z INFO openlogi_hid::gesture: SPIKE raw xy dx=21 dy=0 +2026-07-20T04:57:44.459292Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.459337Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=-2 +2026-07-20T04:57:44.467352Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 19, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.467370Z INFO openlogi_hid::gesture: SPIKE raw xy dx=19 dy=-5 +2026-07-20T04:57:44.474323Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.474346Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-7 +2026-07-20T04:57:44.482343Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 18, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.482361Z INFO openlogi_hid::gesture: SPIKE raw xy dx=18 dy=-9 +2026-07-20T04:57:44.489592Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.489614Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-8 +2026-07-20T04:57:44.497422Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 11, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.497476Z INFO openlogi_hid::gesture: SPIKE raw xy dx=11 dy=-12 +2026-07-20T04:57:44.504429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 5, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.504461Z INFO openlogi_hid::gesture: SPIKE raw xy dx=5 dy=-10 +2026-07-20T04:57:44.512518Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.512546Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-10 +2026-07-20T04:57:44.519311Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 1, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.519345Z INFO openlogi_hid::gesture: SPIKE raw xy dx=1 dy=-16 +2026-07-20T04:57:44.527365Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.527384Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-9 +2026-07-20T04:57:44.534511Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.534528Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-9 +2026-07-20T04:57:44.542389Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.542419Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-8 +2026-07-20T04:57:44.549508Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.549525Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-10 +2026-07-20T04:57:44.557335Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.557352Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-5 +2026-07-20T04:57:44.564546Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.564563Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-4 +2026-07-20T04:57:44.572573Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.572609Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-3 +2026-07-20T04:57:44.579297Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.579328Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-3 +2026-07-20T04:57:44.587360Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.587379Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-2 +2026-07-20T04:57:44.594410Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.594430Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-1 +2026-07-20T04:57:44.602477Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.602518Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-1 +2026-07-20T04:57:44.609398Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.609435Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=0 +2026-07-20T04:57:44.617465Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 253, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.617500Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-3 dy=-1 +2026-07-20T04:57:44.624504Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:44.624533Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=0 +2026-07-20T04:57:44.893484Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:44.895328Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:44.895381Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:44.905391Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:44.910320Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:44.910380Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:45.659509Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 0, function_id: U4(1), software_id: U4(1) }, [4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.674423Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 0, function_id: U4(0), software_id: U4(1) }, [1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.689351Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(0), software_id: U4(1) }, [45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.712381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.727396Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 3, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.742485Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 5, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.764633Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [29, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.787428Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 32, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.809589Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 33, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.824425Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.839443Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.862621Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [16, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.877420Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [23, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.892560Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [25, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.914449Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [25, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:45.914548Z DEBUG openlogi_hid::inventory::probe: Bolt slot probe timed out; using cached data if available slot=2 budget=1s +2026-07-20T04:57:45.920488Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:45.920524Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:45.921433Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:45.921434Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:45.923552Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:45.923559Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:45.925489Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:45.925498Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:45.925615Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:57:45.929405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [27, 4, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:47.962610Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:57:47.984354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:57:48.050357Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:48.050380Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:48.050383Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:48.050385Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:57:48.050387Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:48.050390Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:48.050395Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:48.050399Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:48.050401Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:48.050403Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:48.050405Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:48.050407Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:48.050409Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:48.050411Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:48.050413Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:48.050415Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:48.050417Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:48.050419Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:48.050421Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:48.050423Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:48.050425Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:57:48.050427Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:48.050429Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:48.050431Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:48.050433Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:48.050440Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:57:48.097607Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:57:48.097630Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:57:48.097727Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:48.099280Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:57:48.099288Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:57:48.100344Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:48.104352Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:48.104366Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:48.111308Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:48.113411Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:49.622294Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:49.624400Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:49.624429Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:49.633438Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:49.641545Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:49.641599Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:50.017406Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:57:50.025430Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 0, function_id: U4(1), software_id: U4(1) }, [4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.039410Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:57:50.047363Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 0, function_id: U4(0), software_id: U4(1) }, [1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.069548Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(0), software_id: U4(1) }, [45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.092402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.114474Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 3, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.137468Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 5, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.159392Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [29, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.182392Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 32, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.204483Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 33, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.219445Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.234354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.257361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [16, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.272394Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [23, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.287345Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [25, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.309504Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [25, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.332455Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [27, 4, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.354549Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 20, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.377344Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 21, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.399405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [34, 80, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.422315Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [33, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.444515Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [33, 33, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.467403Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [33, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.489530Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [34, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.504664Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [34, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.519471Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.542485Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 2, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.557438Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 3, 112, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.572582Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 7, 112, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.594460Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 22, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.617437Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 5, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.639558Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 48, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:50.643374Z DEBUG openlogi_hid::inventory::probe: Bolt slot probe timed out; using cached data if available slot=2 budget=1s +2026-07-20T04:57:50.645406Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:50.645421Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:50.646443Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:50.646531Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:50.649585Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:50.649604Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:50.652391Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:50.652444Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:50.652660Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:57:50.662629Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 145, 104, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:52.737968Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:52.737996Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:52.737999Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:52.738001Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:57:52.738003Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:52.738005Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:52.738007Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:52.738009Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:52.738011Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:52.738013Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:52.738018Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:52.738022Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:52.738024Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:52.738026Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:52.738029Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:52.738031Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:52.738033Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:52.738035Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:52.738037Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:52.738039Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:52.738041Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:57:52.738043Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:52.738045Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:52.738047Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:52.738049Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:52.738056Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:57:52.783088Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:57:52.783113Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:57:52.783220Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:52.784262Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:57:52.784270Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:57:52.785337Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:52.791437Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:52.791447Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:52.798522Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:52.799487Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:54.311514Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:54.313464Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:54.313493Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:54.321564Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:54.328566Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:54.328576Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:54.704348Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:57:54.712405Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 0, function_id: U4(1), software_id: U4(1) }, [4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.719402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:57:54.727399Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 0, function_id: U4(0), software_id: U4(1) }, [1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.749475Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(0), software_id: U4(1) }, [45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.764508Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.779542Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 3, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.802421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 5, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.817450Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [29, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.832383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 32, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.854534Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 33, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.877358Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.899555Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.914461Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [16, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.929440Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [23, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.952398Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [25, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.967483Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [25, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:54.982419Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [27, 4, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.004398Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 20, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.019435Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 21, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.034361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [34, 80, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.049383Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [33, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.064507Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [33, 33, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.087440Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [33, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.102424Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [34, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.117353Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [34, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.139596Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.162487Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 2, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.184475Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 3, 112, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.207307Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 7, 112, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.229579Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 22, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.259463Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 5, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.282621Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 48, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.304482Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 145, 104, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.319391Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 161, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.334505Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [30, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:55.334550Z DEBUG openlogi_hid::inventory::probe: Bolt slot probe timed out; using cached data if available slot=2 budget=1s +2026-07-20T04:57:55.338327Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:55.338356Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:55.341458Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:55.341474Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:55.344336Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:55.344366Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:55.346284Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:55.346310Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:55.346485Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:57:55.357403Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [30, 2, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:57.477750Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:57.477782Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:57.477785Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:57.477787Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:57:57.477789Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:57.477792Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:57.477794Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:57.477799Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:57.477801Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:57.477837Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:57:57.477840Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:57:57.477842Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:57:57.477844Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:57:57.477846Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:57:57.477848Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:57.477850Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:57.477853Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:57:57.477855Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:57.477857Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:57:57.477859Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:57:57.477861Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:57:57.477864Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:57:57.477866Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:57:57.477868Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:57:57.477870Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:57:57.477877Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:57:57.523906Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:57:57.523933Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:57:57.524015Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:57:57.525307Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:57:57.525326Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:57:57.526317Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:57:57.531314Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:57:57.531337Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:57:57.538298Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:57:57.539323Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:57:58.897389Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:57:58.919346Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:57:59.051151Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:57:59.053659Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:57:59.053717Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:57:59.063421Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:57:59.069391Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:57:59.069432Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:57:59.084459Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 0, function_id: U4(1), software_id: U4(1) }, [4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.099536Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 0, function_id: U4(0), software_id: U4(1) }, [1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.122640Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(0), software_id: U4(1) }, [45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.144450Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.159483Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 3, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.174571Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 5, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.189443Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [29, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.204512Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 32, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.228372Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 33, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.243452Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.258582Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.279589Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [16, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.303711Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [23, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.324629Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [25, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.339398Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [25, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.354477Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [27, 4, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.378363Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 20, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.393361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 21, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.408353Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [34, 80, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.429482Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [33, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.444542Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [33, 33, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.459494Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [33, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.474475Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [34, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.489606Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [34, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.513430Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [0, 209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.528496Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 2, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.543520Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 3, 112, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.564366Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 7, 112, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.588419Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 22, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.609404Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 5, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.633578Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 48, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.654471Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 145, 104, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.678615Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 161, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.693316Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [30, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.708497Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [30, 2, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.729647Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [30, 34, 112, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.744346Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [30, 48, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.759402Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [22, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.782482Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [30, 176, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.804409Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 97, 112, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.827380Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [146, 5, 112, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.849581Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [146, 1, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.872517Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [147, 0, 112, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.894301Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [148, 1, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.909438Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [148, 2, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.924484Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [144, 1, 112, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.947370Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 177, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.962604Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 1, function_id: U4(1), software_id: U4(1) }, [24, 192, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.977353Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 18, function_id: U4(0), software_id: U4(1) }, [15, 28, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:57:59.999349Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.022467Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(1) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:58:00.030414Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.030470Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-12 +2026-07-20T04:58:00.037427Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 3, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.037446Z INFO openlogi_hid::gesture: SPIKE raw xy dx=3 dy=-10 +2026-07-20T04:58:00.044626Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(2), software_id: U4(1) }, [50, 53, 51, 48, 90, 65, 76, 53, 81, 71, 78, 56, 0, 0, 0, 0]) +2026-07-20T04:58:00.052515Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 14, 255, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.052558Z INFO openlogi_hid::gesture: SPIKE raw xy dx=14 dy=-50 +2026-07-20T04:58:00.060722Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 10, 255, 182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.060750Z INFO openlogi_hid::gesture: SPIKE raw xy dx=10 dy=-74 +2026-07-20T04:58:00.067403Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 3, function_id: U4(2), software_id: U4(1) }, [3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.070432Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:00.070454Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:00.072393Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:00.072398Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:00.074582Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:00.074600Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:00.075346Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [0, 2, 255, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.075364Z INFO openlogi_hid::gesture: SPIKE raw xy dx=2 dy=-50 +2026-07-20T04:58:00.078469Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:00.078492Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:00.078653Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:58:00.082349Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.082362Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=-124 +2026-07-20T04:58:00.090440Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.090470Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-66 +2026-07-20T04:58:00.097440Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.097460Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-69 +2026-07-20T04:58:00.105504Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.105522Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-76 +2026-07-20T04:58:00.112430Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 255, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.112448Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=-28 +2026-07-20T04:58:00.405587Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.405617Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-5 +2026-07-20T04:58:00.412538Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 255, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.412572Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=-7 +2026-07-20T04:58:00.420554Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.420585Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-3 +2026-07-20T04:58:00.427448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 243, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.427471Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-13 dy=6 +2026-07-20T04:58:00.435711Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.435754Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=-1 +2026-07-20T04:58:00.442693Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 251, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.442710Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-5 dy=-10 +2026-07-20T04:58:00.450375Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 245, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.450406Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-11 dy=-10 +2026-07-20T04:58:00.457363Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.457384Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-4 +2026-07-20T04:58:00.465381Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 247, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.465413Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-9 dy=-2 +2026-07-20T04:58:00.472491Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 249, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.472510Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-7 dy=2 +2026-07-20T04:58:00.480604Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 246, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.480647Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-10 dy=5 +2026-07-20T04:58:00.487473Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 250, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.487517Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-6 dy=7 +2026-07-20T04:58:00.495515Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 248, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.495533Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-8 dy=8 +2026-07-20T04:58:00.502763Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 252, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.502798Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-4 dy=1 +2026-07-20T04:58:00.510380Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.510409Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=0 +2026-07-20T04:58:00.517436Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 13, function_id: U4(1), software_id: U4(0) }, [255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:00.517454Z INFO openlogi_hid::gesture: SPIKE raw xy dx=-1 dy=0 +2026-07-20T04:58:02.174350Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:02.174380Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:02.174383Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:02.174385Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:58:02.174387Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:02.174389Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:02.174391Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:02.174393Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:02.174395Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:02.174397Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:02.174402Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:58:02.174404Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:58:02.174406Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:02.174408Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:02.174410Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:02.174412Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:02.174414Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:02.174416Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:02.174418Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:58:02.174420Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:02.174422Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:58:02.174424Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:58:02.174426Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:02.174428Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:58:02.174430Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:02.174437Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:58:02.217920Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:58:02.217946Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:58:02.218030Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:58:02.219397Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:58:02.219449Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:58:02.219461Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:58:02.226345Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:58:02.226382Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:58:02.234405Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:58:02.235365Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:58:03.132830Z DEBUG openlogi_agent_core::watchers::foreground_app: frontmost app changed current=Some("c:\\program files (x86)\\steam\\steamapps\\common\\command & conquer generals - zero hour\\game.dat") last=Some("c:\\program files\\windowsapps\\claude_1.22209.3.0_x64__pzs8sxrjxfjjc\\app\\claude.exe") +2026-07-20T04:58:03.743980Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:58:03.747291Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:03.747359Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:03.756350Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:58:03.763373Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:58:03.763456Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:58:04.102601Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:58:04.117465Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:04.119394Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:04.119400Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:04.122396Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:04.122450Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:04.124327Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:04.124394Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:04.125477Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:58:04.127536Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:04.127547Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:04.127688Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:58:06.251959Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:06.251989Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:06.251992Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:06.251994Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:58:06.251999Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:06.252001Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:06.252003Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:06.252005Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:06.252007Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:06.252009Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:06.252011Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:58:06.252013Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:58:06.252015Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:06.252017Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:06.252019Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:06.252021Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:06.252023Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:06.252025Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:06.252027Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:58:06.252029Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:06.252031Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:58:06.252033Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:58:06.252035Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:06.252037Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:58:06.252039Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:06.252046Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:58:06.298902Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:58:06.298931Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:58:06.299015Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:58:06.300250Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:58:06.300320Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:58:06.300412Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:58:06.306394Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:58:06.306406Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:58:06.314372Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:58:06.315322Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:58:07.672441Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:58:07.695528Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:58:07.827526Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:58:07.829416Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:07.829469Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:07.838528Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:58:07.845426Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:58:07.845430Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:58:07.860492Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:07.862492Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:07.862510Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:07.865400Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:07.865461Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:07.866454Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:07.866536Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:07.868449Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:07.868470Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:07.868601Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:58:09.957318Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:09.957362Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:09.957368Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:09.957370Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:58:09.957373Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:09.957375Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:09.957377Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:09.957379Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:09.957382Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:09.957384Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:09.957386Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:58:09.957388Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:58:09.957391Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:09.957393Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:09.957408Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:09.957411Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:09.957413Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:09.957416Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:09.957418Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:58:09.957421Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:09.957423Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:58:09.957425Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:58:09.957428Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:09.957430Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:58:09.957432Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:09.957440Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:58:10.003801Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:58:10.003830Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:58:10.003916Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:58:10.005293Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:58:10.005308Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:58:10.006377Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:58:10.011383Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:58:10.011417Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:58:10.018408Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:58:10.019403Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:58:11.531853Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:58:11.533645Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:11.533662Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:11.542476Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:58:11.549448Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:58:11.549528Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:58:11.910435Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:58:11.918357Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:11.921448Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:11.921466Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:11.923333Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:11.923424Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:11.924405Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:11.924406Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:11.927385Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:11.927451Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:11.927625Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:58:11.933495Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:58:14.055253Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:14.055283Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:14.055287Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:14.055289Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:58:14.055292Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:14.055294Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:14.055297Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:14.055299Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:14.055302Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:14.055304Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:14.055307Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:58:14.055311Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:58:14.055313Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:14.055335Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:14.055338Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:14.055340Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:14.055343Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:14.055346Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:14.055348Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:58:14.055351Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:14.055353Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:58:14.055356Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:58:14.055367Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:14.055370Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:58:14.055372Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:14.055379Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:58:14.105023Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:58:14.105049Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:58:14.105153Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:58:14.106315Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:58:14.106333Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:58:14.107315Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:58:14.113311Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:58:14.113355Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:58:14.118403Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:58:14.120291Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:58:15.137313Z DEBUG openlogi_agent_core::watchers::foreground_app: frontmost app changed current=None last=Some("c:\\program files (x86)\\steam\\steamapps\\common\\command & conquer generals - zero hour\\game.dat") +2026-07-20T04:58:15.625511Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:58:15.627431Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:15.627432Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:15.636338Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:58:15.642382Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:58:15.642385Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:58:15.960345Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:58:15.975314Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:15.977342Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:15.977353Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:15.980365Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:15.980510Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:15.982322Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:15.982488Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:15.984437Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:58:15.986381Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:15.986413Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:15.986698Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:58:16.137808Z DEBUG openlogi_agent_core::watchers::foreground_app: frontmost app changed current=Some("c:\\program files\\windowsapps\\claude_1.22209.3.0_x64__pzs8sxrjxfjjc\\app\\claude.exe") last=None +2026-07-20T04:58:18.081084Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:18.081112Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:18.081115Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:18.081117Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:58:18.081119Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:18.081121Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:18.081123Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:18.081125Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:18.081127Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:18.081129Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:18.081131Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:58:18.081133Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:58:18.081135Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:18.081137Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:18.081139Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:18.081185Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:18.081190Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:18.081192Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:18.081194Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:58:18.081196Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:18.081198Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:58:18.081200Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:58:18.081203Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:18.081205Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:58:18.081207Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:18.081215Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:58:18.129390Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:58:18.129416Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:58:18.129495Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:58:18.131305Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:58:18.131346Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:58:18.132378Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:58:18.135338Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:58:18.135396Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:58:18.142438Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:58:18.143382Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:58:19.530354Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:58:19.553378Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:58:19.654282Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:58:19.657299Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:19.657313Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:19.668316Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:58:19.674333Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:58:19.674350Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:58:19.695380Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:19.698320Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:19.698356Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:19.701304Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:19.701415Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:19.703313Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:19.703342Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:19.706293Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:19.706326Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:19.706479Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:58:21.831701Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:21.831732Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:21.831735Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:21.831737Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:58:21.831739Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:21.831741Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:21.831743Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:21.831745Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:21.831747Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:21.831749Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:21.831751Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:58:21.831807Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:58:21.831811Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:21.831813Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:21.831815Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:21.831817Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:21.831819Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:21.831821Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:21.831823Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:58:21.831825Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:21.831827Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:58:21.831829Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:58:21.831831Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:21.831833Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:58:21.831835Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:21.831842Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:58:21.877551Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:58:21.877579Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:58:21.877664Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:58:21.879236Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:58:21.879254Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:58:21.880361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:58:21.885335Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:58:21.885380Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:58:21.892430Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:58:21.893402Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:58:23.141095Z DEBUG openlogi_agent_core::watchers::foreground_app: frontmost app changed current=Some("c:\\windows\\explorer.exe") last=Some("c:\\program files\\windowsapps\\claude_1.22209.3.0_x64__pzs8sxrjxfjjc\\app\\claude.exe") +2026-07-20T04:58:23.407254Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:58:23.410373Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:23.410397Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:23.420358Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:58:23.424330Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:58:23.424369Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:58:23.738362Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:58:23.745342Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:23.747338Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:23.747378Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:23.749318Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:23.749354Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:23.751354Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:23.751416Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:23.753333Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:58:23.754312Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:23.754353Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:23.754584Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:58:24.141724Z DEBUG openlogi_agent_core::watchers::foreground_app: frontmost app changed current=Some("c:\\program files\\google\\chrome\\application\\chrome.exe") last=Some("c:\\windows\\explorer.exe") +2026-07-20T04:58:25.855551Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:25.855594Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:25.855603Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:25.855619Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:58:25.855630Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:25.855636Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:25.855642Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:25.855648Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:25.855653Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:25.855659Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:25.855665Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:58:25.855671Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:58:25.855677Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:25.855683Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:25.855688Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:25.855695Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:25.855700Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:25.855706Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:25.855712Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:58:25.855719Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:25.855725Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:58:25.855730Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:58:25.855736Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:25.855742Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:58:25.855748Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:25.855764Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:58:25.906196Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:58:25.906232Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:58:25.906414Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:58:25.908303Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:58:25.908343Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:58:25.909459Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:58:25.915413Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:58:25.915448Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:58:25.920364Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:58:25.922400Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:58:27.435776Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:58:27.439368Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:27.439447Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:27.447428Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:58:27.455429Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:58:27.455474Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:58:27.795425Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:58:27.810376Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:27.813367Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:27.813415Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:27.816366Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:27.816418Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:27.818383Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:27.818438Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:27.820414Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:58:27.821347Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:27.821373Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:27.821643Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:58:29.961898Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:29.962114Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:29.962123Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:29.962128Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:58:29.962136Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:29.962141Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:29.962145Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:29.962149Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:29.962153Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:29.962157Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:29.962161Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:58:29.962165Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:58:29.962168Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:29.962172Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:29.962176Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:29.962181Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:29.962184Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:29.962188Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:29.962193Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:58:29.962197Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:29.962201Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:58:29.962204Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:58:29.962209Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:29.962213Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:58:29.962217Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:29.962231Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:58:30.014547Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:58:30.014652Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:58:30.014790Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:58:30.016323Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:58:30.016352Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:58:30.017357Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:58:30.022334Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:58:30.022424Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:58:30.030355Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:58:30.032347Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:58:31.351330Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:58:31.366364Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:58:31.539926Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:58:31.542493Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:31.542523Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:31.551517Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:58:31.559640Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:58:31.559644Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:58:31.575582Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:31.578561Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:31.578593Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:31.581536Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:31.581557Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:31.583545Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:31.583559Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:31.585462Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:31.585478Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:31.585817Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:58:33.688732Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:33.688763Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:33.688768Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:33.688772Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:58:33.688775Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:33.688779Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:33.688782Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:33.688785Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:33.688788Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:33.688792Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:33.688796Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:58:33.688799Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:58:33.688802Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:33.688806Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:33.688809Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:33.688813Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:33.688816Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:33.688820Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:33.688824Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:58:33.688827Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:33.688831Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:58:33.688835Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:58:33.688844Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:33.688851Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:58:33.688854Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:33.688868Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:58:33.740134Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:58:33.740166Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:58:33.740370Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:58:33.742324Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:58:33.742382Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:58:33.742397Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:58:33.749667Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:58:33.749757Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:58:33.757442Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:58:33.758498Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:58:35.265803Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:58:35.272407Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:35.272551Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:35.281450Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:58:35.287485Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:58:35.287544Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:58:35.617593Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:58:35.625516Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:35.628442Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:35.628489Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:35.631526Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:35.631559Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:35.632499Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:58:35.633568Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:35.633564Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:35.635343Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:35.635390Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:35.635600Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:58:37.774618Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:37.774637Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:37.774639Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:37.774642Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:58:37.774644Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:37.774647Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:37.774649Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:37.774652Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:37.774659Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:37.774666Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:37.774672Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:58:37.774679Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:58:37.774681Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:37.774684Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:37.774686Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:37.774688Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:37.774691Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:37.774696Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:37.774699Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:58:37.774703Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:37.774705Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:58:37.774707Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:58:37.774710Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:37.774712Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:58:37.774714Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:37.774722Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:58:37.828000Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:58:37.828027Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:58:37.829321Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:58:37.829348Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:58:37.829361Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:58:37.835396Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:58:37.835513Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:58:37.841369Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:58:37.843327Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:58:37.893601Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:58:39.357185Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:58:39.359429Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:39.359459Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:39.368350Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:58:39.374556Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:58:39.374561Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:58:39.676323Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:58:39.690416Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:39.692382Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:39.692383Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:39.694343Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:39.694351Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:39.697339Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:39.697352Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:39.698398Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:58:39.699318Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:39.699323Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:39.699462Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:58:41.798441Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:41.798464Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:41.798466Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:41.798469Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:58:41.798471Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:41.798474Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:41.798476Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:41.798478Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:41.798480Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:41.798482Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:41.798484Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:58:41.798486Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:58:41.798488Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:41.798493Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:41.798497Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:41.798499Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:41.798501Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:41.798504Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:41.798506Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:58:41.798508Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:41.798510Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:58:41.798512Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:58:41.798514Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:41.798517Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:58:41.798519Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:41.798527Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:58:41.849943Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:58:41.849981Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:58:41.850176Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:58:41.851423Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:58:41.851461Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:58:41.853356Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:58:41.857425Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:58:41.857503Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:58:41.864357Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:58:41.865479Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0]) +2026-07-20T04:58:43.379595Z DEBUG openlogi_hid::inventory::probe: drained device-arrival events events=1 +2026-07-20T04:58:43.383508Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=1 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:43.383579Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:43.393583Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [82, 2, 66, 176, 18, 193, 120, 77, 2, 1, 128, 20, 1, 0, 0, 0]) +2026-07-20T04:58:43.400477Z DEBUG openlogi_hid::inventory::probe: paired slot slot=2 online=true wpid=Some(45122) bolt_kind=Mouse has_event=true codename=Some("MX Master 4") +2026-07-20T04:58:43.400476Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(11), software_id: U4(5) }, [98, 1, 11, 77, 88, 32, 77, 97, 115, 116, 101, 114, 32, 52, 0, 0]) +2026-07-20T04:58:43.740524Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(0), software_id: U4(14) }, [4, 18, 193, 120, 77, 0, 2, 176, 66, 0, 0, 0, 0, 1, 1, 0]) +2026-07-20T04:58:43.748529Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 9, function_id: U4(1), software_id: U4(1) }, [30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +2026-07-20T04:58:43.751369Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:43.751468Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=3 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:43.754488Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:43.754556Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=4 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:43.757350Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:43.757428Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=5 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:43.760440Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 143, function_id: U4(8), software_id: U4(3) }, [181, 8, 0]) +2026-07-20T04:58:43.760492Z DEBUG openlogi_hid::inventory::probe: slot empty or unreadable slot=6 error=Protocol(RegisterAccess(UnknownDevice)) +2026-07-20T04:58:43.760726Z WARN openlogi_hid::inventory: node probe keeps failing — dropping its channel to reopen next tick +2026-07-20T04:58:43.762369Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 2, feature_index: 2, function_id: U4(1), software_id: U4(14) }, [0, 82, 66, 77, 39, 3, 0, 25, 5, 176, 66, 3, 206, 8, 216, 0]) +2026-07-20T04:58:45.891969Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:45.892016Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:45.892024Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=c339 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:45.892030Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xffbc usage_id=0x0088 matched=false +2026-07-20T04:58:45.892036Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:45.892041Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:45.892046Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:45.892052Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:45.892057Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:45.892069Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0080 matched=false +2026-07-20T04:58:45.892078Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x0001 usage_id=0x0013 matched=false +2026-07-20T04:58:45.892084Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000e usage_id=0x0001 matched=false +2026-07-20T04:58:45.892089Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x0001 usage_id=0x0006 matched=false +2026-07-20T04:58:45.892094Z DEBUG openlogi_hid::transport: logitech HID node name=HID VHF Driver pid=4079 usage_page=0x0059 usage_id=0x0001 matched=false +2026-07-20T04:58:45.892099Z DEBUG openlogi_hid::transport: logitech HID node name=Logitech BRIO pid=085e usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:45.892105Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:45.892110Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0x000c usage_id=0x0001 matched=false +2026-07-20T04:58:45.892115Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:45.892120Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0602 matched=true +2026-07-20T04:58:45.892125Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0x0001 usage_id=0x0002 matched=false +2026-07-20T04:58:45.892131Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c539 usage_page=0xff00 usage_id=0x0004 matched=false +2026-07-20T04:58:45.892136Z DEBUG openlogi_hid::transport: logitech HID node name=PRO Gaming Keyboard pid=c339 usage_page=0xff43 usage_id=0x0604 matched=false +2026-07-20T04:58:45.892141Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0001 matched=false +2026-07-20T04:58:45.892146Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0x000d usage_id=0x0005 matched=false +2026-07-20T04:58:45.892151Z DEBUG openlogi_hid::transport: logitech HID node name=USB Receiver pid=c548 usage_page=0xff00 usage_id=0x0002 matched=true +2026-07-20T04:58:45.892165Z DEBUG openlogi_hid::inventory: HID++ candidate interfaces count=3 +2026-07-20T04:58:45.940154Z DEBUG openlogi_hid::transport::windows: paired Windows HID++ short collection name=USB Receiver pid=c539 +2026-07-20T04:58:45.940183Z DEBUG openlogi_hid::transport::windows: opened Windows HID++ composite channel name=USB Receiver pid=c539 supports_short=true supports_long=true +2026-07-20T04:58:45.940344Z DEBUG openlogi_hid::inventory::probe: BT-direct / wired device recognised name=PRO Gaming Keyboard +2026-07-20T04:58:45.941253Z DEBUG openlogi_hid::inventory::features: Device::new failed slot=255 error=UnsupportedProtocolVersion +2026-07-20T04:58:45.941272Z DEBUG openlogi_hid::inventory::probe: slot 0xff exposes no battery or config feature — likely a receiver secondary interface; skipping vid=046d pid=c539 has_model=false +2026-07-20T04:58:45.943467Z INFO openlogi_hid::gesture: SPIKE wire msg=Long(MessageHeader { device_index: 255, feature_index: 131, function_id: U4(15), software_id: U4(11) }, [57, 55, 66, 55, 54, 57, 52, 56, 65, 56, 52, 54, 67, 53, 53, 65]) +2026-07-20T04:58:45.948375Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 129, function_id: U4(0), software_id: U4(2) }, [0, 1, 0]) +2026-07-20T04:58:45.948481Z DEBUG openlogi_hid::inventory::probe: receiver reports pairing count pairing_count=Some(1) +2026-07-20T04:58:45.953368Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 2, feature_index: 65, function_id: U4(1), software_id: U4(0) }, [2, 66, 176]) +2026-07-20T04:58:45.954414Z INFO openlogi_hid::gesture: SPIKE wire msg=Short(MessageHeader { device_index: 255, feature_index: 128, function_id: U4(0), software_id: U4(2) }, [0, 0, 0])