Fix KDE global shortcuts never binding under Plasma 6, and add a joystick widget #1

Merged
branderson merged 1 commits from plasma6-shortcut-fix-and-joystick into main 2026-10-07 21:57:44 -07:00
Collaborator

Summary generated by LLM agent

Why

The KDE global shortcuts installed by kde/install-shortcuts.sh never bound anything. System Settings reported "No default shortcuts" for every entry, and pressing the keys did nothing, while the same actions worked fine when run from a shell.

Root cause

kglobalacceld reads the _launch key of a [services][*.desktop] group as a bare key sequence and passes it straight to QKeySequence::fromString. Plasma 5 stored a keys,default_shortcut,friendly_name triplet in that key; Plasma 6 does not. So the value we wrote, Meta+Alt+T,none,Insta360: Toggle AI tracking, parsed to an empty sequence and bound no key, silently and with nothing logged.

This is confirmed against KServiceActionComponent::loadSettings in the kglobalacceld source rather than inferred from behaviour. Alternates in that value are separated by a tab, and the literal none means unbound.

What changed

_launch is now written as just the key sequence.

The generated desktop entries carry X-KDE-Shortcuts, which is where kglobalacceld reads an entry's default shortcut from. Without it an entry can function yet still display as having no shortcut, which is exactly the confusing state this started in.

The entries are no longer NoDisplay by default. KApplicationTrader::query skips NoDisplay services, so hiding them from the application launcher also hid them from the Shortcuts page in System Settings, making the bindings impossible to inspect or edit through the GUI. HIDE_FROM_MENU=1 restores the previous behaviour for anyone who would rather keep their launcher clean.

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

New: joystick widget

plasmoid/ adds a Plasma 6 applet: a velocity-style virtual joystick for pan and tilt, a zoom slider, and Home, Center and Tracking buttons. Push further to move faster; it stops on release. Degrees per step, step interval, deadzone, axis inversion, the linkctl path and an optional device are all configurable.

It drives the gimbal with relative moves rather than absolute ones. linkctl status reports no pan or tilt at all while the camera is idle, and returns before --force is even considered, so there is no trustworthy position to aim an absolute target from. Relative steps work whether the camera is idle or streaming, cannot drift out of sync with the hardware, and are clamped by linkctl to the device's own range, so holding the stick against a limit is harmless.

The applet's pure logic lives in contents/ui/logic.js specifically so it can be tested outside Plasma. QML itself is not reachable by a test harness here, but shell quoting, command construction and output parsing are the parts where mistakes would actually bite.

Testing

89 checks pass across three suites, and shellcheck is clean on all three shell scripts:

  • node tests/test_joystick_logic.js adds 36 checks over shell quoting, tick command construction, axis inversion, the per-axis threshold that stops a horizontal push creeping vertically, and the multi-object JSON merge a diagonal tick produces.
  • lua tests/test_obs_linkctl.lua and lua tests/test_obs_lifecycle.lua continue to pass unchanged.

Each new suite was mutation-tested to confirm it is not passing vacuously: shrinking the per-axis threshold, making the JSON merge replace instead of merge, disabling the quote escaping, and treating tracking: false as absent are all caught.

The reported fault was reproduced in a throwaway HOME by writing the Plasma 5 triplet form, then confirmed that --list flags it and that reinstalling repairs it to the bare form.

All QML passes qmllint with no syntax errors. The KDE and Plasma QML modules are not installable in the test environment, so their imports are unresolvable there and every remaining warning is of that kind.

Not verified

The applet has not been loaded in a running Plasma session, and the kwriteconfig6 calls were exercised against stubs rather than the real binary. The shortcut fix rests on reading KDE's source and on a reproduction against stubs, which is strong evidence but is not the same as a live session confirming the key now fires.

If the applet fails to load, journalctl --user -b -u plasma-plasmashell will name the QML error.

