VirtualBox

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

Last change on this file was 103538, checked in by vboxsync, 3 months ago

FE/Qt: Moving out logging stuff from UIDefs.h to separate UILoggingDefs.h; This breaks dependency of UIDefs/UICommon headers from VBox/log.h

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.3 KB
Line 
1/* $Id: XKeyboard-new.cpp 103538 2024-02-22 17:06:26Z 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/* 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#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
211 QStringList tuples = remapScancodes.split(",", Qt::SkipEmptyParts);
212#else
213 QStringList tuples = remapScancodes.split(",", QString::SkipEmptyParts);
214#endif
215 scancodes = scancodesTail = new int [tuples.size()+1][2];
216 for (int i = 0; i < tuples.size(); ++i)
217 {
218 QStringList keyc2scan = tuples.at(i).split("=");
219 (*scancodesTail)[0] = keyc2scan.at(0).toUInt();
220 (*scancodesTail)[1] = keyc2scan.at(1).toUInt();
221 /* Do not advance on (ignore) identity mappings as this
222 * is the stop signal to initXKeyboard and friends: */
223 if ((*scancodesTail)[0] != (*scancodesTail)[1])
224 ++scancodesTail;
225 }
226 (*scancodesTail)[0] = (*scancodesTail)[1] = 0;
227 }
228
229 /* Initialize the X keyboard subsystem: */
230 initXKeyboard(pDisplay, scancodes);
231
232 if (scancodes)
233 delete scancodes;
234}
235
236unsigned handleXKeyEvent(Display *pDisplay, unsigned int iDetail)
237{
238 /* Call the WINE event handler: */
239 unsigned iKey = X11DRV_KeyEvent(pDisplay, iDetail);
240 LogRel3(("VBoxKeyboard: converting keycode %d to scancode %s0x%x\n",
241 iDetail, iKey > 0x100 ? "0xe0 " : "", iKey & 0xff));
242 return iKey;
243}
244
245void doXKeyboardLogging(Display *pDisplay)
246{
247 if (((1 == gfByTypeOK) || (1 == gfByXkbOK)) && (gfByLayoutOK != 1))
248 dumpLayout(pDisplay);
249 if (((1 == gfByLayoutOK) || (1 == gfByXkbOK)) && (gfByTypeOK != 1))
250 dumpType(pDisplay);
251 if ((gfByLayoutOK != 1) && (gfByTypeOK != 1) && (gfByXkbOK != 1))
252 {
253 LogRel(("Failed to recognize the keyboard mapping or to guess it based on\n"
254 "the keyboard layout. It is very likely that some keys will not\n"
255 "work correctly in the guest. If this is the case, please submit\n"
256 "a bug report, giving us information about your keyboard type,\n"
257 "its layout and other relevant information such as whether you\n"
258 "are using a remote X server or something similar. \n"));
259 unsigned *keyc2scan = X11DRV_getKeyc2scan();
260
261 LogRel(("The keycode-to-scancode table is: %d=%d",0,keyc2scan[0]));
262 for (int i = 1; i < 256; i++)
263 LogRel((",%d=%d",i,keyc2scan[i]));
264 LogRel(("\n"));
265 }
266 LogRel(("X Server details: vendor: %s, release: %d, protocol version: %d.%d, display string: %s\n",
267 ServerVendor(pDisplay), VendorRelease(pDisplay), ProtocolVersion(pDisplay),
268 ProtocolRevision(pDisplay), DisplayString(pDisplay)));
269 LogRel(("Using %s for keycode to scan code conversion\n",
270 gfByXkbOK ? "XKB"
271 : gfByTypeOK ? "known keycode mapping"
272 : "host keyboard layout detection"));
273}
274
275unsigned long wrapXkbKeycodeToKeysym(Display *pDisplay, unsigned char cCode,
276 unsigned int cGroup, unsigned int cIndex)
277{
278 KeySym cSym = XkbKeycodeToKeysym(pDisplay, cCode, cGroup, cIndex);
279 if (cSym != NoSymbol)
280 return cSym;
281 return XKeycodeToKeysym(pDisplay, cCode, cGroup * 2 + cIndex % 2);
282}
283
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use