VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/platform/x11/XKeyboard-new.cpp@ 99825

Last change on this file since 99825 was 99825, checked in by vboxsync, 2 years ago

FE/Qt: bugref:10407. Adding an getter to UICommon to return display server type.

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

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