**Summary generated by LLM agent** ## Why The KDE global shortcuts installed by `kde/install-shortcuts.sh` never bound anything. System Settings reported "No default shortcuts" for every entry, and pressing the keys did nothing, while the same actions worked fine when run from a shell. ## Root cause `kglobalacceld` reads the `_launch` key of a `[services][*.desktop]` group as a **bare key sequence** and passes it straight to `QKeySequence::fromString`. Plasma 5 stored a `keys,default_shortcut,friendly_name` triplet in that key; Plasma 6 does not. So the value we wrote, `Meta+Alt+T,none,Insta360: Toggle AI tracking`, parsed to an empty sequence and bound no key, silently and with nothing logged. This is confirmed against `KServiceActionComponent::loadSettings` in the `kglobalacceld` source rather than inferred from behaviour. Alternates in that value are separated by a tab, and the literal `none` means unbound. ## What changed `_launch` is now written as just the key sequence. The generated desktop entries carry `X-KDE-Shortcuts`, which is where `kglobalacceld` reads an entry's *default* shortcut from. Without it an entry can function yet still display as having no shortcut, which is exactly the confusing state this started in. The entries are no longer `NoDisplay` by default. `KApplicationTrader::query` skips `NoDisplay` services, so hiding them from the application launcher also hid them from the Shortcuts page in System Settings, making the bindings impossible to inspect or edit through the GUI. `HIDE_FROM_MENU=1` restores the previous behaviour for anyone who would rather keep their launcher clean. `--list` is now a diagnostic instead of a bare dump. It reports the registered key, the default read from the desktop entry, and whether the entry file exists, and it flags any comma-bearing `_launch` value as the unparseable Plasma 5 form. It would have identified this fault immediately. ## New: joystick widget `plasmoid/` adds a Plasma 6 applet: a velocity-style virtual joystick for pan and tilt, a zoom slider, and Home, Center and Tracking buttons. Push further to move faster; it stops on release. Degrees per step, step interval, deadzone, axis inversion, the `linkctl` path and an optional device are all configurable. It drives the gimbal with **relative** moves rather than absolute ones. `linkctl status` reports no pan or tilt at all while the camera is idle, and returns before `--force` is even considered, so there is no trustworthy position to aim an absolute target from. Relative steps work whether the camera is idle or streaming, cannot drift out of sync with the hardware, and are clamped by `linkctl` to the device's own range, so holding the stick against a limit is harmless. The applet's pure logic lives in `contents/ui/logic.js` specifically so it can be tested outside Plasma. QML itself is not reachable by a test harness here, but shell quoting, command construction and output parsing are the parts where mistakes would actually bite. ## Testing 89 checks pass across three suites, and `shellcheck` is clean on all three shell scripts: - `node tests/test_joystick_logic.js` adds 36 checks over shell quoting, tick command construction, axis inversion, the per-axis threshold that stops a horizontal push creeping vertically, and the multi-object JSON merge a diagonal tick produces. - `lua tests/test_obs_linkctl.lua` and `lua tests/test_obs_lifecycle.lua` continue to pass unchanged. Each new suite was mutation-tested to confirm it is not passing vacuously: shrinking the per-axis threshold, making the JSON merge replace instead of merge, disabling the quote escaping, and treating `tracking: false` as absent are all caught. The reported fault was reproduced in a throwaway `HOME` by writing the Plasma 5 triplet form, then confirmed that `--list` flags it and that reinstalling repairs it to the bare form. All QML passes `qmllint` with no syntax errors. The KDE and Plasma QML modules are not installable in the test environment, so their imports are unresolvable there and every remaining warning is of that kind. ## Not verified The applet has not been loaded in a running Plasma session, and the `kwriteconfig6` calls were exercised against stubs rather than the real binary. The shortcut fix rests on reading KDE's source and on a reproduction against stubs, which is strong evidence but is not the same as a live session confirming the key now fires. If the applet fails to load, `journalctl --user -b -u plasma-plasmashell` will name the QML error.
dejima-agent added 1 commit 2026-10-07 21:18:17 -07:00
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.
branderson approved these changes 2026-10-07 21:57:40 -07:00
branderson merged commit 7ad1dcf7cd into main 2026-10-07 21:57:44 -07:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: branderson/insta360-link-tools#1