Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / client / X11 / xf_keyboard.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * X11 Keyboard Handling
4  *
5  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25 #include <X11/keysym.h>
26
27 #include "xf_keyboard.h"
28
29 void xf_kbd_init(xfInfo* xfi)
30 {
31         memset(xfi->pressed_keys, 0, 256 * sizeof(boolean));
32         xfi->keyboard_layout_id = xfi->instance->settings->kbd_layout;
33         xfi->keyboard_layout_id = freerdp_kbd_init(xfi->display, xfi->keyboard_layout_id);
34         xfi->instance->settings->kbd_layout = xfi->keyboard_layout_id;
35 }
36
37 void xf_kbd_set_keypress(xfInfo* xfi, uint8 keycode, KeySym keysym)
38 {
39         if (keycode >= 8)
40                 xfi->pressed_keys[keycode] = keysym;
41         else
42                 return;
43 }
44
45 void xf_kbd_unset_keypress(xfInfo* xfi, uint8 keycode)
46 {
47         if (keycode >= 8)
48                 xfi->pressed_keys[keycode] = NoSymbol;
49         else
50                 return;
51 }
52
53 boolean xf_kbd_key_pressed(xfInfo* xfi, KeySym keysym)
54 {
55         KeyCode keycode = XKeysymToKeycode(xfi->display, keysym);
56         return (xfi->pressed_keys[keycode] == keysym);
57 }
58
59 void xf_kbd_send_key(xfInfo* xfi, boolean down, uint8 keycode)
60 {
61         uint16 flags;
62         uint8 scancode;
63         boolean extended;
64         rdpInput* input;
65
66         input = xfi->instance->input;
67         scancode = freerdp_kbd_get_scancode_by_keycode(keycode, &extended);
68
69         if (scancode == 0)
70         {
71                 /* unknown key */
72         }
73         else if ((scancode == 0x46) && extended &&
74                         !xf_kbd_key_pressed(xfi, XK_Control_L) && !xf_kbd_key_pressed(xfi, XK_Control_R))
75         {
76                 /* Pause without Ctrl has to be sent as Ctrl + NumLock. */
77                 if (down)
78                 {
79                         input->KeyboardEvent(input, KBD_FLAGS_DOWN, 0x1D); /* Ctrl down */
80                         input->KeyboardEvent(input, KBD_FLAGS_DOWN, 0x45); /* NumLock down */
81                         input->KeyboardEvent(input, KBD_FLAGS_RELEASE, 0x1D); /* Ctrl up */
82                         input->KeyboardEvent(input, KBD_FLAGS_RELEASE, 0x45); /* NumLock up */
83                 }
84         }
85         else
86         {
87                 flags = (extended) ? KBD_FLAGS_EXTENDED : 0;
88                 flags |= (down) ? KBD_FLAGS_DOWN : KBD_FLAGS_RELEASE;
89
90                 input->KeyboardEvent(input, flags, scancode);
91
92                 if ((scancode == 0x3A) && (down == false)) /* caps lock was released */
93                 {
94                         uint32 syncFlags;
95                         syncFlags = xf_kbd_get_toggle_keys_state(xfi);
96                         input->SynchronizeEvent(input, syncFlags);
97                 }
98         }
99 }
100
101 int xf_kbd_read_keyboard_state(xfInfo* xfi)
102 {
103         int dummy;
104         Window wdummy;
105         uint32 state = 0;
106
107         if (xfi->remote_app != true)
108         {
109                 XQueryPointer(xfi->display, xfi->window->handle,
110                         &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
111         }
112
113         return state;
114 }
115
116 boolean xf_kbd_get_key_state(xfInfo* xfi, int state, int keysym)
117 {
118         int offset;
119         int modifierpos, key, keysymMask = 0;
120         KeyCode keycode = XKeysymToKeycode(xfi->display, keysym);
121
122         if (keycode == NoSymbol)
123                 return false;
124
125         for (modifierpos = 0; modifierpos < 8; modifierpos++)
126         {
127                 offset = xfi->modifier_map->max_keypermod * modifierpos;
128                 for (key = 0; key < xfi->modifier_map->max_keypermod; key++)
129                 {
130                         if (xfi->modifier_map->modifiermap[offset + key] == keycode)
131                         {
132                                 keysymMask |= 1 << modifierpos;
133                         }
134                 }
135         }
136
137         return (state & keysymMask) ? true : false;
138 }
139
140 int xf_kbd_get_toggle_keys_state(xfInfo* xfi)
141 {
142         int state;
143         int toggle_keys_state = 0;
144
145         state = xf_kbd_read_keyboard_state(xfi);
146         if (xf_kbd_get_key_state(xfi, state, XK_Scroll_Lock))
147                 toggle_keys_state |= KBD_SYNC_SCROLL_LOCK;
148         if (xf_kbd_get_key_state(xfi, state, XK_Num_Lock))
149                 toggle_keys_state |= KBD_SYNC_NUM_LOCK;
150         if (xf_kbd_get_key_state(xfi, state, XK_Caps_Lock))
151                 toggle_keys_state |= KBD_SYNC_CAPS_LOCK;
152         if (xf_kbd_get_key_state(xfi, state, XK_Kana_Lock))
153                 toggle_keys_state |= KBD_SYNC_KANA_LOCK;
154
155         return toggle_keys_state;
156 }
157
158 void xf_kbd_focus_in(xfInfo* xfi)
159 {
160         rdpInput* input;
161         uint32 syncFlags;
162
163         input = xfi->instance->input;
164
165         /* on focus in send a tab up like mstsc.exe */
166         input->KeyboardEvent(input, KBD_FLAGS_RELEASE, 0x0F);
167
168         /* synchronize toggle keys */
169         syncFlags = xf_kbd_get_toggle_keys_state(xfi);
170         input->SynchronizeEvent(input, syncFlags);
171 }
172
173 boolean xf_kbd_handle_special_keys(xfInfo* xfi, KeySym keysym)
174 {
175         if (keysym == XK_Return)
176         {
177                 if ((xf_kbd_key_pressed(xfi, XK_Alt_L) || xf_kbd_key_pressed(xfi, XK_Alt_R))
178                     && (xf_kbd_key_pressed(xfi, XK_Control_L) || xf_kbd_key_pressed(xfi, XK_Control_R)))
179                 {
180                         /* Ctrl-Alt-Enter: toggle full screen */
181                         xf_toggle_fullscreen(xfi);
182                         return true;
183                 }
184         }
185
186         return false;
187 }
188