Skip to content
 
 

Repository files navigation

logimap

logimap Version 0.4.0

Per-application profile manager for the Logitech MX Creative Keypad on Linux.

Switch what the keypad's 9 LCD keys display and which keyboard shortcuts they fire, automatically, based on the application currently focused on your desktop. Author profiles in a small Tk editor; a background daemon handles the rest.

logimap-demo-reduced-size.mp4

Disclaimer: This is not an official Logitech™ application. This project is not affiliated with, endorsed by, or sponsored by Logitech.

Note

This is the NPPprojects community fork of abishekmuthian/logimap, focused on native Hyprland support while retaining KDE Plasma support and upstream attribution.

Status / Scope

Need Supported
Hardware Logitech MX Creative Keypad (USB 046d:c354)
OS Linux (kernel ≥ 5.10 for uinput)
Desktop KDE Plasma 6 or Hyprland on Wayland
Keystroke injection Built-in /dev/uinput (no third-party daemon)

The separate MX Dialpad is not supported yet.

Features

  • Automatically selects a profile by focused-window class and optional title regex on KDE Plasma 6 or Hyprland.
  • Fills all nine MX Creative Keypad LCD keys with generated text labels using per-profile foreground and background colors.
  • Sends single-chord and multi-chord keyboard shortcuts through /dev/uinput.
  • Dispatches numbered workspaces directly through Hyprland IPC. Workspace profiles can show a fixed range or a compact, live list containing only occupied workspaces, with the active workspace highlighted.
  • Includes a Tk profile editor and an on-device preview action.
  • Hot-reloads profiles.json and automatically reconnects after keypad or compositor restarts.
  • Can run as a systemd --user service and writes rotating diagnostic logs.

Current keypad limits: labels are generated from text rather than custom images. General shortcut profiles have one page; arrow pagination applies to fixed or occupied Hyprland workspace layouts.

Quick start

git clone --recursive https://github.com/NPPprojects/logimap-hyprland.git
cd logimap-hyprland
./install.sh
logimap install-kwin   # KDE only; one-time per Plasma session
logimap gui            # author your first profile
logimap run            # auto-detect KWin or Hyprland

If you're adding yourself to the input group for the first time you'll need to log out and back in once before the daemon can write /dev/uinput across reboots. install.sh will tell you.

What install.sh does

It's a plain bash script, so read it before running. In order, it:

  1. Refuses to proceed unless you're on Linux with KDE Plasma 6 Wayland or Hyprland (pass --force to override).
  2. Detects your distro (Fedora, Debian/Ubuntu, or Arch) and installs the build/runtime deps (cmake, a C++ compiler, Python, Tk, Pillow, dbus-next, pybind11, DejaVu Sans, git, acl).
  3. Creates ~/.local/share/logimap/venv and installs the Python runtime dependencies.
  4. git submodule update --init, which pulls the project's LogiLinux core compatibility fork and the upstream logilinux-sdk/.
  5. Builds the C++ core (logilinux/) with CMake.
  6. Symlinks the SDK's empty logilinux-driver stub to ../logilinux so the pybind11 build resolves headers. It then pip-installs pybind11, logilinux-sdk (editable), and logimap (editable). The venv uses --system-site-packages so it inherits Tk and Pillow-tk from the distro.
  7. Drops two udev rules into /etc/udev/rules.d/:
    • 99-logitech-creator.rules: GROUP=input MODE=0660 for HID PID 046d:c354 (MX Creative Keypad).
    • 99-logimap-uinput.rules: GROUP=input MODE=0660 for /dev/uinput. It also loads the uinput kernel module now and at boot through /etc/modules-load.d/logimap-uinput.conf.
  8. Adds your user to the input group if you're not already a member, plus a temporary ACL bridge for the current boot.
  9. Drops a launcher at ~/.local/bin/logimap and a .desktop entry under ~/.local/share/applications/.
  10. Drops a systemd --user unit at ~/.config/systemd/user/logimap.service (installed but not enabled; you opt in).

You'll be prompted for sudo at the udev / usermod steps.

