Files
insta360-link-tools/README.md
brad bf6595614a Fix KDE shortcuts never binding, and add a joystick widget
The shortcuts wrote the Plasma 5 value format and so never bound anything,
which is what produced "No default shortcuts" in System Settings.

kglobalacceld's KServiceActionComponent::loadSettings reads the services
_launch key as a bare key sequence and hands it straight to
QKeySequence::fromString. Plasma 5 stored a "keys,default,name" triplet
there and Plasma 6 does not, so "Meta+Alt+T,none,Insta360: Toggle AI
tracking" parsed to an empty sequence and bound no key. The value is now
just the key sequence; alternates would be tab-separated and "none" means
unbound.

Two supporting changes. The desktop entries now carry X-KDE-Shortcuts,
which is where kglobalacceld reads an entry's default shortcut from, so the
binding shows up in System Settings as a default instead of as nothing.
And they are no longer NoDisplay by default: KApplicationTrader skips
NoDisplay services, so hiding them from the launcher also hid them from the
Shortcuts page, which is the opposite of helpful. HIDE_FROM_MENU=1 restores
the old behaviour.

--list is now a diagnostic rather than a bare dump: it reports the
registered key, the default from the desktop entry, whether the entry file
exists, and flags any comma-bearing value as the unparseable Plasma 5 form.
It would have identified this fault directly.

The new plasmoid is a Plasma 6 applet: a velocity-style virtual joystick
plus zoom slider and Home/Center/Tracking buttons. It drives the gimbal
with relative moves, not absolute ones, because linkctl status reports no
pan or tilt while the camera is idle, leaving no trustworthy position to aim
from; relative steps work in either state and cannot drift, and linkctl
clamps them to the device range. The pure logic lives in a .js library so it
is testable outside Plasma.

Tested: 36 new node checks over shell quoting, tick command construction,
inversion, the per-axis threshold and the multi-object JSON merge, each
confirmed meaningful by mutation. Reproduced the broken shortcut state in a
throwaway HOME and verified --list flags it and reinstalling repairs it. All
QML passes qmllint with no syntax errors (KDE modules are unresolvable
offline). shellcheck clean. The applet has not been loaded in a real Plasma
session.
2026-10-07 21:03:38 -07:00

162 lines
6.7 KiB
Markdown

