From 710292754835660ad57f2904db65fc7742a08331 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 10 Dec 2018 14:25:07 +0100 Subject: [PATCH] X11 extended button remapping support. Up until now X11 mouse button remapping was only possible for the default buttons 1 to 3. With this pull any X11 mouse button can be mapped to any RDP mouse event and all X11 remappings are respected. --- client/X11/xf_client.c | 76 ++++++++++++++++++------- client/X11/xf_event.c | 149 +++++++++++-------------------------------------- client/X11/xf_event.h | 8 ++- client/X11/xf_input.c | 8 +-- client/X11/xfreerdp.h | 15 ++--- 5 files changed, 105 insertions(+), 151 deletions(-) diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 455f41a..a7d0850 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -1036,26 +1036,55 @@ static void xf_get_x11_button_map(xfContext* xfc, unsigned char* x11_map) /* Assignment of physical (not logical) mouse buttons to wire flags. */ /* Notice that the middle button is 2 in X11, but 3 in RDP. */ -static const int xf_button_flags[NUM_BUTTONS_MAPPED] = +static const button_map xf_button_flags[NUM_BUTTONS_MAPPED] = { - PTR_FLAGS_BUTTON1, - PTR_FLAGS_BUTTON3, - PTR_FLAGS_BUTTON2 + {Button1, PTR_FLAGS_BUTTON1}, + {Button2, PTR_FLAGS_BUTTON3}, + {Button3, PTR_FLAGS_BUTTON2}, + {Button4, PTR_FLAGS_WHEEL | 0x78}, + {Button5, PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x78}, + {6, PTR_FLAGS_HWHEEL | 0x78}, + {7, PTR_FLAGS_HWHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x78}, + {8, PTR_XFLAGS_BUTTON1}, + {9, PTR_XFLAGS_BUTTON2}, + {97, PTR_XFLAGS_BUTTON1}, + {112, PTR_XFLAGS_BUTTON2} }; +static UINT16 get_flags_for_button(int button) +{ + size_t x; + + for (x = 0; x < ARRAYSIZE(xf_button_flags); x++) + { + const button_map* map = &xf_button_flags[x]; + + if (map->button == button) + return map->flags; + } + + return 0; +} + static void xf_button_map_init(xfContext* xfc) { + size_t pos = 0; /* loop counter for array initialization */ - int physical; - int logical; + size_t physical; /* logical mouse button which is used for each physical mouse */ /* button (indexed from zero). This is the default map. */ - unsigned char x11_map[NUM_BUTTONS_MAPPED] = - { - Button1, - Button2, - Button3 - }; + unsigned char x11_map[112] = { 0 }; + x11_map[0] = Button1; + x11_map[1] = Button2; + x11_map[2] = Button3; + x11_map[3] = Button4; + x11_map[4] = Button5; + x11_map[5] = 6; + x11_map[6] = 7; + x11_map[7] = 8; + x11_map[8] = 9; + x11_map[96] = 97; + x11_map[111] = 112; /* query system for actual remapping */ if (!xfc->context.settings->UnmapButtons) @@ -1066,18 +1095,23 @@ static void xf_button_map_init(xfContext* xfc) /* iterate over all (mapped) physical buttons; for each of them */ /* find the logical button in X11, and assign to this the */ /* appropriate value to send over the RDP wire. */ - for (physical = 0; physical < NUM_BUTTONS_MAPPED; ++physical) + for (physical = 0; physical < ARRAYSIZE(x11_map); ++physical) { - logical = x11_map[physical]; + const unsigned char logical = x11_map[physical]; + const UINT16 flags = get_flags_for_button(logical); - if (Button1 <= logical && logical <= Button3) - { - xfc->button_map[logical - BUTTON_BASE] = xf_button_flags[physical]; - } - else + if ((logical != 0) && (flags != 0)) { - WLog_ERR(TAG, "Mouse physical button %d is mapped to logical button %d", - physical, logical); + if (pos >= NUM_BUTTONS_MAPPED) + { + WLog_ERR(TAG, "Failed to map mouse button to RDP button, no space"); + } + else + { + button_map* map = &xfc->button_map[pos++]; + map->button = physical + Button1; + map->flags = get_flags_for_button(logical); + } } } } diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index c900e62..d528790 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -371,70 +371,50 @@ static BOOL xf_event_MotionNotify(xfContext* xfc, XEvent* event, BOOL app) return xf_generic_MotionNotify(xfc, event->xmotion.x, event->xmotion.y, event->xmotion.state, event->xmotion.window, app); } -BOOL xf_generic_ButtonPress(xfContext* xfc, int x, int y, int button, - Window window, BOOL app) + +BOOL xf_generic_ButtonEvent(xfContext* xfc, int x, int y, int button, + Window window, BOOL app, BOOL down) { - int flags; - BOOL wheel; - BOOL extended; + UINT16 flags = 0; rdpInput* input; Window childWindow; - wheel = FALSE; - extended = FALSE; - input = xfc->context.input; + size_t i; - switch (button) + for (i = 0; i < ARRAYSIZE(xfc->button_map); i++) { - case Button1: - case Button2: - case Button3: - flags = PTR_FLAGS_DOWN | xfc->button_map[button - BUTTON_BASE]; - break; + const button_map* cur = &xfc->button_map[i]; - case 4: - wheel = TRUE; - flags = PTR_FLAGS_WHEEL | 0x0078; + if (cur->button == button) + { + flags = cur->flags; break; + } + } - case 5: - wheel = TRUE; - flags = PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0078; - break; + input = xfc->context.input; - case 8: /* back */ - case 97: /* Xming */ - extended = TRUE; - flags = PTR_XFLAGS_DOWN | PTR_XFLAGS_BUTTON1; - break; + if (flags != 0) + { + BOOL extended = FALSE; - case 9: /* forward */ - case 112: /* Xming */ + if (flags & (PTR_XFLAGS_BUTTON1 | PTR_XFLAGS_BUTTON1)) + { extended = TRUE; - flags = PTR_XFLAGS_DOWN | PTR_XFLAGS_BUTTON2; - break; - - case 6: /* wheel left */ - wheel = TRUE; - flags = PTR_FLAGS_HWHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0078; - break; - case 7: /* wheel right */ - wheel = TRUE; - flags = PTR_FLAGS_HWHEEL | 0x0078; - break; + if (down) + flags |= PTR_XFLAGS_DOWN; + } - default: - x = 0; - y = 0; - flags = 0; - break; - } + if (flags & (PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 | PTR_FLAGS_BUTTON3)) + { + if (down) + flags |= PTR_FLAGS_DOWN; + } - if (flags != 0) - { - if (wheel) + if (flags & (PTR_FLAGS_WHEEL | PTR_FLAGS_HWHEEL)) { - freerdp_input_send_mouse_event(input, flags, 0, 0); + if (down) + freerdp_input_send_mouse_event(input, flags, 0, 0); } else { @@ -466,80 +446,17 @@ static BOOL xf_event_ButtonPress(xfContext* xfc, XEvent* event, BOOL app) if (xfc->use_xinput) return TRUE; - return xf_generic_ButtonPress(xfc, event->xbutton.x, event->xbutton.y, - event->xbutton.button, event->xbutton.window, app); + return xf_generic_ButtonEvent(xfc, event->xbutton.x, event->xbutton.y, + event->xbutton.button, event->xbutton.window, app, TRUE); } -BOOL xf_generic_ButtonRelease(xfContext* xfc, int x, int y, int button, - Window window, BOOL app) -{ - int flags = 0; - BOOL extended = FALSE; - rdpInput* input; - Window childWindow; - - if (!xfc || !xfc->context.input) - return FALSE; - input = xfc->context.input; - - switch (button) - { - case Button1: - case Button2: - case Button3: - flags = xfc->button_map[button - BUTTON_BASE]; - break; - - case 6: - case 8: - case 97: - extended = TRUE; - flags = PTR_XFLAGS_BUTTON1; - break; - - case 7: - case 9: - case 112: - extended = TRUE; - flags = PTR_XFLAGS_BUTTON2; - break; - - default: - flags = 0; - break; - } - - if (flags != 0) - { - if (app) - { - /* make sure window exists */ - if (!xf_AppWindowFromX11Window(xfc, window)) - return TRUE; - - /* Translate to desktop coordinates */ - XTranslateCoordinates(xfc->display, window, - RootWindowOfScreen(xfc->screen), - x, y, &x, &y, &childWindow); - } - - xf_event_adjust_coordinates(xfc, &x, &y); - - if (extended) - freerdp_input_send_extended_mouse_event(input, flags, x, y); - else - freerdp_input_send_mouse_event(input, flags, x, y); - } - - return TRUE; -} static BOOL xf_event_ButtonRelease(xfContext* xfc, XEvent* event, BOOL app) { if (xfc->use_xinput) return TRUE; - return xf_generic_ButtonRelease(xfc, event->xbutton.x, event->xbutton.y, - event->xbutton.button, event->xbutton.window, app); + return xf_generic_ButtonEvent(xfc, event->xbutton.x, event->xbutton.y, + event->xbutton.button, event->xbutton.window, app, FALSE); } static BOOL xf_event_KeyPress(xfContext* xfc, XEvent* event, BOOL app) { diff --git a/client/X11/xf_event.h b/client/X11/xf_event.h index 4e880aa..b61c144 100644 --- a/client/X11/xf_event.h +++ b/client/X11/xf_event.h @@ -29,12 +29,14 @@ BOOL xf_event_action_script_init(xfContext* xfc); void xf_event_action_script_free(xfContext* xfc); BOOL xf_event_process(freerdp* instance, XEvent* event); -void xf_event_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, ...); +void xf_event_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, + ...); -void xf_event_adjust_coordinates(xfContext* xfc, int* x, int *y); +void xf_event_adjust_coordinates(xfContext* xfc, int* x, int* y); BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window window, BOOL app); BOOL xf_generic_ButtonPress(xfContext* xfc, int x, int y, int button, Window window, BOOL app); -BOOL xf_generic_ButtonRelease(xfContext* xfc, int x, int y, int button, Window window, BOOL app); +BOOL xf_generic_ButtonEvent(xfContext* xfc, int x, int y, int button, Window window, BOOL app, + BOOL down); #endif /* FREERDP_CLIENT_X11_EVENT_H */ diff --git a/client/X11/xf_input.c b/client/X11/xf_input.c index 0bed66c..4279b59 100644 --- a/client/X11/xf_input.c +++ b/client/X11/xf_input.c @@ -581,13 +581,13 @@ static int xf_input_event(xfContext* xfc, XIDeviceEvent* event, int evtype) switch (evtype) { case XI_ButtonPress: - xf_generic_ButtonPress(xfc, (int) event->event_x, (int) event->event_y, - event->detail, event->event, xfc->remote_app); + xf_generic_ButtonEvent(xfc, (int) event->event_x, (int) event->event_y, + event->detail, event->event, xfc->remote_app, TRUE); break; case XI_ButtonRelease: - xf_generic_ButtonRelease(xfc, (int) event->event_x, (int) event->event_y, - event->detail, event->event, xfc->remote_app); + xf_generic_ButtonEvent(xfc, (int) event->event_x, (int) event->event_y, + event->detail, event->event, xfc->remote_app, FALSE); break; case XI_Motion: diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 98dad2b..5d6dfb9 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -85,13 +85,14 @@ typedef struct _xfDispContext xfDispContext; typedef struct _xfVideoContext xfVideoContext; typedef struct xf_rail_icon_cache xfRailIconCache; -/* Value of the first logical button number in X11 which must be */ -/* subtracted to go from a button number in X11 to an index into */ -/* a per-button array. */ -#define BUTTON_BASE Button1 - /* Number of buttons that are mapped from X11 to RDP button events. */ -#define NUM_BUTTONS_MAPPED 3 +#define NUM_BUTTONS_MAPPED 11 + +typedef struct +{ + int button; + UINT16 flags; +} button_map; struct xf_context { @@ -231,7 +232,7 @@ struct xf_context BOOL xrenderAvailable; /* value to be sent over wire for each logical client mouse button */ - int button_map[NUM_BUTTONS_MAPPED]; + button_map button_map[NUM_BUTTONS_MAPPED]; BYTE savedMaximizedState; }; -- 2.7.4