VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/platform/nix/XKeyboard-new.cpp

Last change on this file was 106061, checked in by vboxsync, 41 hours ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.1 KB
Line 
1/* $Id: XKeyboard-new.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - Implementation of Linux-specific keyboard functions.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QString>
30#include <QStringList>
31
32/* GUI includes: */
33#include "UILoggingDefs.h"
34#include "XKeyboard.h"
35
36/* Other VBox includes: */
37#include "VBox/VBoxKeyboard.h"
38
39/* External includes: */
40#include <X11/XKBlib.h>
41#include <X11/keysym.h>
42
43
44/* VBoxKeyboard uses the deprecated XKeycodeToKeysym(3) API, but uses it safely. */
45#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
46
47static unsigned gfByLayoutOK = 1;
48static unsigned gfByTypeOK = 1;
49static unsigned gfByXkbOK = 1;
50
51/** Prints a key to the release log in the format needed for the Wine layout tables. */
52static void printKey(Display *pDisplay, int cKeys)
53{
54 bool fWasEscape = false;
55
56 for (int i = 0; i < 2; ++i)
57 {
58 int iKeySym = XKeycodeToKeysym(pDisplay, cKeys, i);
59
60 int iValue = iKeySym & 0xff;
61 if ('\\' == iValue)
62 {
63 LogRel(("\\\\"));
64 }
65 else if ('"' == iValue)
66 {
67 LogRel(("\\\""));
68 }
69 else if ((iValue > 32) && (iValue < 127))
70 {
71 if ( fWasEscape
72 && ( ((iValue >= '0') && (iValue <= '9'))
73 || ((iValue >= 'A') && (iValue <= 'F'))
74 || ((iValue >= 'a') && (iValue <= 'f'))))
75 {
76 LogRel(("\"\""));
77 }
78 LogRel(("%c", (char)iValue));
79 }
80 else
81 {
82 LogRel(("\\x%x", iValue));
83 fWasEscape = true;
84 }
85 }
86}
87
88/** Dumps the keyboard layout to the release log. */
89static void dumpLayout(Display *pDisplay)
90{
91 LogRel(("Your keyboard layout does not appear to be fully supported by\n"
92 "VirtualBox. If you are experiencing keyboard problems this.\n"
93 "information may help us to resolve them.\n"
94 "(Note: please tell us if you are using a custom layout.)\n\n"
95 "The correct table for your layout is:\n"));
96 /* First, build up a table of scan-to-key code mappings */
97 unsigned scanToKeycode[512] = { 0 };
98 int iMinKey, iMaxKey;
99 XDisplayKeycodes(pDisplay, &iMinKey, &iMaxKey);
100 for (int i = iMinKey; i < iMaxKey; ++i)
101 scanToKeycode[X11DRV_KeyEvent(pDisplay, i)] = i;
102 LogRel(("\""));
103 printKey(pDisplay, scanToKeycode[0x29]); /* `~ */
104 for (int i = 2; i <= 0xd; ++i) /* 1! - =+ */
105 {
106 LogRel(("\",\""));
107 printKey(pDisplay, scanToKeycode[i]);
108 }
109 LogRel(("\",\n"));
110 LogRel(("\""));
111 printKey(pDisplay, scanToKeycode[0x10]); /* qQ */
112 for (int i = 0x11; i <= 0x1b; ++i) /* wW - ]} */
113 {
114 LogRel(("\",\""));
115 printKey(pDisplay, scanToKeycode[i]);
116 }
117 LogRel(("\",\n"));
118 LogRel(("\""));
119 printKey(pDisplay, scanToKeycode[0x1e]); /* aA */
120 for (int i = 0x1f; i <= 0x28; ++i) /* sS - '" */
121 {
122 LogRel(("\",\""));
123 printKey(pDisplay, scanToKeycode[i]);
124 }
125 LogRel(("\",\""));
126 printKey(pDisplay, scanToKeycode[0x2b]); /* \| */
127 LogRel(("\",\n"));
128 LogRel(("\""));
129 printKey(pDisplay, scanToKeycode[0x2c]); /* zZ */
130 for (int i = 0x2d; i <= 0x35; ++i) /* xX - /? */
131 {
132 LogRel(("\",\""));
133 printKey(pDisplay, scanToKeycode[i]);
134 }
135 LogRel(("\",\""));
136 printKey(pDisplay, scanToKeycode[0x56]); /* The 102nd key */
137 LogRel(("\",\""));
138 printKey(pDisplay, scanToKeycode[0x73]); /* The Brazilian key */
139 LogRel(("\",\""));
140 printKey(pDisplay, scanToKeycode[0x7d]); /* The Yen key */
141 LogRel(("\"\n\n"));
142}
143
144/** Dumps the keyboard type tables to the release log. */
145static void dumpType(Display *pDisplay)
146{
147 LogRel(("Your keyboard type does not appear to be known to VirtualBox. If\n"
148 "you are experiencing keyboard problems this information may help us\n"
149 "to resolve them. Please also provide information about what type\n"
150 "of keyboard you have and whether you are using a remote X server or\n"
151 "something similar.\n\n"
152 "The tables for your keyboard are:\n"));
153 for (unsigned i = 0; i < 256; ++i)
154 {
155 LogRel(("0x%x", X11DRV_KeyEvent(pDisplay, i)));
156 if (i < 255)
157 LogRel((", "));
158 if (15 == (i % 16))
159 LogRel(("\n"));
160 }
161 LogRel(("and\n"));
162 LogRel(("NULL, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x,\n0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
163 XKeysymToKeycode(pDisplay, XK_Control_L),
164 XKeysymToKeycode(pDisplay, XK_Shift_L),
165 XKeysymToKeycode(pDisplay, XK_Caps_Lock),
166 XKeysymToKeycode(pDisplay, XK_Tab),
167 XKeysymToKeycode(pDisplay, XK_Escape),
168 XKeysymToKeycode(pDisplay, XK_Return),
169 XKeysymToKeycode(pDisplay, XK_Up),
170 XKeysymToKeycode(pDisplay, XK_Down),
171 XKeysymToKeycode(pDisplay, XK_Left),
172 XKeysymToKeycode(pDisplay, XK_Right),
173 XKeysymToKeycode(pDisplay, XK_F1),
174 XKeysymToKeycode(pDisplay, XK_F2),
175 XKeysymToKeycode(pDisplay, XK_F3),
176 XKeysymToKeycode(pDisplay, XK_F4),
177 XKeysymToKeycode(pDisplay, XK_F5),
178 XKeysymToKeycode(pDisplay, XK_F6),
179 XKeysymToKeycode(pDisplay, XK_F7),
180 XKeysymToKeycode(pDisplay, XK_F8)));
181}
182
183/** Builds a table mapping the X server's scan codes to PC keyboard scan codes.
184 * The logic of the function is that while the X server may be using a different
185 * set of scan codes (if for example it is running on a non-PC machine), the
186 * keyboard layout should be similar to a PC layout. So we look at the symbols
187 * attached to each key on the X server, find the PC layout which is closest to
188 * it and remember the mappings. */
189bool initXKeyboard(Display *pDisplay, int (*remapScancodes)[2])
190{
191 X11DRV_InitKeyboard(pDisplay, &gfByLayoutOK, &gfByTypeOK, &gfByXkbOK, remapScancodes);
192
193 /* It will almost always work to some extent.. */
194 return true;
195}
196
197void initMappedX11Keyboard(Display *pDisplay, const QString &remapScancodes)
198{
199 /* Initialize X11 keyboard including the remapping specified in the
200 * global property GUI/RemapScancodes. This property is a string of
201 * comma-separated x=y pairs, where x is the X11 keycode and y is the
202 * keyboard scancode that is emitted when the key attached to the X11
203 * keycode is pressed. */
204
205 int (*scancodes)[2] = NULL;
206 int (*scancodesTail)[2] = NULL;
207
208 if (remapScancodes != QString())
209 {
210 const QStringList tuples = remapScancodes.split(",", Qt::SkipEmptyParts);
211 scancodes = scancodesTail = new int [tuples.size()+1][2];
212 for (int i = 0; i < tuples.size(); ++i)
213 {
214 QStringList keyc2scan = tuples.at(i).split("=");
215 (*scancodesTail)[0] = keyc2scan.at(0).toUInt();
216 (*scancodesTail)[1] = keyc2scan.at(1).toUInt();
217 /* Do not advance on (ignore) identity mappings as this
218 * is the stop signal to initXKeyboard and friends: */
219 if ((*scancodesTail)[0] != (*scancodesTail)[1])
220 ++scancodesTail;
221 }
222 (*scancodesTail)[0] = (*scancodesTail)[1] = 0;
223 }
224
225 /* Initialize the X keyboard subsystem: */
226 initXKeyboard(pDisplay, scancodes);
227
228 if (scancodes)
229 delete scancodes;
230}
231
232unsigned handleXKeyEvent(Display *pDisplay, unsigned int iDetail)
233{
234 /* Call the WINE event handler: */
235 unsigned iKey = X11DRV_KeyEvent(pDisplay, iDetail);
236 LogRel3(("VBoxKeyboard: converting keycode %d to scancode %s0x%x\n",
237 iDetail, iKey > 0x100 ? "0xe0 " : "", iKey & 0xff));
238 return iKey;
239}
240
241void doXKeyboardLogging(Display *pDisplay)
242{
243 if (((1 == gfByTypeOK) || (1 == gfByXkbOK)) && (gfByLayoutOK != 1))
244 dumpLayout(pDisplay);
245 if (((1 == gfByLayoutOK) || (1 == gfByXkbOK)) && (gfByTypeOK != 1))
246 dumpType(pDisplay);
247 if ((gfByLayoutOK != 1) && (gfByTypeOK != 1) && (gfByXkbOK != 1))
248 {
249 LogRel(("Failed to recognize the keyboard mapping or to guess it based on\n"
250 "the keyboard layout. It is very likely that some keys will not\n"
251 "work correctly in the guest. If this is the case, please submit\n"
252 "a bug report, giving us information about your keyboard type,\n"
253 "its layout and other relevant information such as whether you\n"
254 "are using a remote X server or something similar. \n"));
255 unsigned *keyc2scan = X11DRV_getKeyc2scan();
256
257 LogRel(("The keycode-to-scancode table is: %d=%d",0,keyc2scan[0]));
258 for (int i = 1; i < 256; i++)
259 LogRel((",%d=%d",i,keyc2scan[i]));
260 LogRel(("\n"));
261 }
262 LogRel(("X Server details: vendor: %s, release: %d, protocol version: %d.%d, display string: %s\n",
263 ServerVendor(pDisplay), VendorRelease(pDisplay), ProtocolVersion(pDisplay),
264 ProtocolRevision(pDisplay), DisplayString(pDisplay)));
265 LogRel(("Using %s for keycode to scan code conversion\n",
266 gfByXkbOK ? "XKB"
267 : gfByTypeOK ? "known keycode mapping"
268 : "host keyboard layout detection"));
269}
270
271unsigned long wrapXkbKeycodeToKeysym(Display *pDisplay, unsigned char cCode,
272 unsigned int cGroup, unsigned int cIndex)
273{
274 KeySym cSym = XkbKeycodeToKeysym(pDisplay, cCode, cGroup, cIndex);
275 if (cSym != NoSymbol)
276 return cSym;
277 return XKeycodeToKeysym(pDisplay, cCode, cGroup * 2 + cIndex % 2);
278}
279
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette