FreeRDP
xf_keyboard.c
1 
20 #include <freerdp/config.h>
21 
22 #include <ctype.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdint.h>
27 
28 #include <winpr/crt.h>
29 #include <winpr/path.h>
30 #include <winpr/assert.h>
31 #include <winpr/collections.h>
32 
33 #include <freerdp/utils/string.h>
34 
35 #include <X11/Xlib.h>
36 #include <X11/Xutil.h>
37 #include <X11/keysym.h>
38 #include <X11/XKBlib.h>
39 
40 #include <freerdp/locale/keyboard.h>
41 
42 #include "xf_event.h"
43 
44 #include "xf_keyboard.h"
45 
46 #include "xf_utils.h"
47 
48 #include <freerdp/log.h>
49 #define TAG CLIENT_TAG("x11")
50 
51 static void xf_keyboard_modifier_map_free(xfContext* xfc)
52 {
53  WINPR_ASSERT(xfc);
54  if (xfc->modifierMap)
55  {
56  XFreeModifiermap(xfc->modifierMap);
57  xfc->modifierMap = NULL;
58  }
59 }
60 
61 BOOL xf_keyboard_update_modifier_map(xfContext* xfc)
62 {
63  WINPR_ASSERT(xfc);
64  xf_keyboard_modifier_map_free(xfc);
65  xfc->modifierMap = XGetModifierMapping(xfc->display);
66  return xfc->modifierMap != NULL;
67 }
68 
69 static void xf_keyboard_send_key(xfContext* xfc, BOOL down, BOOL repeat, const XKeyEvent* ev);
70 
71 static BOOL xf_sync_kbd_state(xfContext* xfc)
72 {
73  const UINT32 syncFlags = xf_keyboard_get_toggle_keys_state(xfc);
74 
75  WINPR_ASSERT(xfc);
76  return freerdp_input_send_synchronize_event(xfc->common.context.input, syncFlags);
77 }
78 
79 static void xf_keyboard_clear(xfContext* xfc)
80 {
81  WINPR_ASSERT(xfc);
82  ZeroMemory(xfc->KeyboardState, sizeof(xfc->KeyboardState));
83 }
84 
85 static BOOL xf_action_script_append(xfContext* xfc, const char* buffer, size_t size, void* user,
86  const char* what, const char* arg)
87 {
88  WINPR_ASSERT(xfc);
89  WINPR_UNUSED(what);
90  WINPR_UNUSED(arg);
91 
92  if (!buffer || (size == 0))
93  return TRUE;
94  return ArrayList_Append(xfc->keyCombinations, buffer);
95 }
96 
97 static BOOL xf_keyboard_action_script_init(xfContext* xfc)
98 {
99  wObject* obj = NULL;
100  const rdpSettings* settings = NULL;
101 
102  settings = xfc->common.context.settings;
103  WINPR_ASSERT(settings);
104 
105  xfc->keyCombinations = ArrayList_New(TRUE);
106 
107  if (!xfc->keyCombinations)
108  return FALSE;
109 
110  obj = ArrayList_Object(xfc->keyCombinations);
111  WINPR_ASSERT(obj);
112  obj->fnObjectNew = winpr_ObjectStringClone;
113  obj->fnObjectFree = winpr_ObjectStringFree;
114 
115  if (!run_action_script(xfc, "key", NULL, xf_action_script_append, NULL))
116  return FALSE;
117 
118  return xf_event_action_script_init(xfc);
119 }
120 
121 static void xf_keyboard_action_script_free(xfContext* xfc)
122 {
123  xf_event_action_script_free(xfc);
124 
125  if (xfc->keyCombinations)
126  {
127  ArrayList_Free(xfc->keyCombinations);
128  xfc->keyCombinations = NULL;
129  xfc->actionScriptExists = FALSE;
130  }
131 }
132 
133 BOOL xf_keyboard_init(xfContext* xfc)
134 {
135  rdpSettings* settings = NULL;
136 
137  WINPR_ASSERT(xfc);
138 
139  settings = xfc->common.context.settings;
140  WINPR_ASSERT(settings);
141 
142  xf_keyboard_clear(xfc);
143  xfc->KeyboardLayout = freerdp_settings_get_uint32(settings, FreeRDP_KeyboardLayout);
144  xfc->KeyboardLayout = freerdp_keyboard_init_ex(
145  xfc->KeyboardLayout, freerdp_settings_get_string(settings, FreeRDP_KeyboardRemappingList));
146  if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardLayout, xfc->KeyboardLayout))
147  return FALSE;
148 
149  if (!xf_keyboard_update_modifier_map(xfc))
150  return FALSE;
151 
152  xf_keyboard_action_script_init(xfc);
153  return TRUE;
154 }
155 
156 void xf_keyboard_free(xfContext* xfc)
157 {
158  xf_keyboard_modifier_map_free(xfc);
159  xf_keyboard_action_script_free(xfc);
160 }
161 
162 void xf_keyboard_key_press(xfContext* xfc, const XKeyEvent* event, KeySym keysym)
163 {
164  BOOL last = 0;
165 
166  WINPR_ASSERT(xfc);
167  WINPR_ASSERT(event);
168  WINPR_ASSERT(event->keycode < ARRAYSIZE(xfc->KeyboardState));
169 
170  last = xfc->KeyboardState[event->keycode];
171  xfc->KeyboardState[event->keycode] = TRUE;
172 
173  if (xf_keyboard_handle_special_keys(xfc, keysym))
174  return;
175 
176  xf_keyboard_send_key(xfc, TRUE, last, event);
177 }
178 
179 void xf_keyboard_key_release(xfContext* xfc, const XKeyEvent* event, KeySym keysym)
180 {
181  WINPR_ASSERT(xfc);
182  WINPR_ASSERT(event);
183  WINPR_ASSERT(event->keycode < ARRAYSIZE(xfc->KeyboardState));
184 
185  BOOL last = xfc->KeyboardState[event->keycode];
186  xfc->KeyboardState[event->keycode] = FALSE;
187  xf_keyboard_handle_special_keys_release(xfc, keysym);
188  xf_keyboard_send_key(xfc, FALSE, last, event);
189 }
190 
191 void xf_keyboard_release_all_keypress(xfContext* xfc)
192 {
193  WINPR_ASSERT(xfc);
194 
195  WINPR_STATIC_ASSERT(ARRAYSIZE(xfc->KeyboardState) <= UINT32_MAX);
196  for (size_t keycode = 0; keycode < ARRAYSIZE(xfc->KeyboardState); keycode++)
197  {
198  if (xfc->KeyboardState[keycode])
199  {
200  const DWORD rdp_scancode =
201  freerdp_keyboard_get_rdp_scancode_from_x11_keycode((UINT32)keycode);
202 
203  // release tab before releasing the windows key.
204  // this stops the start menu from opening on unfocus event.
205  if (rdp_scancode == RDP_SCANCODE_LWIN)
206  freerdp_input_send_keyboard_event_ex(xfc->common.context.input, FALSE, FALSE,
207  RDP_SCANCODE_TAB);
208 
209  freerdp_input_send_keyboard_event_ex(xfc->common.context.input, FALSE, FALSE,
210  rdp_scancode);
211  xfc->KeyboardState[keycode] = FALSE;
212  }
213  }
214  xf_sync_kbd_state(xfc);
215 }
216 
217 BOOL xf_keyboard_key_pressed(xfContext* xfc, KeySym keysym)
218 {
219  KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
220  WINPR_ASSERT(keycode < ARRAYSIZE(xfc->KeyboardState));
221  return xfc->KeyboardState[keycode];
222 }
223 
224 void xf_keyboard_send_key(xfContext* xfc, BOOL down, BOOL repeat, const XKeyEvent* event)
225 {
226  DWORD rdp_scancode = 0;
227  rdpInput* input = NULL;
228 
229  WINPR_ASSERT(xfc);
230  WINPR_ASSERT(event);
231 
232  input = xfc->common.context.input;
233  WINPR_ASSERT(input);
234 
235  rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(event->keycode);
236  if (rdp_scancode == RDP_SCANCODE_PAUSE && !xf_keyboard_key_pressed(xfc, XK_Control_L) &&
237  !xf_keyboard_key_pressed(xfc, XK_Control_R))
238  {
239  /* Pause without Ctrl has to be sent as a series of keycodes
240  * in a single input PDU. Pause only happens on "press";
241  * no code is sent on "release".
242  */
243  if (down)
244  {
245  freerdp_input_send_keyboard_pause_event(input);
246  }
247  }
248  else
249  {
250  if (freerdp_settings_get_bool(xfc->common.context.settings, FreeRDP_UnicodeInput))
251  {
252  wchar_t buffer[32] = { 0 };
253  int xwc = -1;
254 
255  switch (rdp_scancode)
256  {
257  case RDP_SCANCODE_RETURN:
258  break;
259  default:
260  {
261  XIM xim = XOpenIM(xfc->display, 0, 0, 0);
262  XIC xic =
263  XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, NULL);
264 
265  KeySym ignore = { 0 };
266  Status return_status = 0;
267  XKeyEvent ev = *event;
268  ev.type = KeyPress;
269  xwc = XwcLookupString(xic, &ev, buffer, ARRAYSIZE(buffer), &ignore,
270  &return_status);
271  }
272  break;
273  }
274 
275  if (xwc < 1)
276  {
277  if (rdp_scancode == RDP_SCANCODE_UNKNOWN)
278  WLog_ERR(TAG, "Unknown key with X keycode 0x%02" PRIx8 "", event->keycode);
279  else
280  freerdp_input_send_keyboard_event_ex(input, down, repeat, rdp_scancode);
281  }
282  else
283  freerdp_input_send_unicode_keyboard_event(input, down ? 0 : KBD_FLAGS_RELEASE,
284  buffer[0]);
285  }
286  else if (rdp_scancode == RDP_SCANCODE_UNKNOWN)
287  WLog_ERR(TAG, "Unknown key with X keycode 0x%02" PRIx8 "", event->keycode);
288  else
289  freerdp_input_send_keyboard_event_ex(input, down, repeat, rdp_scancode);
290 
291  if ((rdp_scancode == RDP_SCANCODE_CAPSLOCK) && (down == FALSE))
292  {
293  xf_sync_kbd_state(xfc);
294  }
295  }
296 }
297 
298 int xf_keyboard_read_keyboard_state(xfContext* xfc)
299 {
300  int dummy = 0;
301  Window wdummy = 0;
302  UINT32 state = 0;
303 
304  if (!xfc->remote_app && xfc->window)
305  {
306  XQueryPointer(xfc->display, xfc->window->handle, &wdummy, &wdummy, &dummy, &dummy, &dummy,
307  &dummy, &state);
308  }
309  else
310  {
311  XQueryPointer(xfc->display, DefaultRootWindow(xfc->display), &wdummy, &wdummy, &dummy,
312  &dummy, &dummy, &dummy, &state);
313  }
314 
315  return state;
316 }
317 
318 static int xf_keyboard_get_keymask(xfContext* xfc, int keysym)
319 {
320  int keysymMask = 0;
321  KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
322 
323  if (keycode == NoSymbol)
324  return 0;
325 
326  WINPR_ASSERT(xfc->modifierMap);
327  for (int modifierpos = 0; modifierpos < 8; modifierpos++)
328  {
329  int offset = xfc->modifierMap->max_keypermod * modifierpos;
330 
331  for (int key = 0; key < xfc->modifierMap->max_keypermod; key++)
332  {
333  if (xfc->modifierMap->modifiermap[offset + key] == keycode)
334  {
335  keysymMask |= 1 << modifierpos;
336  }
337  }
338  }
339 
340  return keysymMask;
341 }
342 
343 BOOL xf_keyboard_get_key_state(xfContext* xfc, int state, int keysym)
344 {
345  int keysymMask = xf_keyboard_get_keymask(xfc, keysym);
346 
347  if (!keysymMask)
348  return FALSE;
349 
350  return (state & keysymMask) ? TRUE : FALSE;
351 }
352 
353 static BOOL xf_keyboard_set_key_state(xfContext* xfc, BOOL on, int keysym)
354 {
355  if (!xfc->xkbAvailable)
356  return FALSE;
357 
358  const int keysymMask = xf_keyboard_get_keymask(xfc, keysym);
359 
360  if (!keysymMask)
361  {
362  return FALSE;
363  }
364 
365  return XkbLockModifiers(xfc->display, XkbUseCoreKbd, keysymMask, on ? keysymMask : 0);
366 }
367 
368 UINT32 xf_keyboard_get_toggle_keys_state(xfContext* xfc)
369 {
370  UINT32 toggleKeysState = 0;
371  const int state = xf_keyboard_read_keyboard_state(xfc);
372 
373  if (xf_keyboard_get_key_state(xfc, state, XK_Scroll_Lock))
374  toggleKeysState |= KBD_SYNC_SCROLL_LOCK;
375 
376  if (xf_keyboard_get_key_state(xfc, state, XK_Num_Lock))
377  toggleKeysState |= KBD_SYNC_NUM_LOCK;
378 
379  if (xf_keyboard_get_key_state(xfc, state, XK_Caps_Lock))
380  toggleKeysState |= KBD_SYNC_CAPS_LOCK;
381 
382  if (xf_keyboard_get_key_state(xfc, state, XK_Kana_Lock))
383  toggleKeysState |= KBD_SYNC_KANA_LOCK;
384 
385  return toggleKeysState;
386 }
387 
388 static void xk_keyboard_update_modifier_keys(xfContext* xfc)
389 {
390  const int keysyms[] = { XK_Shift_L, XK_Shift_R, XK_Alt_L, XK_Alt_R,
391  XK_Control_L, XK_Control_R, XK_Super_L, XK_Super_R };
392 
393  xf_keyboard_clear(xfc);
394 
395  const int state = xf_keyboard_read_keyboard_state(xfc);
396 
397  for (size_t i = 0; i < ARRAYSIZE(keysyms); i++)
398  {
399  if (xf_keyboard_get_key_state(xfc, state, keysyms[i]))
400  {
401  const KeyCode keycode = XKeysymToKeycode(xfc->display, keysyms[i]);
402  WINPR_ASSERT(keycode < ARRAYSIZE(xfc->KeyboardState));
403  xfc->KeyboardState[keycode] = TRUE;
404  }
405  }
406 }
407 
408 void xf_keyboard_focus_in(xfContext* xfc)
409 {
410  UINT32 state = 0;
411  Window w = None;
412  int d = 0;
413  int x = 0;
414  int y = 0;
415 
416  WINPR_ASSERT(xfc);
417  if (!xfc->display || !xfc->window)
418  return;
419 
420  rdpInput* input = xfc->common.context.input;
421  WINPR_ASSERT(input);
422 
423  const UINT32 syncFlags = xf_keyboard_get_toggle_keys_state(xfc);
424  freerdp_input_send_focus_in_event(input, syncFlags);
425  xk_keyboard_update_modifier_keys(xfc);
426 
427  /* finish with a mouse pointer position like mstsc.exe if required */
428 
429  if (xfc->remote_app || !xfc->window)
430  return;
431 
432  if (XQueryPointer(xfc->display, xfc->window->handle, &w, &w, &d, &d, &x, &y, &state))
433  {
434  if ((x >= 0) && (x < xfc->window->width) && (y >= 0) && (y < xfc->window->height))
435  {
436  xf_event_adjust_coordinates(xfc, &x, &y);
437  freerdp_client_send_button_event(&xfc->common, FALSE, PTR_FLAGS_MOVE, x, y);
438  }
439  }
440 }
441 
442 static BOOL action_script_run(xfContext* xfc, const char* buffer, size_t size, void* user,
443  const char* what, const char* arg)
444 {
445  WINPR_UNUSED(xfc);
446  WINPR_UNUSED(what);
447  WINPR_UNUSED(arg);
448  WINPR_ASSERT(user);
449  int* pstatus = user;
450 
451  if (size == 0)
452  {
453  WLog_WARN(TAG, "ActionScript key: script did not return data");
454  return FALSE;
455  }
456 
457  if (strcmp(buffer, "key-local") == 0)
458  *pstatus = 0;
459  else if (winpr_PathFileExists(buffer))
460  {
461  FILE* fp = popen(buffer, "w");
462  if (!fp)
463  {
464  WLog_ERR(TAG, "Failed to execute '%s'", buffer);
465  return FALSE;
466  }
467 
468  *pstatus = pclose(fp);
469  if (*pstatus < 0)
470  {
471  WLog_ERR(TAG, "Command '%s' returned %d", buffer, *pstatus);
472  return FALSE;
473  }
474  }
475  else
476  {
477  WLog_WARN(TAG, "ActionScript key: no such file '%s'", buffer);
478  return FALSE;
479  }
480  return TRUE;
481 }
482 
483 static int xf_keyboard_execute_action_script(xfContext* xfc, XF_MODIFIER_KEYS* mod, KeySym keysym)
484 {
485  int status = 1;
486  BOOL match = FALSE;
487  char command[2048] = { 0 };
488  char combination[1024] = { 0 };
489 
490  if (!xfc->actionScriptExists)
491  return 1;
492 
493  if ((keysym == XK_Shift_L) || (keysym == XK_Shift_R) || (keysym == XK_Alt_L) ||
494  (keysym == XK_Alt_R) || (keysym == XK_Control_L) || (keysym == XK_Control_R))
495  {
496  return 1;
497  }
498 
499  const char* keyStr = XKeysymToString(keysym);
500 
501  if (keyStr == 0)
502  {
503  return 1;
504  }
505 
506  if (mod->Shift)
507  winpr_str_append("Shift", combination, sizeof(combination), "+");
508 
509  if (mod->Ctrl)
510  winpr_str_append("Ctrl", combination, sizeof(combination), "+");
511 
512  if (mod->Alt)
513  winpr_str_append("Alt", combination, sizeof(combination), "+");
514 
515  if (mod->Super)
516  winpr_str_append("Super", combination, sizeof(combination), "+");
517 
518  winpr_str_append(keyStr, combination, sizeof(combination), "+");
519 
520  for (size_t i = 0; i < strnlen(combination, sizeof(combination)); i++)
521  combination[i] = tolower(combination[i]);
522 
523  const size_t count = ArrayList_Count(xfc->keyCombinations);
524 
525  for (size_t index = 0; index < count; index++)
526  {
527  const char* keyCombination = (const char*)ArrayList_GetItem(xfc->keyCombinations, index);
528 
529  if (_stricmp(keyCombination, combination) == 0)
530  {
531  match = TRUE;
532  break;
533  }
534  }
535 
536  if (!match)
537  return 1;
538 
539  (void)sprintf_s(command, sizeof(command), "key %s", combination);
540  if (!run_action_script(xfc, command, NULL, action_script_run, &status))
541  return -1;
542 
543  return status;
544 }
545 
546 static int xk_keyboard_get_modifier_keys(xfContext* xfc, XF_MODIFIER_KEYS* mod)
547 {
548  mod->LeftShift = xf_keyboard_key_pressed(xfc, XK_Shift_L);
549  mod->RightShift = xf_keyboard_key_pressed(xfc, XK_Shift_R);
550  mod->Shift = mod->LeftShift || mod->RightShift;
551  mod->LeftAlt = xf_keyboard_key_pressed(xfc, XK_Alt_L);
552  mod->RightAlt = xf_keyboard_key_pressed(xfc, XK_Alt_R);
553  mod->Alt = mod->LeftAlt || mod->RightAlt;
554  mod->LeftCtrl = xf_keyboard_key_pressed(xfc, XK_Control_L);
555  mod->RightCtrl = xf_keyboard_key_pressed(xfc, XK_Control_R);
556  mod->Ctrl = mod->LeftCtrl || mod->RightCtrl;
557  mod->LeftSuper = xf_keyboard_key_pressed(xfc, XK_Super_L);
558  mod->RightSuper = xf_keyboard_key_pressed(xfc, XK_Super_R);
559  mod->Super = mod->LeftSuper || mod->RightSuper;
560  return 0;
561 }
562 
563 BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym)
564 {
565  XF_MODIFIER_KEYS mod = { 0 };
566  xk_keyboard_get_modifier_keys(xfc, &mod);
567 
568  // remember state of RightCtrl to ungrab keyboard if next action is release of RightCtrl
569  // do not return anything such that the key could be used by client if ungrab is not the goal
570  if (keysym == XK_Control_R)
571  {
572  if (mod.RightCtrl && !xfc->wasRightCtrlAlreadyPressed)
573  {
574  // Right Ctrl is pressed, getting ready to ungrab
575  xfc->ungrabKeyboardWithRightCtrl = TRUE;
576  xfc->wasRightCtrlAlreadyPressed = TRUE;
577  }
578  }
579  else
580  {
581  // some other key has been pressed, abort ungrabbing
582  if (xfc->ungrabKeyboardWithRightCtrl)
583  xfc->ungrabKeyboardWithRightCtrl = FALSE;
584  }
585 
586  const int rc = xf_keyboard_execute_action_script(xfc, &mod, keysym);
587  if (rc < 0)
588  return FALSE;
589  if (rc == 0)
590  return TRUE;
591 
592  if (!xfc->remote_app && xfc->fullscreen_toggle)
593  {
594  switch (keysym)
595  {
596  case XK_Return:
597  if (mod.Ctrl && mod.Alt)
598  {
599  /* Ctrl-Alt-Enter: toggle full screen */
600  xf_toggle_fullscreen(xfc);
601  return TRUE;
602  }
603  break;
604  default:
605  break;
606  }
607  }
608 
609  if (mod.Ctrl && mod.Alt)
610  {
611  switch (keysym)
612  {
613  case XK_m:
614  case XK_M:
615  xf_minimize(xfc);
616  return TRUE;
617  case XK_c:
618  case XK_C:
619  /* Ctrl-Alt-C: toggle control */
620  if (freerdp_client_encomsp_toggle_control(xfc->common.encomsp))
621  return TRUE;
622  break;
623  default:
624  break;
625  }
626  }
627 
628 #if 0 /* set to 1 to enable multi touch gesture simulation via keyboard */
629 #ifdef WITH_XRENDER
630 
631  if (!xfc->remote_app && freerdp_settings_get_bool(xfc->common.context.settings, FreeRDP_MultiTouchGestures))
632  {
633  rdpContext* ctx = &xfc->common.context;
634 
635  if (mod.Ctrl && mod.Alt)
636  {
637  int pdx = 0;
638  int pdy = 0;
639  int zdx = 0;
640  int zdy = 0;
641 
642  switch (keysym)
643  {
644  case XK_0: /* Ctrl-Alt-0: Reset scaling and panning */{
645  const UINT32 sessionWidth = freerdp_settings_get_uint32(xfc->common.context.settings, FreeRDP_DesktopWidth);
646  const UINT32 sessionHeight = freerdp_settings_get_uint32(xfc->common.context.settings, FreeRDP_DesktopHeight);
647 
648  xfc->scaledWidth = sessionWidth;
649  xfc->scaledHeight = sessionHeight;
650  xfc->offset_x = 0;
651  xfc->offset_y = 0;
652 
653  if (!xfc->fullscreen && (sessionWidth != xfc->window->width ||
654  sessionHeight != xfc->window->height))
655  {
656  xf_ResizeDesktopWindow(xfc, xfc->window, sessionWidth, sessionHeight);
657  }
658 
659  xf_draw_screen(xfc, 0, 0, sessionWidth, sessionHeight);
660  return TRUE;
661 }
662 
663  case XK_1: /* Ctrl-Alt-1: Zoom in */
664  zdx = zdy = 10;
665  break;
666 
667  case XK_2: /* Ctrl-Alt-2: Zoom out */
668  zdx = zdy = -10;
669  break;
670 
671  case XK_3: /* Ctrl-Alt-3: Pan left */
672  pdx = -10;
673  break;
674 
675  case XK_4: /* Ctrl-Alt-4: Pan right */
676  pdx = 10;
677  break;
678 
679  case XK_5: /* Ctrl-Alt-5: Pan up */
680  pdy = -10;
681  break;
682 
683  case XK_6: /* Ctrl-Alt-6: Pan up */
684  pdy = 10;
685  break;
686  }
687 
688  if (pdx != 0 || pdy != 0)
689  {
690  PanningChangeEventArgs e;
691  EventArgsInit(&e, "xfreerdp");
692  e.dx = pdx;
693  e.dy = pdy;
694  PubSub_OnPanningChange(ctx->pubSub, xfc, &e);
695  return TRUE;
696  }
697 
698  if (zdx != 0 || zdy != 0)
699  {
700  ZoomingChangeEventArgs e;
701  EventArgsInit(&e, "xfreerdp");
702  e.dx = zdx;
703  e.dy = zdy;
704  PubSub_OnZoomingChange(ctx->pubSub, xfc, &e);
705  return TRUE;
706  }
707  }
708  }
709 
710 #endif /* WITH_XRENDER defined */
711 #endif /* pinch/zoom/pan simulation */
712  return FALSE;
713 }
714 
715 void xf_keyboard_handle_special_keys_release(xfContext* xfc, KeySym keysym)
716 {
717  if (keysym != XK_Control_R)
718  return;
719 
720  xfc->wasRightCtrlAlreadyPressed = FALSE;
721 
722  if (!xfc->ungrabKeyboardWithRightCtrl)
723  return;
724 
725  // all requirements for ungrab are fulfilled, ungrabbing now
726  XF_MODIFIER_KEYS mod = { 0 };
727  xk_keyboard_get_modifier_keys(xfc, &mod);
728 
729  if (!mod.RightCtrl)
730  {
731  if (!xfc->fullscreen)
732  {
733  freerdp_client_encomsp_toggle_control(xfc->common.encomsp);
734  }
735 
736  xfc->mouse_active = FALSE;
737  xf_ungrab(xfc);
738  }
739 
740  // ungrabbed
741  xfc->ungrabKeyboardWithRightCtrl = FALSE;
742 }
743 
744 BOOL xf_keyboard_set_indicators(rdpContext* context, UINT16 led_flags)
745 {
746  xfContext* xfc = (xfContext*)context;
747  xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_SCROLL_LOCK, XK_Scroll_Lock);
748  xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_NUM_LOCK, XK_Num_Lock);
749  xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_CAPS_LOCK, XK_Caps_Lock);
750  xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_KANA_LOCK, XK_Kana_Lock);
751  return TRUE;
752 }
753 
754 BOOL xf_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
755  UINT32 imeConvMode)
756 {
757  if (!context)
758  return FALSE;
759 
760  WLog_WARN(TAG,
761  "KeyboardSetImeStatus(unitId=%04" PRIx16 ", imeState=%08" PRIx32
762  ", imeConvMode=%08" PRIx32 ") ignored",
763  imeId, imeState, imeConvMode);
764  return TRUE;
765 }
766 
767 BOOL xf_ungrab(xfContext* xfc)
768 {
769  WINPR_ASSERT(xfc);
770  XUngrabKeyboard(xfc->display, CurrentTime);
771  XUngrabPointer(xfc->display, CurrentTime);
772  xfc->common.mouse_grabbed = FALSE;
773  return TRUE;
774 }
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.
This struct contains function pointer to initialize/free objects.
Definition: collections.h:57