Skip to content

Commit

Permalink
support for extra mouse buttons
Browse files Browse the repository at this point in the history
  • Loading branch information
brccabral committed Mar 19, 2024
1 parent 040ca1e commit 7eba65d
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 67 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ Makefile.in
/flatpak/.flatpak-builder/
/flatpak/build-dir/
/.cache/
/.vscode/
31 changes: 24 additions & 7 deletions src/callbacks.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,13 +270,15 @@ gboolean on_buttonpress (GtkWidget *win,
gdk_window_set_event_compression(gtk_widget_get_window(data->win), TRUE);
}

/* See GdkModifierType. Am I fixing a Gtk misbehaviour??? */
ev->state |= 1 << (ev->button + 7);
// add new buttons to GromitState
GromitState newState = devdata->state;
newState.buttons |= (ev->button <= 10) ? 1 << (ev->button - 1) : 0;
newState.modifiers = ev->state & 255;


if (ev->state != devdata->state ||
if (!compare_state(devdata->state, newState) ||
devdata->lastslave != gdk_event_get_source_device ((GdkEvent *) ev))
select_tool (data, ev->device, gdk_event_get_source_device ((GdkEvent *) ev), ev->state);
select_tool (data, ev->device, gdk_event_get_source_device ((GdkEvent *) ev), newState);

GromitPaintType type = devdata->cur_context->type;

Expand All @@ -301,7 +303,7 @@ gboolean on_buttonpress (GtkWidget *win,
if(data->maxwidth > devdata->cur_context->maxwidth)
data->maxwidth = devdata->cur_context->maxwidth;

if (ev->button <= 5)
if (ev->button <= 10)
draw_line (data, ev->device, ev->x, ev->y, ev->x, ev->y);

coord_list_prepend (data, ev->device, ev->x, ev->y, data->maxwidth);
Expand All @@ -325,12 +327,22 @@ gboolean on_motion (GtkWidget *win,
if (!devdata->is_grabbed)
return FALSE;

// GdkEventMotion->state has only buttons 1-5, keep 6-10
GromitState newState = devdata->state;
newState.buttons &= 992; // remove old 1-5, keep 6-10
newState.buttons |= (ev->state >> 8) & 1023; // update new 1-5
newState.modifiers = ev->state & 255;

// return if there is no button pressed
if(!newState.buttons)
return TRUE;

if(data->debug)
g_printerr("DEBUG: Device '%s': motion to (x,y)=(%.2f : %.2f)\n", gdk_device_get_name(ev->device), ev->x, ev->y);

if (ev->state != devdata->state ||
if(!compare_state(devdata->state, newState) ||
devdata->lastslave != gdk_event_get_source_device ((GdkEvent *) ev))
select_tool (data, ev->device, gdk_event_get_source_device ((GdkEvent *) ev), ev->state);
select_tool (data, ev->device, gdk_event_get_source_device ((GdkEvent *) ev), newState);

GromitPaintType type = devdata->cur_context->type;

Expand Down Expand Up @@ -455,6 +467,11 @@ gboolean on_buttonrelease (GtkWidget *win,
(ev->y != devdata->lasty))
on_motion(win, (GdkEventMotion *) ev, user_data);

// remove released button bit from GromitState
guint button = 1 << (ev->button - 1);
devdata->state.buttons &= ~button;
devdata->state.modifiers = ev->state & 255;

if (!devdata->is_grabbed)
return FALSE;

Expand Down
50 changes: 27 additions & 23 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,25 @@ static gpointer UNDOKEY_SYMBOL_VALUE = (gpointer) 4;
* Functions for parsing the Configuration-file
*/

static gchar* parse_name (GScanner *scanner)
static gboolean parse_name (GScanner *scanner, GromitLookupKey *key)
{
GTokenType token;

guint buttons = 0;
guint modifier = 0;
guint len = 0;
gchar *name;

token = g_scanner_cur_token(scanner);

if (token != G_TOKEN_STRING)
{
g_scanner_unexp_token (scanner, G_TOKEN_STRING, NULL,
NULL, NULL, "aborting", TRUE);
return NULL;
return 0;
}

len = strlen (scanner->value.v_string);
name = g_strndup (scanner->value.v_string, len + 3);
key->name = g_strndup (scanner->value.v_string, len);

token = g_scanner_get_next_token (scanner);

Expand All @@ -80,17 +79,17 @@ static gchar* parse_name (GScanner *scanner)
{
if (token == G_TOKEN_SYMBOL)
{
if ((intptr_t) scanner->value.v_symbol < 11)
if ((intptr_t) scanner->value.v_symbol <= 10)
buttons |= 1 << ((intptr_t) scanner->value.v_symbol - 1);
else
modifier |= 1 << ((intptr_t) scanner->value.v_symbol - 11);
}
else if (token == G_TOKEN_INT)
{
if (scanner->value.v_int <= 5 && scanner->value.v_int > 0)
if (scanner->value.v_int <= 10 && scanner->value.v_int > 0)
buttons |= 1 << (scanner->value.v_int - 1);
else
g_printerr ("Only Buttons 1-5 are supported!\n");
g_printerr ("Only Buttons 1-10 are supported!\n");
}
else
{
Expand All @@ -102,12 +101,10 @@ static gchar* parse_name (GScanner *scanner)
token = g_scanner_get_next_token (scanner);
}

name [len] = 124;
name [len+1] = buttons + 64;
name [len+2] = modifier + 48;
name [len+3] = 0;
key->state.buttons = buttons;
key->state.modifiers = modifier;

return name;
return 1;
}

gboolean parse_config (GromitData *data)
Expand All @@ -120,7 +117,7 @@ gboolean parse_config (GromitData *data)
gchar *filename;
int file;

gchar *name, *copy;
gboolean parsed;

GromitPaintType type;
GdkRGBA *fg_color=NULL;
Expand Down Expand Up @@ -181,10 +178,15 @@ gboolean parse_config (GromitData *data)
g_scanner_scope_add_symbol (scanner, 1, "BUTTON3", (gpointer) 3);
g_scanner_scope_add_symbol (scanner, 1, "BUTTON4", (gpointer) 4);
g_scanner_scope_add_symbol (scanner, 1, "BUTTON5", (gpointer) 5);
g_scanner_scope_add_symbol (scanner, 1, "BUTTON6", (gpointer) 6);
g_scanner_scope_add_symbol (scanner, 1, "BUTTON7", (gpointer) 7);
g_scanner_scope_add_symbol (scanner, 1, "BUTTON8", (gpointer) 8);
g_scanner_scope_add_symbol (scanner, 1, "BUTTON9", (gpointer) 9);
g_scanner_scope_add_symbol (scanner, 1, "BUTTON10", (gpointer) 10);
g_scanner_scope_add_symbol (scanner, 1, "SHIFT", (gpointer) 11);
g_scanner_scope_add_symbol (scanner, 1, "CONTROL", (gpointer) 12);
g_scanner_scope_add_symbol (scanner, 1, "META", (gpointer) 13);
g_scanner_scope_add_symbol (scanner, 1, "ALT", (gpointer) 13);
g_scanner_scope_add_symbol (scanner, 1, "CONTROL", (gpointer) 13);
g_scanner_scope_add_symbol (scanner, 1, "META", (gpointer) 14);
g_scanner_scope_add_symbol (scanner, 1, "ALT", (gpointer) 14);

g_scanner_scope_add_symbol (scanner, 2, "size", (gpointer) 1);
g_scanner_scope_add_symbol (scanner, 2, "color", (gpointer) 2);
Expand All @@ -206,10 +208,11 @@ gboolean parse_config (GromitData *data)
/*
* New tool definition
*/
GromitLookupKey keyName = {};

name = parse_name (scanner);
parsed = parse_name (scanner, &keyName);

if(!name)
if(!parsed)
goto cleanup;

token = g_scanner_cur_token(scanner);
Expand Down Expand Up @@ -239,11 +242,12 @@ gboolean parse_config (GromitData *data)
}
else if (token == G_TOKEN_STRING)
{
copy = parse_name (scanner);
if(!copy)
GromitLookupKey keyCopy = {};
parsed = parse_name (scanner, &keyCopy);
if(!parsed)
goto cleanup;
token = g_scanner_cur_token(scanner);
context_template = g_hash_table_lookup (data->tool_config, copy);
context_template = g_hash_table_lookup (data->tool_config, key2string(keyCopy));
if (context_template)
{
type = context_template->type;
Expand All @@ -257,7 +261,7 @@ gboolean parse_config (GromitData *data)
else
{
g_printerr ("WARNING: Unable to copy \"%s\": "
"not yet defined!\n", copy);
"not yet defined!\n", key2string(keyCopy));
}
}
else
Expand Down Expand Up @@ -430,7 +434,7 @@ gboolean parse_config (GromitData *data)

context = paint_context_new (data, type, fg_color, width,
arrowsize, arrowtype, minwidth, maxwidth);
g_hash_table_insert (data->tool_config, name, context);
g_hash_table_insert (data->tool_config, key2string(keyName), context);
}
else if (token == G_TOKEN_SYMBOL &&
(scanner->value.v_symbol == HOTKEY_SYMBOL_VALUE ||
Expand Down
84 changes: 50 additions & 34 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,41 +253,30 @@ gint reshape (gpointer user_data)
void select_tool (GromitData *data,
GdkDevice *device,
GdkDevice *slave_device,
guint state)
GromitState state)
{
guint buttons = 0, modifier = 0, slave_len = 0, len = 0, default_len = 0;
guint req_buttons = 0, req_modifier = 0;
guint i, j, success = 0;
GromitPaintContext *context = NULL;
guchar *slave_name;
guchar *name;
guchar *default_name;
GromitLookupKey keySlave = {}, keyName = {}, keyDefault = {};

/* get the data for this device */
GromitDeviceData *devdata = g_hash_table_lookup(data->devdatatable, device);

if (device)
{
slave_len = strlen (gdk_device_get_name(slave_device));
slave_name = (guchar*) g_strndup (gdk_device_get_name(slave_device), slave_len + 3);
keySlave.name = g_strndup (gdk_device_get_name(slave_device), slave_len);
len = strlen (gdk_device_get_name(device));
name = (guchar*) g_strndup (gdk_device_get_name(device), len + 3);
keyName.name = g_strndup (gdk_device_get_name(device), len);
default_len = strlen(DEFAULT_DEVICE_NAME);
default_name = (guchar*) g_strndup (DEFAULT_DEVICE_NAME, default_len + 3);
keyDefault.name = g_strndup (DEFAULT_DEVICE_NAME, default_len);


/* Extract Button/Modifiers from state (see GdkModifierType) */
req_buttons = (state >> 8) & 31;

req_modifier = (state >> 1) & 7;
if (state & GDK_SHIFT_MASK) req_modifier |= 1;

slave_name [slave_len] = 124;
slave_name [slave_len+3] = 0;
name [len] = 124;
name [len+3] = 0;
default_name [default_len] = 124;
default_name [default_len+3] = 0;
req_buttons = state.buttons;
req_modifier = state.modifiers;

/*
Iterate i up until <= req_buttons.
Expand Down Expand Up @@ -316,36 +305,36 @@ void select_tool (GromitData *data,
{
j++;
modifier = req_modifier & ((1 << j)-1);
slave_name [slave_len+1] = buttons + 64;
slave_name [slave_len+2] = modifier + 48;
name [len+1] = buttons + 64;
name [len+2] = modifier + 48;
default_name [default_len+1] = buttons + 64;
default_name [default_len+2] = modifier + 48;
keySlave.state.buttons = buttons;
keySlave.state.modifiers = modifier;
keyName.state.buttons = buttons;
keyName.state.modifiers = modifier;
keyDefault.state.buttons = buttons;
keyDefault.state.modifiers = modifier;

if(data->debug)
g_printerr("DEBUG: select_tool looking up context for '%s' attached to '%s'\n", slave_name, name);
g_printerr("DEBUG: select_tool looking up context for '%s' attached to '%s'\n", key2string(keySlave), key2string(keyName));

context = g_hash_table_lookup (data->tool_config, slave_name);
context = g_hash_table_lookup (data->tool_config, key2string(keySlave));
if(context) {
if(data->debug)
g_printerr("DEBUG: select_tool set context for '%s'\n", slave_name);
g_printerr("DEBUG: select_tool set context for '%s'\n", key2string(keySlave));
devdata->cur_context = context;
success = 1;
}
else /* try master name */
if ((context = g_hash_table_lookup (data->tool_config, name)))
if ((context = g_hash_table_lookup (data->tool_config, key2string(keyName))))
{
if(data->debug)
g_printerr("DEBUG: select_tool set context for '%s'\n", name);
g_printerr("DEBUG: select_tool set context for '%s'\n", key2string(keyName));
devdata->cur_context = context;
success = 1;
}
else /* try default_name */
if((context = g_hash_table_lookup (data->tool_config, default_name)))
if((context = g_hash_table_lookup (data->tool_config, key2string(keyDefault))))
{
if(data->debug)
g_printerr("DEBUG: select_tool set default context '%s' for '%s'\n", default_name, name);
g_printerr("DEBUG: select_tool set default context '%s' for '%s'\n", key2string(keyDefault), key2string(keyName));
devdata->cur_context = context;
success = 1;
}
Expand All @@ -363,11 +352,9 @@ void select_tool (GromitData *data,
devdata->cur_context = data->default_pen;

if(data->debug)
g_printerr("DEBUG: select_tool set fallback context for '%s'\n", name);
g_printerr("DEBUG: select_tool set fallback context for '%s'\n", key2string(keyName));
}

g_free (name);
g_free (default_name);
}
else
g_printerr ("ERROR: select_tool attempted to select nonexistent device!\n");
Expand Down Expand Up @@ -1189,3 +1176,32 @@ void indicate_active(GromitData *data, gboolean YESNO)
else
app_indicator_set_icon(data->trayicon, "net.christianbeier.Gromit-MPX");
}

gboolean compare_state(GromitState lhs, GromitState rhs)
{
return lhs.buttons == rhs.buttons &&
lhs.modifiers == rhs.modifiers;
}

gchar *key2string(GromitLookupKey key)
{
guint len = 0;
gchar *result;

len = strlen(key.name);
result = g_strndup(key.name, len + 4);

result[len] = 124;

// to identify buttons 1-10 we need two bytes (two char)
guint buttons = key.state.buttons;
gchar buttons_low = key.state.buttons & 255; // 1-8
gchar buttons_high = key.state.buttons >> 8 & 255; // 9-10

result[len + 1] = buttons_high + 48;
result[len + 2] = buttons_low + 48;
result[len + 3] = key.state.modifiers + 48;
result[len + 4] = 0;

return result;
}
Loading

0 comments on commit 7eba65d

Please sign in to comment.