Blame client/X11/xf_keyboard.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * X11 Keyboard Handling
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/path.h>
Packit 1fb8d4
#include <winpr/collections.h>
Packit 1fb8d4
Packit 1fb8d4
#include <X11/Xlib.h>
Packit 1fb8d4
#include <X11/Xutil.h>
Packit 1fb8d4
#include <X11/keysym.h>
Packit 1fb8d4
#include <X11/XKBlib.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/locale/keyboard.h>
Packit 1fb8d4
Packit 1fb8d4
#include "xf_event.h"
Packit 1fb8d4
Packit 1fb8d4
#include "xf_keyboard.h"
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
#define TAG CLIENT_TAG("x11")
Packit 1fb8d4
Packit 1fb8d4
static BOOL firstPressRightCtrl = TRUE;
Packit 1fb8d4
static BOOL ungrabKeyboardWithRightCtrl = TRUE;
Packit 1fb8d4
Packit 1fb8d4
static BOOL xf_keyboard_action_script_init(xfContext* xfc)
Packit 1fb8d4
{
Packit 1fb8d4
	FILE* keyScript;
Packit 1fb8d4
	char* keyCombination;
Packit 1fb8d4
	char buffer[1024] = { 0 };
Packit 1fb8d4
	char command[1024] = { 0 };
Packit 1fb8d4
	xfc->actionScriptExists = PathFileExistsA(xfc->context.settings->ActionScript);
Packit 1fb8d4
Packit 1fb8d4
	if (!xfc->actionScriptExists)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	xfc->keyCombinations = ArrayList_New(TRUE);
Packit 1fb8d4
Packit 1fb8d4
	if (!xfc->keyCombinations)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	ArrayList_Object(xfc->keyCombinations)->fnObjectFree = free;
Packit 1fb8d4
	sprintf_s(command, sizeof(command), "%s key", xfc->context.settings->ActionScript);
Packit 1fb8d4
	keyScript = popen(command, "r");
Packit 1fb8d4
Packit 1fb8d4
	if (!keyScript)
Packit 1fb8d4
	{
Packit 1fb8d4
		xfc->actionScriptExists = FALSE;
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	while (fgets(buffer, sizeof(buffer), keyScript) != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		strtok(buffer, "\n");
Packit 1fb8d4
		keyCombination = _strdup(buffer);
Packit 1fb8d4
Packit 1fb8d4
		if (!keyCombination || ArrayList_Add(xfc->keyCombinations, keyCombination) < 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			ArrayList_Free(xfc->keyCombinations);
Packit 1fb8d4
			xfc->actionScriptExists = FALSE;
Packit 1fb8d4
			pclose(keyScript);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	pclose(keyScript);
Packit 1fb8d4
	return xf_event_action_script_init(xfc);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void xf_keyboard_action_script_free(xfContext* xfc)
Packit 1fb8d4
{
Packit 1fb8d4
	xf_event_action_script_free(xfc);
Packit 1fb8d4
Packit 1fb8d4
	if (xfc->keyCombinations)
Packit 1fb8d4
	{
Packit 1fb8d4
		ArrayList_Free(xfc->keyCombinations);
Packit 1fb8d4
		xfc->keyCombinations = NULL;
Packit 1fb8d4
		xfc->actionScriptExists = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL xf_keyboard_init(xfContext* xfc)
Packit 1fb8d4
{
Packit 1fb8d4
	xf_keyboard_clear(xfc);
Packit 1fb8d4
	xfc->KeyboardLayout = xfc->context.settings->KeyboardLayout;
Packit 1fb8d4
	xfc->KeyboardLayout = freerdp_keyboard_init(xfc->KeyboardLayout);
Packit 1fb8d4
	xfc->context.settings->KeyboardLayout = xfc->KeyboardLayout;
Packit 1fb8d4
Packit 1fb8d4
	if (xfc->modifierMap)
Packit 1fb8d4
		XFreeModifiermap(xfc->modifierMap);
Packit 1fb8d4
Packit 1fb8d4
	if (!(xfc->modifierMap = XGetModifierMapping(xfc->display)))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	xf_keyboard_action_script_init(xfc);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void xf_keyboard_free(xfContext* xfc)
Packit 1fb8d4
{
Packit 1fb8d4
	if (xfc->modifierMap)
Packit 1fb8d4
	{
Packit 1fb8d4
		XFreeModifiermap(xfc->modifierMap);
Packit 1fb8d4
		xfc->modifierMap = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	xf_keyboard_action_script_free(xfc);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void xf_keyboard_clear(xfContext* xfc)
Packit 1fb8d4
{
Packit 1fb8d4
	ZeroMemory(xfc->KeyboardState, 256 * sizeof(BOOL));
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void xf_keyboard_key_press(xfContext* xfc, BYTE keycode, KeySym keysym)
Packit 1fb8d4
{
Packit 1fb8d4
	if (keycode < 8)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	xfc->KeyboardState[keycode] = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (xf_keyboard_handle_special_keys(xfc, keysym))
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	xf_keyboard_send_key(xfc, TRUE, keycode);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void xf_keyboard_key_release(xfContext* xfc, BYTE keycode, KeySym keysym)
Packit 1fb8d4
{
Packit 1fb8d4
	if (keycode < 8)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	xfc->KeyboardState[keycode] = FALSE;
Packit 1fb8d4
	xf_keyboard_handle_special_keys_release(xfc, keysym);
Packit 1fb8d4
	xf_keyboard_send_key(xfc, FALSE, keycode);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void xf_keyboard_release_all_keypress(xfContext* xfc)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t keycode;
Packit 1fb8d4
	DWORD rdp_scancode;
Packit 1fb8d4
Packit 1fb8d4
	for (keycode = 0; keycode < ARRAYSIZE(xfc->KeyboardState); keycode++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (xfc->KeyboardState[keycode])
Packit 1fb8d4
		{
Packit 1fb8d4
			rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(keycode);
Packit 1fb8d4
Packit 1fb8d4
			// release tab before releasing the windows key.
Packit 1fb8d4
			// this stops the start menu from opening on unfocus event.
Packit 1fb8d4
			if (rdp_scancode == RDP_SCANCODE_LWIN)
Packit 1fb8d4
				freerdp_input_send_keyboard_event_ex(xfc->context.input, FALSE,
Packit 1fb8d4
				                                     RDP_SCANCODE_TAB);
Packit 1fb8d4
Packit 1fb8d4
			freerdp_input_send_keyboard_event_ex(xfc->context.input, FALSE, rdp_scancode);
Packit 1fb8d4
			xfc->KeyboardState[keycode] = FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL xf_keyboard_key_pressed(xfContext* xfc, KeySym keysym)
Packit 1fb8d4
{
Packit 1fb8d4
	KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
Packit 1fb8d4
	return xfc->KeyboardState[keycode];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void xf_keyboard_send_key(xfContext* xfc, BOOL down, BYTE keycode)
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD rdp_scancode;
Packit 1fb8d4
	rdpInput* input;
Packit 1fb8d4
	input = xfc->context.input;
Packit 1fb8d4
	rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(keycode);
Packit 1fb8d4
Packit 1fb8d4
	if (rdp_scancode == RDP_SCANCODE_UNKNOWN)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG,  "Unknown key with X keycode 0x%02"PRIx8"", keycode);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (rdp_scancode == RDP_SCANCODE_PAUSE &&
Packit 1fb8d4
	         !xf_keyboard_key_pressed(xfc, XK_Control_L)
Packit 1fb8d4
	         && !xf_keyboard_key_pressed(xfc, XK_Control_R))
Packit 1fb8d4
	{
Packit 1fb8d4
		/* Pause without Ctrl has to be sent as a series of keycodes
Packit 1fb8d4
		 * in a single input PDU.  Pause only happens on "press";
Packit 1fb8d4
		 * no code is sent on "release".
Packit 1fb8d4
		 */
Packit 1fb8d4
		if (down)
Packit 1fb8d4
		{
Packit 1fb8d4
			freerdp_input_send_keyboard_pause_event(input);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		freerdp_input_send_keyboard_event_ex(input, down, rdp_scancode);
Packit 1fb8d4
Packit 1fb8d4
		if ((rdp_scancode == RDP_SCANCODE_CAPSLOCK) && (down == FALSE))
Packit 1fb8d4
		{
Packit 1fb8d4
			UINT32 syncFlags;
Packit 1fb8d4
			syncFlags = xf_keyboard_get_toggle_keys_state(xfc);
Packit 1fb8d4
			input->SynchronizeEvent(input, syncFlags);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int xf_keyboard_read_keyboard_state(xfContext* xfc)
Packit 1fb8d4
{
Packit 1fb8d4
	int dummy;
Packit 1fb8d4
	Window wdummy;
Packit 1fb8d4
	UINT32 state = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (!xfc->remote_app)
Packit 1fb8d4
	{
Packit 1fb8d4
		XQueryPointer(xfc->display, xfc->window->handle,
Packit 1fb8d4
		              &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		XQueryPointer(xfc->display, DefaultRootWindow(xfc->display),
Packit 1fb8d4
		              &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return state;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int xf_keyboard_get_keymask(xfContext* xfc, int keysym)
Packit 1fb8d4
{
Packit 1fb8d4
	int modifierpos, key, keysymMask = 0;
Packit 1fb8d4
	KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
Packit 1fb8d4
Packit 1fb8d4
	if (keycode == NoSymbol)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	for (modifierpos = 0; modifierpos < 8; modifierpos++)
Packit 1fb8d4
	{
Packit 1fb8d4
		int offset = xfc->modifierMap->max_keypermod * modifierpos;
Packit 1fb8d4
Packit 1fb8d4
		for (key = 0; key < xfc->modifierMap->max_keypermod; key++)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (xfc->modifierMap->modifiermap[offset + key] == keycode)
Packit 1fb8d4
			{
Packit 1fb8d4
				keysymMask |= 1 << modifierpos;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return keysymMask;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL xf_keyboard_get_key_state(xfContext* xfc, int state, int keysym)
Packit 1fb8d4
{
Packit 1fb8d4
	int keysymMask = xf_keyboard_get_keymask(xfc, keysym);
Packit 1fb8d4
Packit 1fb8d4
	if (!keysymMask)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return (state & keysymMask) ? TRUE : FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL xf_keyboard_set_key_state(xfContext* xfc, BOOL on, int keysym)
Packit 1fb8d4
{
Packit 1fb8d4
	int keysymMask;
Packit 1fb8d4
Packit 1fb8d4
	if (!xfc->xkbAvailable)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	keysymMask = xf_keyboard_get_keymask(xfc, keysym);
Packit 1fb8d4
Packit 1fb8d4
	if (!keysymMask)
Packit 1fb8d4
	{
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return XkbLockModifiers(xfc->display, XkbUseCoreKbd, keysymMask,
Packit 1fb8d4
	                        on ? keysymMask : 0);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
UINT32 xf_keyboard_get_toggle_keys_state(xfContext* xfc)
Packit 1fb8d4
{
Packit 1fb8d4
	int state;
Packit 1fb8d4
	UINT32 toggleKeysState = 0;
Packit 1fb8d4
	state = xf_keyboard_read_keyboard_state(xfc);
Packit 1fb8d4
Packit 1fb8d4
	if (xf_keyboard_get_key_state(xfc, state, XK_Scroll_Lock))
Packit 1fb8d4
		toggleKeysState |= KBD_SYNC_SCROLL_LOCK;
Packit 1fb8d4
Packit 1fb8d4
	if (xf_keyboard_get_key_state(xfc, state, XK_Num_Lock))
Packit 1fb8d4
		toggleKeysState |= KBD_SYNC_NUM_LOCK;
Packit 1fb8d4
Packit 1fb8d4
	if (xf_keyboard_get_key_state(xfc, state, XK_Caps_Lock))
Packit 1fb8d4
		toggleKeysState |= KBD_SYNC_CAPS_LOCK;
Packit 1fb8d4
Packit 1fb8d4
	if (xf_keyboard_get_key_state(xfc, state, XK_Kana_Lock))
Packit 1fb8d4
		toggleKeysState |= KBD_SYNC_KANA_LOCK;
Packit 1fb8d4
Packit 1fb8d4
	return toggleKeysState;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void xk_keyboard_update_modifier_keys(xfContext* xfc)
Packit 1fb8d4
{
Packit 1fb8d4
	int state;
Packit 1fb8d4
	size_t i;
Packit 1fb8d4
	KeyCode keycode;
Packit 1fb8d4
	int keysyms[] = {XK_Shift_L, XK_Shift_R, XK_Alt_L, XK_Alt_R,
Packit 1fb8d4
	                 XK_Control_L, XK_Control_R, XK_Super_L, XK_Super_R
Packit 1fb8d4
	                };
Packit 1fb8d4
	state = xf_keyboard_read_keyboard_state(xfc);
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < ARRAYSIZE(keysyms); i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (xf_keyboard_get_key_state(xfc, state, keysyms[i]))
Packit 1fb8d4
		{
Packit 1fb8d4
			keycode = XKeysymToKeycode(xfc->display, keysyms[i]);
Packit 1fb8d4
			xfc->KeyboardState[keycode] = TRUE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void xf_keyboard_focus_in(xfContext* xfc)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpInput* input;
Packit 1fb8d4
	UINT32 syncFlags, state;
Packit 1fb8d4
	Window w;
Packit 1fb8d4
	int d, x, y;
Packit 1fb8d4
Packit 1fb8d4
	if (!xfc->display || !xfc->window)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	input = xfc->context.input;
Packit 1fb8d4
	syncFlags = xf_keyboard_get_toggle_keys_state(xfc);
Packit 1fb8d4
	input->FocusInEvent(input, syncFlags);
Packit 1fb8d4
	xk_keyboard_update_modifier_keys(xfc);
Packit 1fb8d4
Packit 1fb8d4
	/* finish with a mouse pointer position like mstsc.exe if required */
Packit 1fb8d4
Packit 1fb8d4
	if (xfc->remote_app)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	if (XQueryPointer(xfc->display, xfc->window->handle, &w, &w, &d, &d, &x, &y,
Packit 1fb8d4
	                  &state))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (x >= 0 && x < xfc->window->width && y >= 0 && y < xfc->window->height)
Packit 1fb8d4
		{
Packit 1fb8d4
			xf_event_adjust_coordinates(xfc, &x, &y);
Packit 1fb8d4
			input->MouseEvent(input, PTR_FLAGS_MOVE, x, y);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int xf_keyboard_execute_action_script(xfContext* xfc,
Packit 1fb8d4
        XF_MODIFIER_KEYS* mod,
Packit 1fb8d4
        KeySym keysym)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
	int count;
Packit 1fb8d4
	int status = 1;
Packit 1fb8d4
	FILE* keyScript;
Packit 1fb8d4
	const char* keyStr;
Packit 1fb8d4
	BOOL match = FALSE;
Packit 1fb8d4
	char* keyCombination;
Packit 1fb8d4
	char buffer[1024] = { 0 };
Packit 1fb8d4
	char command[2048] = { 0 };
Packit 1fb8d4
	char combination[1024] = { 0 };
Packit 1fb8d4
Packit 1fb8d4
	if (!xfc->actionScriptExists)
Packit 1fb8d4
		return 1;
Packit 1fb8d4
Packit 1fb8d4
	if ((keysym == XK_Shift_L) || (keysym == XK_Shift_R) ||
Packit 1fb8d4
	    (keysym == XK_Alt_L) || (keysym == XK_Alt_R) ||
Packit 1fb8d4
	    (keysym == XK_Control_L) || (keysym == XK_Control_R))
Packit 1fb8d4
	{
Packit 1fb8d4
		return 1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	keyStr = XKeysymToString(keysym);
Packit 1fb8d4
Packit 1fb8d4
	if (keyStr == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		return 1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (mod->Shift)
Packit 1fb8d4
		strcat(combination, "Shift+");
Packit 1fb8d4
Packit 1fb8d4
	if (mod->Ctrl)
Packit 1fb8d4
		strcat(combination, "Ctrl+");
Packit 1fb8d4
Packit 1fb8d4
	if (mod->Alt)
Packit 1fb8d4
		strcat(combination, "Alt+");
Packit 1fb8d4
Packit 1fb8d4
	if (mod->Super)
Packit 1fb8d4
		strcat(combination, "Super+");
Packit 1fb8d4
Packit 1fb8d4
	strcat(combination, keyStr);
Packit 1fb8d4
	count = ArrayList_Count(xfc->keyCombinations);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < count; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		keyCombination = (char*) ArrayList_GetItem(xfc->keyCombinations, index);
Packit 1fb8d4
Packit 1fb8d4
		if (_stricmp(keyCombination, combination) == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			match = TRUE;
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!match)
Packit 1fb8d4
		return 1;
Packit 1fb8d4
Packit 1fb8d4
	sprintf_s(command, sizeof(command), "%s key %s",
Packit 1fb8d4
	          xfc->context.settings->ActionScript, combination);
Packit 1fb8d4
	keyScript = popen(command, "r");
Packit 1fb8d4
Packit 1fb8d4
	if (!keyScript)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	while (fgets(buffer, sizeof(buffer), keyScript) != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		strtok(buffer, "\n");
Packit 1fb8d4
Packit 1fb8d4
		if (strcmp(buffer, "key-local") == 0)
Packit 1fb8d4
			status = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (pclose(keyScript) == -1)
Packit 1fb8d4
		status = -1;
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int xk_keyboard_get_modifier_keys(xfContext* xfc, XF_MODIFIER_KEYS* mod)
Packit 1fb8d4
{
Packit 1fb8d4
	mod->LeftShift = xf_keyboard_key_pressed(xfc, XK_Shift_L);
Packit 1fb8d4
	mod->RightShift = xf_keyboard_key_pressed(xfc, XK_Shift_R);
Packit 1fb8d4
	mod->Shift = mod->LeftShift || mod->RightShift;
Packit 1fb8d4
	mod->LeftAlt = xf_keyboard_key_pressed(xfc, XK_Alt_L);
Packit 1fb8d4
	mod->RightAlt = xf_keyboard_key_pressed(xfc, XK_Alt_R);
Packit 1fb8d4
	mod->Alt = mod->LeftAlt || mod->RightAlt;
Packit 1fb8d4
	mod->LeftCtrl = xf_keyboard_key_pressed(xfc, XK_Control_L);
Packit 1fb8d4
	mod->RightCtrl = xf_keyboard_key_pressed(xfc, XK_Control_R);
Packit 1fb8d4
	mod->Ctrl = mod->LeftCtrl || mod->RightCtrl;
Packit 1fb8d4
	mod->LeftSuper = xf_keyboard_key_pressed(xfc, XK_Super_L);
Packit 1fb8d4
	mod->RightSuper = xf_keyboard_key_pressed(xfc, XK_Super_R);
Packit 1fb8d4
	mod->Super = mod->LeftSuper || mod->RightSuper;
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym)
Packit 1fb8d4
{
Packit 1fb8d4
	XF_MODIFIER_KEYS mod = { 0 };
Packit 1fb8d4
	xk_keyboard_get_modifier_keys(xfc, &mod);
Packit 1fb8d4
Packit 1fb8d4
	// remember state of RightCtrl to ungrab keyboard if next action is release of RightCtrl
Packit 1fb8d4
	// do not return anything such that the key could be used by client if ungrab is not the goal
Packit 1fb8d4
	if (keysym == XK_Control_R)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (mod.RightCtrl && firstPressRightCtrl)
Packit 1fb8d4
		{
Packit 1fb8d4
			// Right Ctrl is pressed, getting ready to ungrab
Packit 1fb8d4
			ungrabKeyboardWithRightCtrl = TRUE;
Packit 1fb8d4
			firstPressRightCtrl = FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		// some other key has been pressed, abort ungrabbing
Packit 1fb8d4
		if (ungrabKeyboardWithRightCtrl)
Packit 1fb8d4
			ungrabKeyboardWithRightCtrl = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!xf_keyboard_execute_action_script(xfc, &mod, keysym))
Packit 1fb8d4
	{
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!xfc->remote_app && xfc->fullscreen_toggle)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (keysym == XK_Return)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (mod.Ctrl && mod.Alt)
Packit 1fb8d4
			{
Packit 1fb8d4
				/* Ctrl-Alt-Enter: toggle full screen */
Packit 1fb8d4
				xf_toggle_fullscreen(xfc);
Packit 1fb8d4
				return TRUE;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((keysym == XK_c) || (keysym == XK_C))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (mod.Ctrl && mod.Alt)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* Ctrl-Alt-C: toggle control */
Packit 1fb8d4
			xf_toggle_control(xfc);
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#if 0 /* set to 1 to enable multi touch gesture simulation via keyboard */
Packit 1fb8d4
#ifdef WITH_XRENDER
Packit 1fb8d4
Packit 1fb8d4
	if (!xfc->remote_app && xfc->settings->MultiTouchGestures)
Packit 1fb8d4
	{
Packit 1fb8d4
		rdpContext* ctx = &xfc->context;
Packit 1fb8d4
Packit 1fb8d4
		if (mod.Ctrl && mod.Alt)
Packit 1fb8d4
		{
Packit 1fb8d4
			int pdx = 0;
Packit 1fb8d4
			int pdy = 0;
Packit 1fb8d4
			int zdx = 0;
Packit 1fb8d4
			int zdy = 0;
Packit 1fb8d4
Packit 1fb8d4
			switch (keysym)
Packit 1fb8d4
			{
Packit 1fb8d4
				case XK_0:	/* Ctrl-Alt-0: Reset scaling and panning */
Packit 1fb8d4
					xfc->scaledWidth = xfc->sessionWidth;
Packit 1fb8d4
					xfc->scaledHeight = xfc->sessionHeight;
Packit 1fb8d4
					xfc->offset_x = 0;
Packit 1fb8d4
					xfc->offset_y = 0;
Packit 1fb8d4
Packit 1fb8d4
					if (!xfc->fullscreen && (xfc->sessionWidth != xfc->window->width ||
Packit 1fb8d4
					                         xfc->sessionHeight != xfc->window->height))
Packit 1fb8d4
					{
Packit 1fb8d4
						xf_ResizeDesktopWindow(xfc, xfc->window, xfc->sessionWidth, xfc->sessionHeight);
Packit 1fb8d4
					}
Packit 1fb8d4
Packit 1fb8d4
					xf_draw_screen(xfc, 0, 0, xfc->sessionWidth, xfc->sessionHeight);
Packit 1fb8d4
					return TRUE;
Packit 1fb8d4
Packit 1fb8d4
				case XK_1:	/* Ctrl-Alt-1: Zoom in */
Packit 1fb8d4
					zdx = zdy = 10;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case XK_2:	/* Ctrl-Alt-2: Zoom out */
Packit 1fb8d4
					zdx = zdy = -10;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case XK_3:	/* Ctrl-Alt-3: Pan left */
Packit 1fb8d4
					pdx = -10;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case XK_4:	/* Ctrl-Alt-4: Pan right */
Packit 1fb8d4
					pdx = 10;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case XK_5:	/* Ctrl-Alt-5: Pan up */
Packit 1fb8d4
					pdy = -10;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case XK_6:	/* Ctrl-Alt-6: Pan up */
Packit 1fb8d4
					pdy = 10;
Packit 1fb8d4
					break;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (pdx != 0 || pdy != 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				PanningChangeEventArgs e;
Packit 1fb8d4
				EventArgsInit(&e, "xfreerdp");
Packit 1fb8d4
				e.dx = pdx;
Packit 1fb8d4
				e.dy = pdy;
Packit 1fb8d4
				PubSub_OnPanningChange(ctx->pubSub, xfc, &e);
Packit 1fb8d4
				return TRUE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (zdx != 0 || zdy != 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				ZoomingChangeEventArgs e;
Packit 1fb8d4
				EventArgsInit(&e, "xfreerdp");
Packit 1fb8d4
				e.dx = zdx;
Packit 1fb8d4
				e.dy = zdy;
Packit 1fb8d4
				PubSub_OnZoomingChange(ctx->pubSub, xfc, &e);
Packit 1fb8d4
				return TRUE;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif /* WITH_XRENDER defined */
Packit 1fb8d4
#endif /* pinch/zoom/pan simulation */
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void xf_keyboard_handle_special_keys_release(xfContext* xfc, KeySym keysym)
Packit 1fb8d4
{
Packit 1fb8d4
	if (keysym != XK_Control_R)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	firstPressRightCtrl = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (!ungrabKeyboardWithRightCtrl)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	// all requirements for ungrab are fulfilled, ungrabbing now
Packit 1fb8d4
	XF_MODIFIER_KEYS mod = { 0 };
Packit 1fb8d4
	xk_keyboard_get_modifier_keys(xfc, &mod);
Packit 1fb8d4
Packit 1fb8d4
	if (!mod.RightCtrl)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!xfc->fullscreen)
Packit 1fb8d4
		{
Packit 1fb8d4
			xf_toggle_control(xfc);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		xfc->mouse_active = FALSE;
Packit 1fb8d4
		XUngrabKeyboard(xfc->display, CurrentTime);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	// ungrabbed
Packit 1fb8d4
	ungrabKeyboardWithRightCtrl = FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL xf_keyboard_set_indicators(rdpContext* context, UINT16 led_flags)
Packit 1fb8d4
{
Packit 1fb8d4
	xfContext* xfc = (xfContext*) context;
Packit 1fb8d4
	xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_SCROLL_LOCK,
Packit 1fb8d4
	                          XK_Scroll_Lock);
Packit 1fb8d4
	xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_NUM_LOCK, XK_Num_Lock);
Packit 1fb8d4
	xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_CAPS_LOCK, XK_Caps_Lock);
Packit 1fb8d4
	xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_KANA_LOCK, XK_Kana_Lock);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL xf_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
Packit 1fb8d4
                                UINT32 imeConvMode)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!context)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	WLog_WARN(TAG,
Packit 1fb8d4
	          "KeyboardSetImeStatus(unitId=%04"PRIx16", imeState=%08"PRIx32", imeConvMode=%08"PRIx32") ignored",
Packit 1fb8d4
	          imeId, imeState, imeConvMode);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}