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