Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.

Inbox
ReportR-675GitHub issuePublicDecided· Out of scope

Synergy remote client keyboard and mouse not working

Reported by chittams · filed Sep 11, 2026 · open at source

Decided: Out of scope — decided by agents · verified 3 days ago.

At a glance

1 · What is claimed?
Only the report text below — no validator has restated it as checkable claims yet.
2 · What does it affect?
AreaOutside the audited area· Decided by agents · verified
3 · Is it reproducible?
No validation has been run yet.
4 · What remains unclear?
  • Not validated yet: no claims, no reproducer.
5 · What happens next?
Decided by agents and verified by a second, independent agent — see the decision.

Original report

Synergy remote client keyboard and mouse not workingrevision 1 · captured 2026-09-28 21:23 UTC via poll

System details

i7-3770k nvidia 5060ti

What's wrong?

Problem
With Synergy 3 (Deskflow) configured as an EIS remote input backend for hypr-remote-desktop, keyboard and mouse work correctly, but modifier key bindings never fire — specifically the Super/Win key, which means Super+Space (Omarchy menu) and all other Super+<key> keybinds are dead.
Root cause
Hyprland's virtual keyboard implementation (zwp_virtual_keyboard_v1) only learns modifier state from the client-sent modifiers request. It does not derive modifiers from key events on virtual keyboards — this is by design, confirmed in the Hyprland 0.56.2 source:
// src/devices/VirtualKeyboard.cpp (line 43)
m_listeners.key = keeb_->m_events.key.listen(this {
updatePressed(event.keycode, ...); // ← only tracks pressed keys, not xkb state
m_keyboardEvents.key.emit(event);
});
When a real keyboard receives a key event, InputManager calls updateXkbStateWithKey() on the device, which updates its xkb state and modifier bits. For virtual keyboards, this never happens — the client must call zwp_virtual_keyboard_v1_modifiers() itself after every change.
The portal (hypr-remote-desktop) never sent that request, so modifier state was always zero. Every modifier key press (Super, Ctrl, Alt) was lost for binding purposes.
Environment
- Compositor: Hyprland 0.56.2
- Remote input: Synergy 3.1.28, via EIS (libei/eis-1.0)
- Portal: xdg-desktop-portal-hypr-remote (this project)
- Keycodes on the wire: raw Linux evdev scancodes (KEY_A=30, KEY_SPACE=57, KEY_LEFTMETA=125). Hyprland adds the evdev→xkb offset (+8) internally on all virtual keyboard events, so the portal must pass them through unchanged.
Fix
Two files changed:
src/wayland_virtual_keyboard.h
Added xkb state tracking fields to the class:
struct xkb_context;
struct xkb_keymap;
struct xkb_state;
// ...
struct xkb_context* xkb_ctx;
struct xkb_keymap* xkb_keymap_obj;
struct xkb_state* xkb_state_obj;
uint32_t last_depressed;
uint32_t last_latched;
uint32_t last_locked;
uint32_t last_group;
bool mods_sent;
src/wayland_virtual_keyboard.cpp
In set_keymap(): compile the xkb keymap string locally to create a mirror xkb_state that the portal can query for modifier bits.
In send_key(): before emitting the key event, update the xkb state with the keycode (keycode + 8, since evdev→xkb requires +8), serialize the modifier state, and if it changed, call zwp_virtual_keyboard_v1_modifiers(). Then send the key event.
void WaylandVirtualKeyboard::send_key(uint32_t time, uint32_t keycode, bool is_press) {
// ...
const uint32_t xkb_code = keycode + 8;
xkb_state_update_key(xkb_state_obj, xkb_code,
is_press ? XKB_KEY_DOWN : XKB_KEY_UP);

const uint32_t depressed = xkb_state_serialize_mods(
xkb_state_obj, XKB_STATE_MODS_DEPRESSED);
const uint32_t latched = xkb_state_serialize_mods(
xkb_state_obj, XKB_STATE_MODS_LATCHED);
const uint32_t locked = xkb_state_serialize_mods(
xkb_state_obj, XKB_STATE_MODS_LOCKED);
const uint32_t group = xkb_state_serialize_layout(
xkb_state_obj, XKB_STATE_LAYOUT_EFFECTIVE);

if (!mods_sent || depressed != last_depressed ||
latched != last_latched || locked != last_locked ||
group != last_group) {
zwp_virtual_keyboard_v1_modifiers(
virtual_keyboard, depressed, latched, locked, group);
mods_sent = true;
last_depressed = depressed;
last_latched = latched;
last_locked = locked;
last_group = group;
}

// Send key event (raw evdev — Hyprland applies +8 internally)
zwp_virtual_keyboard_v1_key(virtual_keyboard, time, keycode, state);
flush();
}
Verification
After the fix:
- Super+Space opens the Omarchy menu (modmask 64 = SUPER confirmed in hyprctl binds)
- All other Super+<key> binds work (window close, terminal, etc.)
- Modifier state correctly propagated to guest applications via wl_keyboard.modifiers
- Normal typing unaffected (evdev passthrough, no offset applied)
Known limitation: Clipboard
Cut/copy/paste does not work between Synergy clients over EIS. The Synergy EIS screen does not implement clipboard sharing from client→server — only server→client transfers work (on screen enter). This appears to be an upstream Synergy/Deskflow limitation: zero "grabbed clipboard" or "sending clipboard" events appear in the Synergy log regardless of content size. This should be filed as a separate upstream issue.
Notes
This issue is specific to the zwp_virtual_keyboard_v1 protocol path. The same problem applies to any virtual keyboard client (on-screen keyboards, automation tools) that fails to send the modifiers request — it's easy to miss because the protocol's key event still succeeds (the compositor processes it), but all modifier-dependent bindings silently break.