Authoring your first profile

  1. logimap gui opens the Tk editor.

  2. Click Add, pick a profile name.

  3. In the Match section, set wm_class to the focused window class reported by your compositor. The easy way to discover this: with logimap run active, alt-tab to the app you care about and tail the log:

    tail -F ~/.local/state/logimap/logimap.log | grep 'focus ->'

    Copy the logged wm_class string verbatim. Plasma often uses a reverse-DNS class such as org.mozilla.firefox; Hyprland commonly reports firefox.

  4. Click a key in the 3×3 grid (e.g. GRID_0).

  5. Type a Title (what the LCD will show) and assign a shortcut. Two ways:

    • Capture: click the button, press the chord (e.g. Ctrl+T). Works for app-level shortcuts the compositor doesn't intercept. Capture records a single chord — for multi-chord shortcuts like tmux prefixes, type directly (see below).
    • Type directly into the Shortcut field: required for chords KWin grabs globally before they reach the editor (e.g. Meta+L for lock screen, Meta+D for show desktop). Use the canonical +-joined form: logo+l, ctrl+shift+t, alt+f4. Modifier names: ctrl, shift, alt, logo (also accepts meta / super / control). The daemon synthesizes these via uinput, and KWin's global-shortcut handler honors them on Plasma 6.
    • Multi-chord shortcuts (tmux, screen, etc.): separate chords with a comma. For example, tmux's vertical split (Ctrl+B then ") is entered as ctrl+b," (the " auto-expands to shift+'). The daemon injects each chord with a 50 ms pause between them so the receiving application can distinguish the prefix from the action. Other examples:
      • ctrl+b,% — tmux horizontal split
      • ctrl+b,o — tmux switch pane
      • ctrl+b,x — tmux close pane
    • Fixed Hyprland workspaces: leave Workspace layout set to fixed and enter workspace:1 through workspace:9. These actions dispatch directly through Hyprland IPC instead of synthesizing a modifier chord. Set Last workspace on the profile (for example, 15) to enable the hardware arrow buttons. Right shows workspaces 10–15; left returns to 1–9.
    • Occupied Hyprland workspaces: set Workspace layout to occupied. All nine keys are generated from live Hyprland state, sorted and packed without gaps. Empty and special workspaces are hidden, and the active occupied workspace is highlighted. Last workspace still limits the highest workspace shown. Configured per-key bindings are retained but ignored while this mode is active.
  6. Save. The daemon hot-reloads the config file (mtime watcher; SIGHUP also works).

Profile JSON

~/.config/logimap/profiles.json:

{
  "version": 1,
  "default_profile": "default",
  "profiles": {
    "firefox": {
      "match": {"wm_class": "org.mozilla.firefox", "title_regex": null},
      "bg_color": [30, 30, 30],
      "fg_color": [255, 255, 255],
      "keys": {
        "GRID_0": {"title": "New Tab",    "shortcut": "ctrl+t"},
        "GRID_1": {"title": "Close Tab",  "shortcut": "ctrl+w"},
        "GRID_2": {"title": "Reopen Tab", "shortcut": "ctrl+shift+t"},
        "GRID_3": {"title": "Split V",    "shortcut": "ctrl+b,\""},
        "GRID_4": {"title": "Split H",    "shortcut": "ctrl+b,%"}
      }
    },
    "default": {
      "match": {"wm_class": "*", "title_regex": null},
      "workspace_limit": 15,
      "workspace_mode": "occupied",
      "keys": {}
    }
  }
}

Layout:

GRID_0 GRID_1 GRID_2
GRID_3 GRID_4 GRID_5
GRID_6 GRID_7 GRID_8

Profile selection: first profile whose wm_class matches (with title_regex checked if set), otherwise default_profile.

Auto-start at login

Start the installed service immediately:

systemctl --user start logimap
journalctl --user -u logimap -f         # follow the daemon's logs

On KDE, enable it for future graphical sessions:

systemctl --user enable logimap

For a Hyprland session not managed by UWSM, add this to hyprland.conf instead:

exec-once = systemctl --user start logimap.service

For a Lua-based Hyprland configuration, put the equivalent command in its startup hook, for example hl.exec_cmd("systemctl --user start logimap.service").

UWSM-managed Hyprland sessions start graphical-session.target, so systemctl --user enable logimap is sufficient there.

Architecture

KWin JS ──D-Bus───────┐
                      ├──▶ daemon ──JPEG bytes──▶ MX Keypad
