Fix changelog email address
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-kbd / libkbd.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * XKB-based Keyboard Mapping to Microsoft Keyboard System
4  *
5  * Copyright 2009 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 <freerdp/types.h>
24 #include <freerdp/kbd/kbd.h>
25
26 #include "libkbd.h"
27
28 #include <freerdp/kbd/locales.h>
29 #include <freerdp/kbd/vkcodes.h>
30 #include <freerdp/kbd/layouts.h>
31 #include "layouts_xkb.h"
32
33 /*
34  * The actual mapping from X keycodes to RDP keycodes, initialized from xkb keycodes or similar.
35  * Used directly by freerdp_kbd_get_scancode_by_keycode. The mapping is a global variable,
36  * but it only depends on which keycodes the X servers keyboard driver uses and is thus very static.
37  */
38
39 RdpScancodes x_keycode_to_rdp_scancode;
40
41 uint8 rdp_scancode_to_x_keycode[256][2];
42
43 #ifndef WITH_XKBFILE
44
45 static unsigned int detect_keyboard(void* dpy, unsigned int keyboardLayoutID, char* xkbfile, size_t xkbfilelength)
46 {
47         xkbfile[0] = '\0';
48
49         if (keyboardLayoutID != 0)
50                 DEBUG_KBD("keyboard layout configuration: %X", keyboardLayoutID);
51
52 #if defined(sun)
53         if (keyboardLayoutID == 0)
54         {
55                 keyboardLayoutID = detect_keyboard_type_and_layout_sunos(xkbfile, xkbfilelength);
56                 DEBUG_KBD("detect_keyboard_type_and_layout_sunos: %X %s", keyboardLayoutID, xkbfile);
57         }
58 #endif
59
60         if (keyboardLayoutID == 0)
61         {
62                 keyboardLayoutID = detect_keyboard_layout_from_locale();
63                 DEBUG_KBD("detect_keyboard_layout_from_locale: %X", keyboardLayoutID);
64         }
65
66         if (keyboardLayoutID == 0)
67         {
68                 keyboardLayoutID = 0x0409;
69                 DEBUG_KBD("using default keyboard layout: %X", keyboardLayoutID);
70         }
71
72         if (xkbfile[0] == '\0')
73         {
74                 strncpy(xkbfile, "base", xkbfilelength);
75                 DEBUG_KBD("using default keyboard layout: %s", xkbfile);
76         }
77
78         return keyboardLayoutID;
79 }
80
81 #endif
82
83 /*
84  * Initialize global keyboard mapping and return the suggested server side layout.
85  * dpy must be a X Display* or NULL.
86  */
87
88 unsigned int freerdp_kbd_init(void* dpy, unsigned int keyboard_layout_id)
89 {
90         memset(x_keycode_to_rdp_scancode, 0, sizeof(x_keycode_to_rdp_scancode));
91         memset(rdp_scancode_to_x_keycode, '\0', sizeof(rdp_scancode_to_x_keycode));
92
93 #ifdef WITH_XKBFILE
94         if (!init_xkb(dpy))
95         {
96                 DEBUG_KBD("Error initializing xkb");
97                 return 0;
98         }
99         if (keyboard_layout_id == 0)
100         {
101                 keyboard_layout_id = detect_keyboard_layout_from_xkb(dpy);
102                 DEBUG_KBD("detect_keyboard_layout_from_xkb: %X", keyboard_layout_id);
103         }
104         init_keycodes_from_xkb(dpy, x_keycode_to_rdp_scancode, rdp_scancode_to_x_keycode);
105 #else
106         int vkcode;
107         int keycode;
108         char xkbfile[256];
109         KeycodeToVkcode keycodeToVkcode;
110
111         if (keyboard_layout_id == 0)
112                 keyboard_layout_id = detect_keyboard(dpy, keyboard_layout_id, xkbfile, sizeof(xkbfile));
113
114         DEBUG_KBD("Using keyboard layout 0x%X with xkb name %s and xkbfile %s",
115                         keyboard_layout_id, get_layout_name(keyboard_layout_id), xkbfile);
116
117         load_keyboard_map(keycodeToVkcode, xkbfile);
118
119         for (keycode = 0; keycode < 256; keycode++)
120         {
121                 vkcode = keycodeToVkcode[keycode];
122
123                 DEBUG_KBD("X keycode %3d VK %3d %-19s-> RDP scancode %d/%d",
124                                 keycode, vkcode, virtualKeyboard[vkcode].name,
125                                 virtualKeyboard[vkcode].extended, virtualKeyboard[vkcode].scancode);
126
127                 x_keycode_to_rdp_scancode[keycode].keycode = virtualKeyboard[vkcode].scancode;
128                 x_keycode_to_rdp_scancode[keycode].extended = virtualKeyboard[vkcode].extended;
129                 x_keycode_to_rdp_scancode[keycode].keyname = virtualKeyboard[vkcode].name;
130
131                 if (x_keycode_to_rdp_scancode[keycode].extended)
132                         rdp_scancode_to_x_keycode[virtualKeyboard[vkcode].scancode][1] = keycode;
133                 else
134                         rdp_scancode_to_x_keycode[virtualKeyboard[vkcode].scancode][0] = keycode;
135         }
136 #endif
137
138         return keyboard_layout_id;
139 }
140
141 rdpKeyboardLayout* freerdp_kbd_get_layouts(int types)
142 {
143         return get_keyboard_layouts(types);
144 }
145
146 uint8 freerdp_kbd_get_scancode_by_keycode(uint8 keycode, boolean* extended)
147 {
148         DEBUG_KBD("%2x %4s -> %d/%d", keycode, x_keycode_to_rdp_scancode[keycode].keyname,
149                         x_keycode_to_rdp_scancode[keycode].extended, x_keycode_to_rdp_scancode[keycode].keycode);
150
151         *extended = x_keycode_to_rdp_scancode[keycode].extended;
152
153         return x_keycode_to_rdp_scancode[keycode].keycode;
154 }
155
156 uint8 freerdp_kbd_get_keycode_by_scancode(uint8 scancode, boolean extended)
157 {
158         if (extended)
159                 return rdp_scancode_to_x_keycode[scancode][1];
160         else
161                 return rdp_scancode_to_x_keycode[scancode][0];
162 }
163
164 uint8 freerdp_kbd_get_scancode_by_virtualkey(int vkcode, boolean* extended)
165 {
166         *extended = virtualKeyboard[vkcode].extended;
167         return virtualKeyboard[vkcode].scancode;
168 }