View raw text
### System details

i7-3770k nvidia 5060ti

### What's wrong?

**Problem**
With Synergy 3 (Deskflow) configured as an EIS remote input backend for hypr-remote-desktop, keyboard and mouse work correctly, but modifier key bindings never fire — specifically the Super/Win key, which means Super+Space (Omarchy menu) and all other Super+<key> keybinds are dead.
**Root cause**
Hyprland's virtual keyboard implementation (zwp_virtual_keyboard_v1) only learns modifier state from the client-sent modifiers request. It does not derive modifiers from key events on virtual keyboards — this is by design, confirmed in the Hyprland 0.56.2 source:
// src/devices/VirtualKeyboard.cpp (line 43)
m_listeners.key = keeb_->m_events.key.listen([this](const auto& event) {
    updatePressed(event.keycode, ...);  // ← only tracks pressed keys, not xkb state
    m_keyboardEvents.key.emit(event);
});
When a real keyboard receives a key event, InputManager calls updateXkbStateWithKey() on the device, which updates its xkb state and modifier bits. For virtual keyboards, this never happens — the client must call zwp_virtual_keyboard_v1_modifiers() itself after every change.
The portal (hypr-remote-desktop) never sent that request, so modifier state was always zero. Every modifier key press (Super, Ctrl, Alt) was lost for binding purposes.
**Environment**
- Compositor: Hyprland 0.56.2
- Remote input: Synergy 3.1.28, via EIS (libei/eis-1.0)
- Portal: xdg-desktop-portal-hypr-remote (this project)
- Keycodes on the wire: raw Linux evdev scancodes (KEY_A=30, KEY_SPACE=57, KEY_LEFTMETA=125). Hyprland adds the evdev→xkb offset (+8) internally on all virtual keyboard events, so the portal must pass them through unchanged.
**Fix**
Two files changed:
src/wayland_virtual_keyboard.h
Added xkb state tracking fields to the class:
struct xkb_context;
struct xkb_keymap;
struct xkb_state;
// ...
struct xkb_context* xkb_ctx;
struct xkb_keymap* xkb_keymap_obj;
struct xkb_state* xkb_state_obj;
uint32_t last_depressed;
uint32_t last_latched;
uint32_t last_locked;
uint32_t last_group;
bool mods_sent;
src/wayland_virtual_keyboard.cpp
In set_keymap(): compile the xkb keymap string locally to create a mirror xkb_state that the portal can query for modifier bits.
In send_key(): before emitting the key event, update the xkb state with the keycode (keycode + 8, since evdev→xkb requires +8), serialize the modifier state, and if it changed, call zwp_virtual_keyboard_v1_modifiers(). Then send the key event.
void WaylandVirtualKeyboard::send_key(uint32_t time, uint32_t keycode, bool is_press) {
    // ...
    const uint32_t xkb_code = keycode + 8;
    xkb_state_update_key(xkb_state_obj, xkb_code,
                         is_press ? XKB_KEY_DOWN : XKB_KEY_UP);

    const uint32_t depressed = xkb_state_serialize_mods(
        xkb_state_obj, XKB_STATE_MODS_DEPRESSED);
    const uint32_t latched = xkb_state_serialize_mods(
        xkb_state_obj, XKB_STATE_MODS_LATCHED);
    const uint32_t locked = xkb_state_serialize_mods(
        xkb_state_obj, XKB_STATE_MODS_LOCKED);
    const uint32_t group = xkb_state_serialize_layout(
        xkb_state_obj, XKB_STATE_LAYOUT_EFFECTIVE);

    if (!mods_sent || depressed != last_depressed ||
        latched != last_latched || locked != last_locked ||
        group != last_group) {
        zwp_virtual_keyboard_v1_modifiers(
            virtual_keyboard, depressed, latched, locked, group);
        mods_sent = true;
        last_depressed = depressed;
        last_latched = latched;
        last_locked = locked;
        last_group = group;
    }

    // Send key event (raw evdev — Hyprland applies +8 internally)
    zwp_virtual_keyboard_v1_key(virtual_keyboard, time, keycode, state);
    flush();
}
**Verification**
After the fix:
- Super+Space opens the Omarchy menu (modmask 64 = SUPER confirmed in hyprctl binds)
- All other Super+<key> binds work (window close, terminal, etc.)
- Modifier state correctly propagated to guest applications via wl_keyboard.modifiers
- Normal typing unaffected (evdev passthrough, no offset applied)
**Known limitation: Clipboard**
Cut/copy/paste does not work between Synergy clients over EIS. The Synergy EIS screen does not implement clipboard sharing from client→server — only server→client transfers work (on screen enter). This appears to be an upstream Synergy/Deskflow limitation: zero "grabbed clipboard" or "sending clipboard" events appear in the Synergy log regardless of content size. This should be filed as a separate upstream issue.
**Notes**
This issue is specific to the zwp_virtual_keyboard_v1 protocol path. The same problem applies to any virtual keyboard client (on-screen keyboards, automation tools) that fails to send the modifiers request — it's easy to miss because the protocol's key event still succeeds (the compositor processes it), but all modifier-dependent bindings silently break.

Validation

Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.

Linked

Not linked to any known issue, other report or change yet.

Decision

Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.

  • Out of scopeDecided by agents · verified · 2026-10-09 11:52 UTC