Skip to content

Commit

Permalink
support mixing maps of synergy and raw keys (#40)
Browse files Browse the repository at this point in the history
This should fix #35, as Windows seems to be sending identical
buttons for different keys, but distinct synergy identifiers.

Also support setting a raw keycode for idle... which goes here becuase
it will solve the problem of HYPR on uinput triggering the play key.

move debug log to include wlRawKey

update readme
  • Loading branch information
r-c-f authored Jul 7, 2022
1 parent 00bbf62 commit a66452c
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 25 deletions.
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,19 @@ The offset functionality is enabled through `raw-keymap/offset`, though it
can also be disabled for explicit mappings by setting `raw-keymap/offset_on_explicit`
to `false`.

###### Synergy ID keymapping

In some cases (see recent comments on #35) Windows servers are sending
duplicate button values for keys which are clearly different. In these cases
using the synergy key IDs might make sense in an `id-keymap` section:
```
[id-keymap]
57218 = 199
57219 = 200
```
with actual values based on the above process, using the `id` parameter in the
server log instead of `button`.

#### Screensaver

`screensaver/start` should contain a command to be run when the screensaver is
Expand All @@ -247,8 +260,9 @@ it when it is deactivated.

Due to issues with the idle inhibition protocol, idle is actually inhibited by
sending a hopefully-meaningless event to the compositor: if `idle-inhibit/method`
is `key`, the key associated with the xkb-style name in `idle-inhibit/keyname` is
pressed (defaults to `HYPR`). If `idle-inhbibit/method` is `mouse`, then a relative
is `key`, the raw keycode given in `idle-inhibit/keycode` is sent if defined,
falling back on the xkb-style key name in `idle-inhibit/keyname`, which will
default to `HYPR`. If `idle-inhbibit/method` is `mouse`, then a relative
move of 0,0 is sent (this is the default).

The mouse approach prevents any clashes with keys, but will prevent cursor
Expand Down
3 changes: 2 additions & 1 deletion include/uSynergy.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,11 +261,12 @@ This callback is called when a key is pressed or released.
@param cookie Cookie supplied in the Synergy context
@param key Key code of key that was pressed or released
@param id Synergy key ID code of the key that was pressed or released
@param modifiers Status of modifier keys (alt, shift, etc.)
@param down Down or up status, 1 is key is pressed down, 0 if key is released (up)
@param repeat Repeat flag, 1 if the key is down because the key is repeating, 0 if the key is initially pressed by the user
**/
typedef void (*uSynergyKeyboardCallback)(uSynergyCookie cookie, uint16_t key, uint16_t modifiers, bool down, bool repeat);
typedef void (*uSynergyKeyboardCallback)(uSynergyCookie cookie, uint16_t key, uint16_t id, uint16_t modifiers, bool down, bool repeat);



Expand Down
9 changes: 8 additions & 1 deletion include/wayland.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,18 @@ struct wlInput {
/* key state information*/
int *key_press_state;
size_t key_count;
int *id_press_state;
size_t id_count;
// keyboard layout handling
struct xkb_context *xkb_ctx;
struct xkb_keymap *xkb_map;
struct xkb_state *xkb_state;
/* raw keymap -- distinct from xkb */
int *raw_keymap;
/* id-based keymap -- uses synergy abstract keycodes */
int *id_keymap;
/* whether or not a given id entry should be used */
bool *id_keymap_valid;
/* wayland context */
struct wlContext *wl_ctx;
/* actual functions */
Expand Down Expand Up @@ -119,7 +125,8 @@ extern void wlMouseButtonUp(struct wlContext *context, int button);
extern void wlMouseWheel(struct wlContext *context, signed short dx, signed short dy);

/* keyboard-related functions */
extern void wlKey(struct wlContext *context, int key, int state);
extern void wlKeyRaw(struct wlContext *context, int key, int state);
extern void wlKey(struct wlContext *context, int key, int id, int state);
/* release all currently-pressed keys, usually on exiting the screen */
extern void wlKeyReleaseAll(struct wlContext *context);

Expand Down
4 changes: 2 additions & 2 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ static void syn_mouse_move_cb(uSynergyCookie cookie, bool rel, int16_t x, int16_
wlMouseMotion(&wlContext, x, y);
}
}
static void syn_key_cb(uSynergyCookie cookie, uint16_t key, uint16_t mod, bool down, bool repeat)
static void syn_key_cb(uSynergyCookie cookie, uint16_t key, uint16_t id, uint16_t mod, bool down, bool repeat)
{
if (!repeat)
wlKey(&wlContext, key, down);
wlKey(&wlContext, key, id, down);
}
static void syn_clip_cb(uSynergyCookie cookie, enum uSynergyClipboardId id, uint32_t format, const uint8_t *data, uint32_t size)
{
Expand Down
10 changes: 5 additions & 5 deletions src/uSynergy.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,14 +204,14 @@ static void sSendScreensaverCallback(uSynergyContext *context, bool state)
/**
@brief Send keyboard callback when a key has been pressed or released
**/
static void sSendKeyboardCallback(uSynergyContext *context, uint16_t key, uint16_t modifiers, bool down, bool repeat)
static void sSendKeyboardCallback(uSynergyContext *context, uint16_t key, uint16_t id, uint16_t modifiers, bool down, bool repeat)
{
// Skip if no callback is installed
if (context->m_keyboardCallback == 0L)
return;

// Send callback
context->m_keyboardCallback(context->m_cookie, key, modifiers, down, repeat);
context->m_keyboardCallback(context->m_cookie, key, id, modifiers, down, repeat);
}


Expand Down Expand Up @@ -496,7 +496,7 @@ static void sProcessMessage(uSynergyContext *context, struct sspBuf *msg)
if (!(sspNetU16(msg, &id) && sspNetU16(msg, &mod) && sspNetU16(msg, &key))) {
PARSE_ERROR();
}
sSendKeyboardCallback(context, context->m_useRawKeyCodes ? key : id, mod, true, false);
sSendKeyboardCallback(context, context->m_useRawKeyCodes ? key : id, id, mod, true, false);
}
else if (!strcmp(pkt_id, "DKRP"))
{
Expand All @@ -510,7 +510,7 @@ static void sProcessMessage(uSynergyContext *context, struct sspBuf *msg)
sspNetU16(msg, &key))) {
PARSE_ERROR();
}
sSendKeyboardCallback(context, context->m_useRawKeyCodes ? key : id, mod, true, true);
sSendKeyboardCallback(context, context->m_useRawKeyCodes ? key : id, id, mod, true, true);
}
else if (!strcmp(pkt_id, "DKUP"))
{
Expand All @@ -521,7 +521,7 @@ static void sProcessMessage(uSynergyContext *context, struct sspBuf *msg)
if (!(sspNetU16(msg, &id) && sspNetU16(msg, &mod) && sspNetU16(msg, &key))) {
PARSE_ERROR();
}
sSendKeyboardCallback(context, context->m_useRawKeyCodes ? key : id, mod, false, false);
sSendKeyboardCallback(context, context->m_useRawKeyCodes ? key : id, id, mod, false, false);
}
else if (!strcmp(pkt_id, "DGBT"))
{
Expand Down
13 changes: 11 additions & 2 deletions src/wl_idle.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


static xkb_keycode_t idle_key;
int idle_key_raw = -1;
static void on_idle_mouse(void *data, struct org_kde_kwin_idle_timeout *timeout)
{
logDbg("Got idle event, responding with zero mouse move");
Expand All @@ -13,8 +14,13 @@ static void on_idle_key(void *data, struct org_kde_kwin_idle_timeout *timeout)
logDbg("Got idle event, responding with keypress");
struct wlContext *ctx = data;
//Second try at this -- press a key we do not care about
wlKey(ctx, idle_key, true);
wlKey(ctx, idle_key, false);
if (idle_key_raw != -1) {
wlKeyRaw(ctx, idle_key_raw, true);
wlKeyRaw(ctx, idle_key_raw, false);
} else {
wlKey(ctx, idle_key, 0, true);
wlKey(ctx, idle_key, 0, false);
}
}
static void on_resumed(void *data, struct org_kde_kwin_idle_timeout *timeout)
{
Expand Down Expand Up @@ -48,6 +54,9 @@ void wlIdleInhibit(struct wlContext *ctx, bool on)
idle_timeout_listener.idle = on_idle_mouse;
} else if (!strcmp(idle_method, "key")) {
idle_timeout_listener.idle = on_idle_key;
/* first try a raw keycode for idle, because in case
* of uinput xkb map might be rather useless */
idle_key_raw = configTryLong("idle-inhibit/keycode", -1);
idle_keyname = configTryString("idle-inhibit/keyname", "HYPR");
idle_key = xkb_keymap_key_by_name(ctx->input.xkb_map, idle_keyname);
free(idle_keyname);
Expand Down
103 changes: 91 additions & 12 deletions src/wl_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,64 @@ static void load_raw_keymap(struct wlContext *ctx)
strfreev(val);
}

static void load_id_keymap(struct wlContext *ctx)
{
char **key, **val, *endstr;
int i, count,lkey, rkey;
key = NULL;
val = NULL;
if (ctx->input.id_keymap) {
free(ctx->input.id_keymap);
}
/* start with the known synergy maximum */
ctx->input.id_count = 0xF000;
logDbg("max key: %zu", ctx->input.id_count);
if ((count = configReadFullSection("id-keymap", &key, &val)) != -1) {
/* slightly inefficient approach, but it will actually work
* First pass -- just find the *real* maximum id keycode */
for (i = 0; i < count; ++i) {
errno = 0;
lkey = strtol(key[i], &endstr, 0);
if (errno || endstr == key[i])
continue;
if (lkey >= ctx->input.id_count) {
ctx->input.id_count = lkey + 1;
logDbg("max id update: %zu", ctx->input.id_count);

}
}
}
/* initialize everything */
ctx->input.id_keymap = xcalloc(ctx->input.id_count, sizeof(*ctx->input.id_keymap));
/* initialize key state tracking now that the size is known */
if (ctx->input.id_press_state) {
free(ctx->input.id_press_state);
}
ctx->input.id_press_state = xcalloc(ctx->input.id_count, sizeof(*ctx->input.id_press_state));
/* and set everything as invalid initially, to trigger raw key map */
if (ctx->input.id_keymap_valid) {
free(ctx->input.id_keymap_valid);
}
ctx->input.id_keymap_valid = xcalloc(ctx->input.id_count, sizeof(*ctx->input.id_keymap_valid));
/* and second pass -- store any actually mappings, set valid */
for (i = 0; i < count; ++i) {
errno = 0;
lkey = strtol(key[i], &endstr, 0);
if (errno || endstr == key[i])
continue;
errno = 0;
rkey = strtol(val[i], &endstr, 0);
if (errno || endstr == val[i])
continue;
ctx->input.id_keymap[lkey] = rkey;
ctx->input.id_keymap_valid[lkey] = true;
logDbg("set id key map: %d = %d", lkey, ctx->input.id_keymap[lkey]);
}

strfreev(key);
strfreev(val);
}

int wlKeySetConfigLayout(struct wlContext *ctx)
{
int ret = 0;
Expand All @@ -105,22 +163,13 @@ int wlKeySetConfigLayout(struct wlContext *ctx)
local_mod_init(ctx, keymap_str);
ret = !ctx->input.key_map(&ctx->input, keymap_str);
load_raw_keymap(ctx);
load_id_keymap(ctx);
free(keymap_str);
return ret;
}

void wlKey(struct wlContext *ctx, int key, int state)
void wlKeyRaw(struct wlContext *ctx, int key, int state)
{
if (!ctx->input.key_press_state[key] && !state) {
return;
}
if (key >= ctx->input.key_count) {
logWarn("Key %d outside configured keymap, dropping", key);
return;
}
ctx->input.key_press_state[key] += state ? 1 : -1;
key = ctx->input.raw_keymap[key];
logDbg("Keycode: %d, state %d", key, state);
if (key > xkb_keymap_max_keycode(ctx->input.xkb_map)) {
logDbg("keycode greater than xkb maximum, mod not tracked");
} else {
Expand All @@ -131,16 +180,46 @@ void wlKey(struct wlContext *ctx, int key, int state)
xkb_layout_index_t group = xkb_state_serialize_layout(ctx->input.xkb_state, XKB_STATE_LAYOUT_EFFECTIVE);
logDbg("Modifiers: depressed: %x latched: %x locked: %x group: %x", depressed, latched, locked, group);
}
logDbg("Keycode: %d, state %d", key, state);
ctx->input.key(&ctx->input, key, state);
}


void wlKey(struct wlContext *ctx, int key, int id, int state)
{
if ((id < ctx->input.id_count) && ctx->input.id_keymap_valid[id]) {
if (!ctx->input.id_press_state[id] && !state) {
return;
}
ctx->input.id_press_state[id] += state ? 1 : -1;
key = ctx->input.id_keymap[id];
} else {
if (key >= ctx->input.key_count) {
logWarn("Key %d outside configured keymap, dropping", key);
return;
}
if (!ctx->input.key_press_state[key] && !state) {
return;
}
ctx->input.key_press_state[key] += state ? 1 : -1;
key = ctx->input.raw_keymap[key];
}
wlKeyRaw(ctx, key, state);
}

void wlKeyReleaseAll(struct wlContext *ctx)
{
size_t i;
for (i = 0; i < ctx->input.key_count; ++i) {
while (ctx->input.key_press_state[i]) {
logDbg("Release all: key %zd, pressed %d times", i, ctx->input.key_press_state[i]);
wlKey(ctx, i, 0);
wlKey(ctx, i, 0, 0);
}
}
for (i = 0; i < ctx->input.id_count; ++i) {
while (ctx->input.id_press_state[i]) {
logDbg("Release all: id %zd, pressed %d times", i, ctx->input.id_press_state[i]);
wlKey(ctx, 0, i, 0);
}
}
}
Expand Down

0 comments on commit a66452c

Please sign in to comment.