Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for extra mouse buttons #199

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading