Skip to content

feat: add ping-pong desktop cycling action (macOS only)#195

Open
winniesi wants to merge 1 commit into
TomBadash:masterfrom
winniesi:feature/cycle-desktops
Open

feat: add ping-pong desktop cycling action (macOS only)#195
winniesi wants to merge 1 commit into
TomBadash:masterfrom
winniesi:feature/cycle-desktops

Conversation

@winniesi

@winniesi winniesi commented Jun 1, 2026

Copy link
Copy Markdown

Summary

Adds a new Cycle Desktops action that ping-pong cycles through desktops on macOS: 1→2→3→4→3→2→1→2→3… This is useful when you want to quickly switch back and forth between desktops without reaching the edge and stopping.

The action appears in the Navigation category and can be assigned to any button (mode shift, middle click, side buttons, etc.).

How it works

Desktop detection

Uses two macOS APIs to detect the current state:

  1. CGSGetActiveSpace (private CoreGraphics API) — returns the id64 of the space on the display where the cursor is located.
  2. com.apple.spaces (user defaults) — contains the per-monitor space configuration, including the ordered list of space IDs for each display.

The implementation parses the Spaces = (...) array block for each monitor section using parenthesis-depth matching, and finds the display whose space list contains the current id64. This correctly handles multi-monitor setups where each display has its own set of desktops.

Ping-pong logic

The engine tracks the current direction (right or left) in config.json under settings.desktop_direction:

  • Moving right until reaching the last desktop → reverse direction
  • Moving left until reaching the first desktop → reverse direction
  • Only one desktop → skip (no action)

Platform support

Platform cycle_desktops action Desktop detection
macOS ✅ Added CGSGetActiveSpace + com.apple.spaces
Windows ❌ Not added
Linux ❌ Not added

The macOS space_right / space_left actions already use _post_symbolic_hotkey which triggers the system "Move left/right a space" shortcuts. The cycle_desktops action delegates to these existing actions.

Changes

  • core/key_simulator.py: Add cycle_desktops action definition in the macOS ACTIONS dictionary (Navigation category). Not added to Windows/Linux.
  • core/engine.py: Add _get_macos_desktop_info() static method for desktop detection, and rewrite _cycle_desktops() with ping-pong logic.
  • ui/locale_manager.py: Add Chinese translations (zh_CN: 循环切换桌面, zh_TW: 循環切換桌面).

Testing

  1. Open Mouser and connect a Logitech mouse
  2. Map any button to Cycle Desktops (Navigation category)
  3. Create multiple desktops (Mission Control → +)
  4. Press the mapped button repeatedly
  5. Verify: desktops cycle 1→2→3→…→N→(N-1)→…→1→2→…
  6. Move cursor to a different display and repeat — should cycle that display's desktops

Device info

  • MX Anywhere 3S
  • macOS (multi-monitor setup)

Adds a new 'Cycle Desktops' action that ping-pong cycles through
desktops: 1→2→3→4→3→2→1→2→3...

The action appears in the Navigation category and can be assigned to
any button (mode shift, middle click, side buttons, etc.).

Desktop detection uses CGSGetActiveSpace to get the current space id64,
then parses com.apple.spaces to find which display owns that space.
Only id64 values inside the Spaces array block are counted (excluding
'Current Space' and 'Collapsed Space' entries) to avoid incorrect
desktop counts on multi-monitor setups.

The engine tracks direction state (left/right) in config.json and
reverses at boundaries. Skips when only 1 desktop exists.

Changes:
- core/key_simulator.py: Add cycle_desktops action (macOS only)
- core/engine.py: Add _get_macos_desktop_info() and _cycle_desktops()
- ui/locale_manager.py: Add zh_CN/zh_TW translations
@winniesi winniesi force-pushed the feature/cycle-desktops branch from 6d52e61 to 79f3313 Compare June 1, 2026 08:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant