FreeRDP/client/X11/xf_keyboard.c

420 lines
10 KiB
C

/**
* FreeRDP: A Remote Desktop Protocol Implementation
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/crt.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <freerdp/locale/keyboard.h>
#include "xf_keyboard.h"
void xf_kbd_init(xfContext* xfc)
{
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);
}
void xf_kbd_clear(xfContext* xfc)
{
ZeroMemory(xfc->pressed_keys, 256 * sizeof(BOOL));
}
void xf_kbd_set_keypress(xfContext* xfc, BYTE keycode, KeySym keysym)
{
if (keycode >= 8)
xfc->pressed_keys[keycode] = keysym;
else
return;
}
void xf_kbd_unset_keypress(xfContext* xfc, BYTE keycode)
{
if (keycode >= 8)
xfc->pressed_keys[keycode] = NoSymbol;
else
return;
}
void xf_kbd_release_all_keypress(xfContext* xfc)
{
int keycode;
DWORD rdp_scancode;
for (keycode = 0; keycode < ARRAYSIZE(xfc->pressed_keys); keycode++)
{
if (xfc->pressed_keys[keycode] != NoSymbol)
{
rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(keycode);
freerdp_input_send_keyboard_event_ex(xfc->instance->input, FALSE, rdp_scancode);
xfc->pressed_keys[keycode] = NoSymbol;
}
}
}
BOOL xf_kbd_key_pressed(xfContext* xfc, KeySym keysym)
{
KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
return (xfc->pressed_keys[keycode] == keysym);
}
void xf_kbd_send_key(xfContext* xfc, BOOL down, BYTE keycode)
{
DWORD rdp_scancode;
rdpInput* input;
input = xfc->instance->input;
rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(keycode);
if (rdp_scancode == RDP_SCANCODE_UNKNOWN)
{
fprintf(stderr, "Unknown key with X keycode 0x%02x\n", keycode);
}
else if (rdp_scancode == RDP_SCANCODE_PAUSE &&
!xf_kbd_key_pressed(xfc, XK_Control_L) && !xf_kbd_key_pressed(xfc, XK_Control_R))
{
/* Pause without Ctrl has to be sent as Ctrl + NumLock. */
if (down)
{
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);
}
}
else
{
freerdp_input_send_keyboard_event_ex(input, down, rdp_scancode);
if ((rdp_scancode == RDP_SCANCODE_CAPSLOCK) && (down == FALSE))
{
UINT32 syncFlags;
syncFlags = xf_kbd_get_toggle_keys_state(xfc);
input->SynchronizeEvent(input, syncFlags);
}
}
}
int xf_kbd_read_keyboard_state(xfContext* xfc)
{
int dummy;
Window wdummy;
UINT32 state = 0;
if (!xfc->remote_app)
{
XQueryPointer(xfc->display, xfc->window->handle,
&wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
}
else
{
XQueryPointer(xfc->display, DefaultRootWindow(xfc->display),
&wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
}
return state;
}
BOOL xf_kbd_get_key_state(xfContext* xfc, int state, int keysym)
{
int offset;
int modifierpos, key, keysymMask = 0;
KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
if (keycode == NoSymbol)
return FALSE;
for (modifierpos = 0; modifierpos < 8; modifierpos++)
{
offset = xfc->modifier_map->max_keypermod * modifierpos;
for (key = 0; key < xfc->modifier_map->max_keypermod; key++)
{
if (xfc->modifier_map->modifiermap[offset + key] == keycode)
{
keysymMask |= 1 << modifierpos;
}
}
}
return (state & keysymMask) ? TRUE : FALSE;
}
int xf_kbd_get_toggle_keys_state(xfContext* xfc)
{
int state;
int toggle_keys_state = 0;
state = xf_kbd_read_keyboard_state(xfc);
if (xf_kbd_get_key_state(xfc, state, XK_Scroll_Lock))
toggle_keys_state |= KBD_SYNC_SCROLL_LOCK;
if (xf_kbd_get_key_state(xfc, state, XK_Num_Lock))
toggle_keys_state |= KBD_SYNC_NUM_LOCK;
if (xf_kbd_get_key_state(xfc, state, XK_Caps_Lock))
toggle_keys_state |= KBD_SYNC_CAPS_LOCK;
if (xf_kbd_get_key_state(xfc, state, XK_Kana_Lock))
toggle_keys_state |= KBD_SYNC_KANA_LOCK;
return toggle_keys_state;
}
void xf_kbd_focus_in(xfContext* xfc)
{
rdpInput* input;
UINT32 syncFlags;
int dummy, mouseX, mouseY;
Window wdummy;
UINT32 state = 0;
if (xfc->display && xfc->window)
{
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);
input->FocusInEvent(input, syncFlags, mouseX, mouseY);
}
}
BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
{
if (keysym == XK_Return)
{
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)))
{
/* Ctrl-Alt-Enter: toggle full screen */
xf_toggle_fullscreen(xfc);
return TRUE;
}
}
if (keysym == XK_period)
{
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)))
{
//Zoom in (scale larger)
double s = xfc->settings->ScalingFactor;
s += 0.1;
if (s > 2.0)
s = 2.0;
xfc->settings->ScalingFactor = s;
xfc->currentWidth = xfc->originalWidth * s;
xfc->currentHeight = xfc->originalHeight * s;
xf_transform_window(xfc);
//IFCALL(xfi->client->OnResizeWindow, xfi->instance, xfi->currentWidth, xfi->currentHeight);
{
ResizeWindowEventArgs e;
EventArgsInit(&e, "xfreerdp");
e.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor;
e.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor;
PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e);
}
xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE);
return TRUE;
}
}
if (keysym == XK_comma)
{
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)))
{
//Zoom out (scale smaller)
double s = xfc->settings->ScalingFactor;
s -= 0.1;
if (s < 0.5)
s = 0.5;
xfc->settings->ScalingFactor = s;
xfc->currentWidth = xfc->originalWidth * s;
xfc->currentHeight = xfc->originalHeight * s;
xf_transform_window(xfc);
//IFCALL(xfi->client->OnResizeWindow, xfi->instance, xfi->currentWidth, xfi->currentHeight);
{
ResizeWindowEventArgs e;
EventArgsInit(&e, "xfreerdp");
e.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor;
e.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor;
PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e);
}
xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE);
return TRUE;
}
}
if (keysym == XK_KP_4)
{
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)))
{
/*
xfc->offset_x -= 5;
xf_transform_window(xfc);
xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE);
printf("pan left : %d\n", xfc->offset_x);
*/
//IFCALL(xfc->client->OnPan, xfi->instance, -5, 0);
{
PanningChangeEventArgs e;
EventArgsInit(&e, "xfreerdp");
e.XPan = -5;
e.YPan = 0;
PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e);
}
return TRUE;
}
}
if (keysym == XK_KP_6)
{
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)))
{
/*
xfi->offset_x += 5;
//if (xfi->offset_x > 0)
// xfi->offset_x = 0;
xf_transform_window(xfi);
xf_draw_screen_scaled(xfi, 0, 0, 0, 0, FALSE);
printf("pan right : %d\n", xfi->offset_x);
*/
//IFCALL(xfi->client->OnPan, xfi->instance, 5, 0);
{
PanningChangeEventArgs e;
EventArgsInit(&e, "xfreerdp");
e.XPan = 5;
e.YPan = 0;
PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e);
}
return TRUE;
}
}
if (keysym == XK_KP_8)
{
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)))
{
/*
xfi->offset_y -= 5;
xf_transform_window(xfi);
xf_draw_screen_scaled(xfi, 0, 0, 0, 0, FALSE);
printf("pan up : %d\n", xfi->offset_y);
*/
//IFCALL(xfi->client->OnPan, xfi->instance, 0, -5);
{
PanningChangeEventArgs e;
EventArgsInit(&e, "xfreerdp");
e.XPan = 0;
e.YPan = -5;
PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e);
}
return TRUE;
}
}
if (keysym == XK_KP_2)
{
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)))
{
/*
xfi->offset_y += 5;
//if (xfi->offset_y > 0)
//xfi->offset_y = 0;
xf_transform_window(xfi);
xf_draw_screen_scaled(xfi, 0, 0, 0, 0, FALSE);
printf("pan down : %d\n", xfi->offset_y);
*/
//IFCALL(xfi->client->OnPan, xfi->instance, 0, 5);
{
PanningChangeEventArgs e;
EventArgsInit(&e, "xfreerdp");
e.XPan = 0;
e.YPan = 5;
PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e);
}
return TRUE;
}
}
return FALSE;
}