Hyprland ──Unix IPC───┘       ▲                       │
                              └──── ButtonEvent ──────┘
                              │
                              └─ /dev/uinput EV_KEY ─▶ focused app
  • logimap/focus/kwin_dbus.py owns org.logimap.Focus1 on the session bus. kwin_script/logimap-focus.js subscribes to workspace.windowActivated and pings us via callDBus.
  • logimap/focus/hyprland_ipc.py listens to Hyprland's event socket and reads structured activewindow data from its request socket. It reconnects and rediscovers the compositor instance after a Hyprland restart. workspace:N actions use the request socket's workspace dispatcher directly.
  • logimap/device.py wraps logilinux.MXKeypadDevice with auto-reconnect.
  • logimap/inject/uinput.py opens /dev/uinput, registers a virtual keyboard, writes EV_KEY events for the chord. wtype/ydotool/xdotool are auto-probed fallbacks (rarely needed on KWin 6; see Troubleshooting).
  • logimap/render.py produces a 118×118 JPEG from a title string to fill the LCD region programmed by MXKeypadDevice.set_key_image().

Troubleshooting

Logs are in ~/.local/state/logimap/logimap.log (rotating, 1 MB × 3 backups). Pass -v for DEBUG.

tail -F ~/.local/state/logimap/logimap.log

# Verify D-Bus owner is the live daemon:
busctl --user status org.logimap.Focus1
Symptom First thing to check
LCDs don't change on alt-tab grep 'focus ->' ~/.local/state/logimap/logimap.log. On KDE, run logimap install-kwin; on Hyprland, check for connected to Hyprland IPC in the log.
Wrong compositor was selected Run logimap run --focus-source hyprland or logimap run --focus-source kwin. LOGIMAP_FOCUS_SOURCE provides the same override for services.
Key press does nothing Look for press GRID_N has no binding in profile '…'. The resolved profile name shows whether your wm_class matched. Use the exact class logged by your compositor; Plasma often uses reverse-DNS names while Hyprland commonly uses names such as firefox.
Capture button doesn't react to Meta+L, Meta+D, etc. KWin grabs those globally before the editor sees them. Type the canonical form (e.g. logo+l) directly into the Shortcut field instead.
No usable keystroke injector found Your user can't open /dev/uinput. Re-login after install.sh (the input group needs a fresh session) or sudo setfacl -m u:$USER:rw /dev/uinput for a one-shot.
Daemon falls back to xdotool on Arch Check lsmod | grep uinput and /dev/uinput. Re-run ./install.sh; it now loads uinput and installs a persistent modules-load entry. Direct workspace:N actions do not depend on an injector.
wtype failed for ... exit 1 KWin 6 hides zwp_virtual_keyboard_v1 from non-IME clients. The probe should have skipped wtype and selected uinput; check the startup log line using built-in uinput injector.
MX Keypad not found lsusb | grep 046d:c354 should show the device. Confirm the matching /dev/hidraw* node belongs to the input group and your user is a member; try sudo udevadm trigger --subsystem-match=hidraw and replug.
RequestNameReply.IN_QUEUE in startup log A second daemon is fighting for the D-Bus name. pkill -f "logimap run" and restart.
ModuleNotFoundError: _logilinux_native The SDK was built against a different Python version than the one running the daemon. Re-run ./install.sh; it picks an interpreter that matches the compiled .so.
systemd unit fails to start journalctl --user -u logimap -n 50 and inspect. Most often: not in input group yet (re-login), or ~/.local/bin not on the systemd user PATH.
Service does not start with Hyprland Non-UWSM Hyprland does not start graphical-session.target; add exec-once = systemctl --user start logimap.service to hyprland.conf.

Development

VENV="$HOME/.local/share/logimap/venv"
"$VENV/bin/python" -m pip install -e ".[dev]"
PYTHONPATH="$PWD:$PWD/logilinux-sdk" \
LD_LIBRARY_PATH="$PWD/logilinux/build/lib" \
"$VENV/bin/python" -m pytest tests/ -q

The test suite covers the shortcut parser, config round-trip, profile resolver, workspace paging, JPEG rendering, Hyprland IPC parsing/selection, and uinput event-sequence logic. Physical keypad and full compositor behavior still require manual integration testing.

Contributions to Hyprland support are welcome through NPPprojects/logimap-hyprland. Changes that are also useful upstream should be proposed to abishekmuthian/logimap.

License

logimap is MIT-licensed. See LICENSE.

Roadmap

  1. General pagination: Extend arrow paging beyond numbered workspace actions to arbitrary multi-page shortcut bindings.

Credits

Built on top of the LogiLinux project:

The core compatibility fork at abishekmuthian/logilinux and the upstream logilinux-sdk are pulled in as git submodules.

About

Logitech Creative Console mapping software for Linux

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages