2011-08-07 21:41:54 +04:00
|
|
|
/**
|
2012-10-09 07:02:04 +04:00
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
2011-08-07 21:41:54 +04:00
|
|
|
* X11 Keyboard Handling
|
|
|
|
*
|
|
|
|
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2012-08-15 01:20:53 +04:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2011-08-07 21:41:54 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2012-11-22 06:22:06 +04:00
|
|
|
|
|
|
|
#include <winpr/crt.h>
|
|
|
|
|
2011-08-07 21:41:54 +04:00
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/Xutil.h>
|
|
|
|
#include <X11/keysym.h>
|
|
|
|
|
2012-11-29 10:33:19 +04:00
|
|
|
#include <freerdp/locale/keyboard.h>
|
|
|
|
|
2011-08-07 21:41:54 +04:00
|
|
|
#include "xf_keyboard.h"
|
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
void xf_kbd_init(xfContext* xfc)
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
2013-06-13 02:57:25 +04:00
|
|
|
xf_kbd_clear(xfc);
|
|
|
|
xfc->keyboard_layout_id = xfc->instance->settings->KeyboardLayout;
|
|
|
|
xfc->keyboard_layout_id = freerdp_keyboard_init(xfc->keyboard_layout_id);
|
|
|
|
xfc->instance->settings->KeyboardLayout = xfc->keyboard_layout_id;
|
|
|
|
xfc->modifier_map = XGetModifierMapping(xfc->display);
|
2011-08-07 21:41:54 +04:00
|
|
|
}
|
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
void xf_kbd_clear(xfContext* xfc)
|
2012-08-03 00:45:03 +04:00
|
|
|
{
|
2013-06-13 02:57:25 +04:00
|
|
|
ZeroMemory(xfc->pressed_keys, 256 * sizeof(BOOL));
|
2012-08-03 00:45:03 +04:00
|
|
|
}
|
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
void xf_kbd_set_keypress(xfContext* xfc, BYTE keycode, KeySym keysym)
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
|
|
|
if (keycode >= 8)
|
2013-06-13 02:57:25 +04:00
|
|
|
xfc->pressed_keys[keycode] = keysym;
|
2011-08-07 21:41:54 +04:00
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
void xf_kbd_unset_keypress(xfContext* xfc, BYTE keycode)
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
|
|
|
if (keycode >= 8)
|
2013-06-13 02:57:25 +04:00
|
|
|
xfc->pressed_keys[keycode] = NoSymbol;
|
2011-08-07 21:41:54 +04:00
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
void xf_kbd_release_all_keypress(xfContext* xfc)
|
2012-04-11 08:37:47 +04:00
|
|
|
{
|
|
|
|
int keycode;
|
2013-03-06 21:50:25 +04:00
|
|
|
DWORD rdp_scancode;
|
2012-04-11 08:37:47 +04:00
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
for (keycode = 0; keycode < ARRAYSIZE(xfc->pressed_keys); keycode++)
|
2012-04-11 08:37:47 +04:00
|
|
|
{
|
2013-06-13 02:57:25 +04:00
|
|
|
if (xfc->pressed_keys[keycode] != NoSymbol)
|
2012-04-11 08:37:47 +04:00
|
|
|
{
|
|
|
|
rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(keycode);
|
2013-06-13 02:57:25 +04:00
|
|
|
freerdp_input_send_keyboard_event_ex(xfc->instance->input, FALSE, rdp_scancode);
|
|
|
|
xfc->pressed_keys[keycode] = NoSymbol;
|
2012-04-11 08:37:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
BOOL xf_kbd_key_pressed(xfContext* xfc, KeySym keysym)
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
2013-06-13 02:57:25 +04:00
|
|
|
KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
|
|
|
|
return (xfc->pressed_keys[keycode] == keysym);
|
2011-08-07 21:41:54 +04:00
|
|
|
}
|
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
void xf_kbd_send_key(xfContext* xfc, BOOL down, BYTE keycode)
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
2013-03-06 21:50:25 +04:00
|
|
|
DWORD rdp_scancode;
|
2011-08-07 21:41:54 +04:00
|
|
|
rdpInput* input;
|
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
input = xfc->instance->input;
|
2012-03-29 03:12:35 +04:00
|
|
|
rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(keycode);
|
2011-08-07 21:41:54 +04:00
|
|
|
|
2012-03-29 03:12:48 +04:00
|
|
|
if (rdp_scancode == RDP_SCANCODE_UNKNOWN)
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
2013-03-29 02:06:34 +04:00
|
|
|
fprintf(stderr, "Unknown key with X keycode 0x%02x\n", keycode);
|
2011-08-07 21:41:54 +04:00
|
|
|
}
|
2012-03-29 03:12:48 +04:00
|
|
|
else if (rdp_scancode == RDP_SCANCODE_PAUSE &&
|
2013-06-13 02:57:25 +04:00
|
|
|
!xf_kbd_key_pressed(xfc, XK_Control_L) && !xf_kbd_key_pressed(xfc, XK_Control_R))
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
|
|
|
/* Pause without Ctrl has to be sent as Ctrl + NumLock. */
|
|
|
|
if (down)
|
|
|
|
{
|
2012-10-09 10:31:28 +04:00
|
|
|
freerdp_input_send_keyboard_event_ex(input, TRUE, RDP_SCANCODE_LCONTROL);
|
|
|
|
freerdp_input_send_keyboard_event_ex(input, TRUE, RDP_SCANCODE_NUMLOCK);
|
|
|
|
freerdp_input_send_keyboard_event_ex(input, FALSE, RDP_SCANCODE_LCONTROL);
|
|
|
|
freerdp_input_send_keyboard_event_ex(input, FALSE, RDP_SCANCODE_NUMLOCK);
|
2011-08-07 21:41:54 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-09-22 22:27:30 +04:00
|
|
|
freerdp_input_send_keyboard_event_ex(input, down, rdp_scancode);
|
2011-08-07 21:41:54 +04:00
|
|
|
|
2012-10-09 10:31:28 +04:00
|
|
|
if ((rdp_scancode == RDP_SCANCODE_CAPSLOCK) && (down == FALSE))
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
2012-10-09 11:26:39 +04:00
|
|
|
UINT32 syncFlags;
|
2013-06-13 02:57:25 +04:00
|
|
|
syncFlags = xf_kbd_get_toggle_keys_state(xfc);
|
2011-08-07 21:41:54 +04:00
|
|
|
input->SynchronizeEvent(input, syncFlags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
int xf_kbd_read_keyboard_state(xfContext* xfc)
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
|
|
|
int dummy;
|
|
|
|
Window wdummy;
|
2012-10-09 11:26:39 +04:00
|
|
|
UINT32 state = 0;
|
2011-08-07 21:41:54 +04:00
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
if (!xfc->remote_app)
|
2011-08-18 09:16:49 +04:00
|
|
|
{
|
2013-06-13 02:57:25 +04:00
|
|
|
XQueryPointer(xfc->display, xfc->window->handle,
|
2011-08-07 21:41:54 +04:00
|
|
|
&wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
|
2011-08-18 09:16:49 +04:00
|
|
|
}
|
2012-02-28 03:04:11 +04:00
|
|
|
else
|
|
|
|
{
|
2013-06-13 02:57:25 +04:00
|
|
|
XQueryPointer(xfc->display, DefaultRootWindow(xfc->display),
|
2012-02-28 03:04:11 +04:00
|
|
|
&wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
|
|
|
|
}
|
2011-08-07 21:41:54 +04:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
BOOL xf_kbd_get_key_state(xfContext* xfc, int state, int keysym)
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
|
|
|
int offset;
|
|
|
|
int modifierpos, key, keysymMask = 0;
|
2013-06-13 02:57:25 +04:00
|
|
|
KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
|
2011-08-07 21:41:54 +04:00
|
|
|
|
|
|
|
if (keycode == NoSymbol)
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2011-08-07 21:41:54 +04:00
|
|
|
|
|
|
|
for (modifierpos = 0; modifierpos < 8; modifierpos++)
|
|
|
|
{
|
2013-06-13 02:57:25 +04:00
|
|
|
offset = xfc->modifier_map->max_keypermod * modifierpos;
|
2013-02-10 22:17:08 +04:00
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
for (key = 0; key < xfc->modifier_map->max_keypermod; key++)
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
2013-06-13 02:57:25 +04:00
|
|
|
if (xfc->modifier_map->modifiermap[offset + key] == keycode)
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
|
|
|
keysymMask |= 1 << modifierpos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-09 10:31:28 +04:00
|
|
|
return (state & keysymMask) ? TRUE : FALSE;
|
2011-08-07 21:41:54 +04:00
|
|
|
}
|
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
int xf_kbd_get_toggle_keys_state(xfContext* xfc)
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
|
|
|
int state;
|
|
|
|
int toggle_keys_state = 0;
|
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
state = xf_kbd_read_keyboard_state(xfc);
|
2013-02-12 05:38:19 +04:00
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
if (xf_kbd_get_key_state(xfc, state, XK_Scroll_Lock))
|
2011-08-07 21:41:54 +04:00
|
|
|
toggle_keys_state |= KBD_SYNC_SCROLL_LOCK;
|
2013-06-13 02:57:25 +04:00
|
|
|
if (xf_kbd_get_key_state(xfc, state, XK_Num_Lock))
|
2011-08-07 21:41:54 +04:00
|
|
|
toggle_keys_state |= KBD_SYNC_NUM_LOCK;
|
2013-06-13 02:57:25 +04:00
|
|
|
if (xf_kbd_get_key_state(xfc, state, XK_Caps_Lock))
|
2011-08-07 21:41:54 +04:00
|
|
|
toggle_keys_state |= KBD_SYNC_CAPS_LOCK;
|
2013-06-13 02:57:25 +04:00
|
|
|
if (xf_kbd_get_key_state(xfc, state, XK_Kana_Lock))
|
2011-08-07 21:41:54 +04:00
|
|
|
toggle_keys_state |= KBD_SYNC_KANA_LOCK;
|
|
|
|
|
|
|
|
return toggle_keys_state;
|
|
|
|
}
|
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
void xf_kbd_focus_in(xfContext* xfc)
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
|
|
|
rdpInput* input;
|
2012-10-09 11:26:39 +04:00
|
|
|
UINT32 syncFlags;
|
2013-04-15 14:14:09 +04:00
|
|
|
int dummy, mouseX, mouseY;
|
|
|
|
Window wdummy;
|
|
|
|
UINT32 state = 0;
|
2011-08-07 21:41:54 +04:00
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
if (xfc->display && xfc->window)
|
2013-05-15 12:42:21 +04:00
|
|
|
{
|
2013-06-13 02:57:25 +04:00
|
|
|
input = xfc->instance->input;
|
|
|
|
syncFlags = xf_kbd_get_toggle_keys_state(xfc);
|
|
|
|
XQueryPointer(xfc->display, xfc->window->handle, &wdummy, &wdummy, &mouseX, &mouseY, &dummy, &dummy, &state);
|
2013-05-15 12:42:21 +04:00
|
|
|
input->FocusInEvent(input, syncFlags, mouseX, mouseY);
|
|
|
|
}
|
2011-08-07 21:41:54 +04:00
|
|
|
}
|
|
|
|
|
2013-06-13 02:57:25 +04:00
|
|
|
BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
|
|
|
if (keysym == XK_Return)
|
|
|
|
{
|
2013-06-13 02:57:25 +04:00
|
|
|
if ((xf_kbd_key_pressed(xfc, XK_Alt_L) || xf_kbd_key_pressed(xfc, XK_Alt_R))
|
|
|
|
&& (xf_kbd_key_pressed(xfc, XK_Control_L) || xf_kbd_key_pressed(xfc, XK_Control_R)))
|
2011-08-07 21:41:54 +04:00
|
|
|
{
|
|
|
|
/* Ctrl-Alt-Enter: toggle full screen */
|
2013-06-13 02:57:25 +04:00
|
|
|
xf_toggle_fullscreen(xfc);
|
2012-10-09 10:31:28 +04:00
|
|
|
return TRUE;
|
2011-08-07 21:41:54 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2011-08-07 21:41:54 +04:00
|
|
|
}
|
|
|
|
|