VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBFE/Keyboard.cpp

Last change on this file was 99890, checked in by vboxsync, 14 months ago

FE/VBoxBFE: Some crude keyboard implementation for some input support inside the guest for now, bugref:10397

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.6 KB
Line 
1/* $Id: Keyboard.cpp 99890 2023-05-22 10:40:30Z vboxsync $ */
2/** @file
3 * VBox frontends: Basic Frontend (BFE):
4 * Keyboard class implementation
5 */
6
7/*
8 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
9 *
10 * This file is part of VirtualBox base platform packages, as
11 * available from https://www.virtualbox.org.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation, in version 3 of the
16 * License.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see <https://www.gnu.org/licenses>.
25 *
26 * SPDX-License-Identifier: GPL-3.0-only
27 */
28
29#define LOG_GROUP LOG_GROUP_MAIN_KEYBOARD
30#include "Keyboard.h"
31
32#include <iprt/semaphore.h>
33#include <iprt/thread.h>
34#include <iprt/asm.h>
35#include <iprt/time.h>
36#include <iprt/cpp/utils.h>
37#include <iprt/alloca.h>
38#include <iprt/uuid.h>
39
40#include <VBox/vmm/vmmr3vtable.h>
41#include <VBox/vmm/pdmdrv.h>
42
43/**
44 * Keyboard device capabilities bitfield.
45 */
46enum
47{
48 /** The keyboard device does not wish to receive keystrokes. */
49 KEYBOARD_DEVCAP_DISABLED = 0,
50 /** The keyboard device does wishes to receive keystrokes. */
51 KEYBOARD_DEVCAP_ENABLED = 1
52};
53
54
55/**
56 * Keyboard driver instance data.
57 *
58 * @implements PDMIKEYBOARDCONNECTOR
59 */
60typedef struct DRVMAINKEYBOARD
61{
62 /** Pointer to the keyboard object. */
63 Keyboard *pKeyboard;
64 /** Pointer to the driver instance structure. */
65 PPDMDRVINS pDrvIns;
66 /** Pointer to the keyboard port interface of the driver/device above us. */
67 PPDMIKEYBOARDPORT pUpPort;
68 /** Our keyboard connector interface. */
69 PDMIKEYBOARDCONNECTOR IConnector;
70 /** The capabilities of this device. */
71 uint32_t u32DevCaps;
72} DRVMAINKEYBOARD, *PDRVMAINKEYBOARD;
73
74// constructor / destructor
75/////////////////////////////////////////////////////////////////////////////
76
77Keyboard::Keyboard()
78{
79}
80
81Keyboard::~Keyboard()
82{
83 if (mpDrv)
84 mpDrv->pKeyboard = NULL;
85
86 mpDrv = NULL;
87}
88
89
90// public methods only for internal purposes
91/////////////////////////////////////////////////////////////////////////////
92
93
94// private methods
95/////////////////////////////////////////////////////////////////////////////
96
97
98/**
99 * Sends a scancode to the keyboard.
100 *
101 * @returns COM status code
102 * @param aScancode The scancode to send
103 */
104int Keyboard::PutScancode(long aScancode)
105{
106 return PutScancodes(&aScancode, 1, NULL);
107}
108
109
110/**
111 * Sends a list of scancodes to the keyboard.
112 *
113 * @returns COM status code
114 * @param aScancodes Pointer to the first scancode
115 * @param aCodesStored Address of variable to store the number
116 * of scancodes that were sent to the keyboard.
117 This value can be NULL.
118 */
119int Keyboard::PutScancodes(const long *paScancodes,
120 uint32_t cScancodes,
121 unsigned long *aCodesStored)
122{
123 /* Send input to the last enabled device. */
124 PPDMIKEYBOARDPORT pUpPort = NULL;
125 if (mpDrv && (mpDrv->u32DevCaps & KEYBOARD_DEVCAP_ENABLED))
126 pUpPort = mpDrv->pUpPort;
127
128 /* No enabled keyboard - throw the input away. */
129 if (!pUpPort)
130 {
131 if (aCodesStored)
132 *aCodesStored = cScancodes;
133 return VINF_SUCCESS;
134 }
135
136 int vrc = VINF_SUCCESS;
137
138 uint32_t sent;
139 for (sent = 0; (sent < cScancodes) && RT_SUCCESS(vrc); ++sent)
140 vrc = pUpPort->pfnPutEventScan(pUpPort, (uint8_t)paScancodes[sent]);
141
142 if (aCodesStored)
143 *aCodesStored = sent;
144
145 return vrc;
146}
147
148int Keyboard::PutUsageCode(long aUsageCode, long aUsagePage, bool fKeyRelease)
149{
150 /* Send input to the last enabled device. Relies on the fact that
151 * the USB keyboard is always initialized after the PS/2 keyboard.
152 */
153 PPDMIKEYBOARDPORT pUpPort = NULL;
154 if (mpDrv && (mpDrv->u32DevCaps & KEYBOARD_DEVCAP_ENABLED))
155 pUpPort = mpDrv->pUpPort;
156
157 /* No enabled keyboard - throw the input away. */
158 if (!pUpPort)
159 return VINF_SUCCESS;
160
161 uint32_t idUsage = (uint16_t)aUsageCode | ((uint32_t)(uint8_t)aUsagePage << 16) | (fKeyRelease ? UINT32_C(0x80000000) : 0);
162 return pUpPort->pfnPutEventHid(pUpPort, idUsage);
163}
164
165
166/**
167 * Releases all currently held keys in the virtual keyboard.
168 *
169 * @returns COM status code
170 *
171 */
172int Keyboard::releaseKeys()
173{
174 /* Release all keys on the active keyboard in order to start with a clean slate.
175 * Note that this should mirror the logic in Keyboard::putScancodes() when choosing
176 * which keyboard to send the release event to.
177 */
178 PPDMIKEYBOARDPORT pUpPort = NULL;
179 if (mpDrv && (mpDrv->u32DevCaps & KEYBOARD_DEVCAP_ENABLED))
180 pUpPort = mpDrv->pUpPort;
181
182 if (pUpPort)
183 {
184 int vrc = pUpPort->pfnReleaseKeys(pUpPort);
185 if (RT_FAILURE(vrc))
186 AssertMsgFailed(("Failed to release keys on all keyboards! vrc=%Rrc\n", vrc));
187 }
188
189 return S_OK;
190}
191
192//
193// private methods
194//
195/*static*/ DECLCALLBACK(void) Keyboard::i_keyboardLedStatusChange(PPDMIKEYBOARDCONNECTOR pInterface, PDMKEYBLEDS enmLeds)
196{
197 RT_NOREF(pInterface, enmLeds);
198}
199
200/**
201 * @interface_method_impl{PDMIKEYBOARDCONNECTOR,pfnSetActive}
202 */
203DECLCALLBACK(void) Keyboard::i_keyboardSetActive(PPDMIKEYBOARDCONNECTOR pInterface, bool fActive)
204{
205 PDRVMAINKEYBOARD pDrv = RT_FROM_MEMBER(pInterface, DRVMAINKEYBOARD, IConnector);
206
207 if (fActive)
208 pDrv->u32DevCaps |= KEYBOARD_DEVCAP_ENABLED;
209 else
210 pDrv->u32DevCaps &= ~KEYBOARD_DEVCAP_ENABLED;
211}
212
213/**
214 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
215 */
216DECLCALLBACK(void *) Keyboard::i_drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
217{
218 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
219 PDRVMAINKEYBOARD pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINKEYBOARD);
220
221 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
222 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIKEYBOARDCONNECTOR, &pDrv->IConnector);
223 return NULL;
224}
225
226
227/**
228 * Destruct a display driver instance.
229 *
230 * @returns VBox status code.
231 * @param pDrvIns The driver instance data.
232 */
233DECLCALLBACK(void) Keyboard::i_drvDestruct(PPDMDRVINS pDrvIns)
234{
235 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
236 PDRVMAINKEYBOARD pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINKEYBOARD);
237 LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
238
239}
240
241
242/**
243 * Construct a display driver instance.
244 *
245 * @copydoc FNPDMDRVCONSTRUCT
246 */
247DECLCALLBACK(int) Keyboard::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
248{
249 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
250 RT_NOREF(fFlags, pCfg);
251 PDRVMAINKEYBOARD pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINKEYBOARD);
252 LogFlow(("Keyboard::drvConstruct: iInstance=%d\n", pDrvIns->iInstance));
253
254 /*
255 * Validate configuration.
256 */
257 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "", "");
258 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
259 ("Configuration error: Not possible to attach anything to this driver!\n"),
260 VERR_PDM_DRVINS_NO_ATTACH);
261
262 /*
263 * IBase.
264 */
265 pDrvIns->IBase.pfnQueryInterface = Keyboard::i_drvQueryInterface;
266
267 pThis->IConnector.pfnLedStatusChange = i_keyboardLedStatusChange;
268 pThis->IConnector.pfnSetActive = Keyboard::i_keyboardSetActive;
269
270 /*
271 * Get the IKeyboardPort interface of the above driver/device.
272 */
273 pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIKEYBOARDPORT);
274 if (!pThis->pUpPort)
275 {
276 AssertMsgFailed(("Configuration error: No keyboard port interface above!\n"));
277 return VERR_PDM_MISSING_INTERFACE_ABOVE;
278 }
279
280 /*
281 * Get the Keyboard object pointer and update the mpDrv member.
282 */
283 RTUUID UuidDisp;
284 RTUuidFromStr(&UuidDisp, KEYBOARD_OID);
285 Keyboard *pKeyboard = (Keyboard *)PDMDrvHlpQueryGenericUserObject(pDrvIns, &UuidDisp);
286 if (!pKeyboard)
287 {
288 AssertMsgFailed(("Configuration error: No/bad Keyboard object!\n"));
289 return VERR_NOT_FOUND;
290 }
291 pThis->pKeyboard = pKeyboard;
292 pThis->pKeyboard->mpDrv = pThis;
293
294#if 0
295 unsigned cDev;
296 for (cDev = 0; cDev < KEYBOARD_MAX_DEVICES; ++cDev)
297 if (!pThis->pKeyboard->mpDrv[cDev])
298 {
299 pThis->pKeyboard->mpDrv[cDev] = pThis;
300 break;
301 }
302 if (cDev == KEYBOARD_MAX_DEVICES)
303 return VERR_NO_MORE_HANDLES;
304#endif
305
306 return VINF_SUCCESS;
307}
308
309
310/**
311 * Display driver registration record.
312 */
313const PDMDRVREG Keyboard::DrvReg =
314{
315 /* u32Version */
316 PDM_DRVREG_VERSION,
317 /* szName */
318 "MainKeyboard",
319 /* szRCMod */
320 "",
321 /* szR0Mod */
322 "",
323 /* pszDescription */
324 "Main keyboard driver (Main as in the API).",
325 /* fFlags */
326 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
327 /* fClass. */
328 PDM_DRVREG_CLASS_KEYBOARD,
329 /* cMaxInstances */
330 ~0U,
331 /* cbInstance */
332 sizeof(DRVMAINKEYBOARD),
333 /* pfnConstruct */
334 Keyboard::i_drvConstruct,
335 /* pfnDestruct */
336 Keyboard::i_drvDestruct,
337 /* pfnRelocate */
338 NULL,
339 /* pfnIOCtl */
340 NULL,
341 /* pfnPowerOn */
342 NULL,
343 /* pfnReset */
344 NULL,
345 /* pfnSuspend */
346 NULL,
347 /* pfnResume */
348 NULL,
349 /* pfnAttach */
350 NULL,
351 /* pfnDetach */
352 NULL,
353 /* pfnPowerOff */
354 NULL,
355 /* pfnSoftReset */
356 NULL,
357 /* u32EndVersion */
358 PDM_DRVREG_VERSION
359};
360
361/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use