# Insta360 Link 2 integration for OBS and KDE
Hotkey and OBS integration on top of [`linkctl`](https://github.com/illegalstudio/linkctl),
so AI tracking and gimbal presets are a keypress rather than a terminal command.
Three pieces, usable independently:
| Path | What it gives you |
|---|---|
| `bin/linkctl-macro` | A wrapper that makes `linkctl` safe to bind to a hotkey: finds the binary in a desktop session's sparse `PATH`, passes `--force`, and reports the result as a desktop notification. |
| `kde/install-shortcuts.sh` | Registers KDE Plasma global shortcuts, so the keys work from anywhere including under Wayland. |
| `obs/obs-linkctl.lua` | OBS hotkeys, buttons, and scene automation: a scene switch can set tracking or load a preset on its own. |
| `plasmoid/` | A Plasma 6 widget with a virtual joystick, zoom slider, and Home/Center/Tracking buttons. |
## Prerequisites
`linkctl` installed and working (`linkctl status` reports your camera), and a
saved home preset:
```sh
linkctl preset save home # point the camera where you want "home" first
```
## Install
```sh
./kde/install-shortcuts.sh --dry-run # review, changes nothing
./kde/install-shortcuts.sh
```
Default bindings, editable in the `BINDINGS` table at the top of that script:
| Key | Action |
|---|---|
| `Meta+Alt+T` | toggle AI tracking |
| `Meta+Alt+1` | tracking on |
| `Meta+Alt+0` | tracking off |
| `Meta+Alt+H` | `preset load home` |
| `Meta+Alt+C` | recenter gimbal |
Check them afterwards with `./kde/install-shortcuts.sh --list`, which shows the
registered key, the default from the desktop entry, and flags any value Plasma
cannot parse. Or look in System Settings under Keyboard, Shortcuts, searching
for "Insta360". Reverse the whole thing with `--uninstall`.
The entries are visible in the launcher by default, because Plasma skips
`NoDisplay` services when building the Shortcuts list and they would otherwise
not appear there at all. `HIDE_FROM_MENU=1 ./kde/install-shortcuts.sh` hides
them at that cost.
## Joystick widget
```sh
./plasmoid/install.sh
```
Then right-click a panel or the desktop, Add Widgets, and search for
"Insta360". Pass `--restart` when reinstalling over a running copy, since
Plasma otherwise keeps the old one loaded.
The joystick is a velocity control: how far you push sets how fast the camera
moves, and it stops when you let go. Degrees per step, step interval, deadzone
and axis inversion are all in the widget's settings, along with the `linkctl`
path and an optional device.
It drives the gimbal with *relative* moves rather than absolute ones, because
`linkctl status` reports no pan or tilt at all while the camera is idle, so
there is no trustworthy position to aim from. Relative steps work either way
and cannot drift out of sync, and linkctl clamps each one to the camera's own
range, so holding the stick against a limit is harmless.
## OBS
Tools, Scripts, `+`, then pick `obs/obs-linkctl.lua`.
Set the `linkctl` binary path if it is not on OBS's `PATH`, then bind the
hotkeys under Settings, Hotkeys (search "Insta360").
**Scene automation.** Press *Insert current scene names* to prefill the mapping
box, then give the scenes you care about an action:
```
Talking Head = tracking on
Overhead = preset load overhead
Slides = tracking off
```
The left side is the scene name, the right side is any `linkctl` arguments.
Blank actions and `#` comments are ignored.
**Startup action** runs when OBS finishes loading, and defaults to
`preset load home`. This is the setting worth keeping: the Link parks its
gimbal facing down when idle, so launching OBS puts it back on its own.
Under Wayland, OBS's own hotkeys only fire while OBS has focus. That is an OBS
limitation, and the reason the KDE shortcuts exist; install both and use the
KDE ones for anything you need mid-stream.
## Configuration
Optional, at `~/.config/linkctl-macro.conf` (see `linkctl-macro.conf.example`):
```sh
LINKCTL=/usr/local/bin/linkctl # if not on PATH
LINKCTL_DEVICE=/dev/video0 # pin the camera if you have more than one
LINKCTL_FORCE=1 # 0 respects linkctl's idle-camera guard
LINKCTL_NOTIFY=always # always | error | never
```
`--force` is on by default because a deliberate keypress means "do it now",
including when nothing currently holds the camera open. That is exactly the
case where the gimbal is parked facing down.
## Testing without a camera
```sh
lua tests/test_obs_linkctl.lua # pure helpers: quoting, parsing, commands
lua tests/test_obs_lifecycle.lua # the OBS script against a mock OBS API
node tests/test_joystick_logic.js # the widget's command building and parsing
bin/linkctl-macro --print tracking on # show the command without running it
./kde/install-shortcuts.sh --dry-run # show the KDE changes, apply nothing
./kde/install-shortcuts.sh --list # diagnose what is actually registered
shellcheck bin/linkctl-macro kde/install-shortcuts.sh plasmoid/install.sh
```
The lifecycle suite drives the script the way OBS does, so it catches broken
wiring (hotkeys not firing, scene actions not matching, the preset name being
captured too early) without needing OBS or a camera.
## Troubleshooting
**Shortcut does nothing, and System Settings says "No default shortcuts".**
Run `./kde/install-shortcuts.sh --list`. A `_launch` value containing commas
is the Plasma 5 format: Plasma 6 passes that value straight to
`QKeySequence::fromString`, so `Meta+Alt+T,none,Some Name` parses to nothing
and binds no key. Re-running the installer rewrites it as a bare key sequence.
Versions of this repo before that fix wrote the Plasma 5 form.
**Shortcut still does nothing.** Run the action directly:
`bin/linkctl-macro tracking on`. A failure notification names the cause. If
that works but the key does not, check for a conflict in System Settings, and
confirm `--list` shows the entry as `present`.
**`tracking` fails with exit 12.** AI tracking is experimental in `linkctl` and
goes through the camera's vendor extension unit. Pan, tilt, zoom and presets use
standard UVC and are unaffected.
**Permission denied (exit 6).** Add yourself to the `video` group, or install
the udev rule from `linkctl`'s `contrib/99-insta360-link.rules`.
**Nothing moves at all.** The Link 2 rejects single-axis pan/tilt writes and
needs both axes set in one `VIDIOC_S_EXT_CTRLS` call. `linkctl` does this
correctly; raw `v4l2-ctl` needs `--set-ctrl pan_absolute=0,tilt_absolute=0`
as one argument.
## Status
The Lua helpers and the shell scripts are tested offline, and the KDE installer
is dry-runnable and reversible. None of it has been exercised against a live
camera or a running Plasma session by the author of this commit, so treat the
first run as the real test and use `--dry-run` first.