VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/KeyboardImpl.cpp@ 66891

Last change on this file since 66891 was 65120, checked in by vboxsync, 8 years ago

Main: doxygen fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.6 KB
Line 
1/* $Id: KeyboardImpl.cpp 65120 2017-01-04 17:10:35Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "KeyboardImpl.h"
19#include "ConsoleImpl.h"
20
21#include "AutoCaller.h"
22#include "Logging.h"
23
24#include <VBox/com/array.h>
25#include <VBox/vmm/pdmdrv.h>
26
27#include <iprt/asm.h>
28#include <iprt/cpp/utils.h>
29
30// defines
31////////////////////////////////////////////////////////////////////////////////
32
33// globals
34////////////////////////////////////////////////////////////////////////////////
35
36/** @name Keyboard device capabilities bitfield
37 * @{ */
38enum
39{
40 /** The keyboard device does not wish to receive keystrokes. */
41 KEYBOARD_DEVCAP_DISABLED = 0,
42 /** The keyboard device does wishes to receive keystrokes. */
43 KEYBOARD_DEVCAP_ENABLED = 1
44};
45
46/**
47 * Keyboard driver instance data.
48 */
49typedef struct DRVMAINKEYBOARD
50{
51 /** Pointer to the keyboard object. */
52 Keyboard *pKeyboard;
53 /** Pointer to the driver instance structure. */
54 PPDMDRVINS pDrvIns;
55 /** Pointer to the keyboard port interface of the driver/device above us. */
56 PPDMIKEYBOARDPORT pUpPort;
57 /** Our keyboard connector interface. */
58 PDMIKEYBOARDCONNECTOR IConnector;
59 /** The capabilities of this device. */
60 uint32_t u32DevCaps;
61} DRVMAINKEYBOARD, *PDRVMAINKEYBOARD;
62
63
64// constructor / destructor
65////////////////////////////////////////////////////////////////////////////////
66
67Keyboard::Keyboard()
68 : mParent(NULL)
69{
70}
71
72Keyboard::~Keyboard()
73{
74}
75
76HRESULT Keyboard::FinalConstruct()
77{
78 RT_ZERO(mpDrv);
79 mpVMMDev = NULL;
80 mfVMMDevInited = false;
81 menmLeds = PDMKEYBLEDS_NONE;
82 return BaseFinalConstruct();
83}
84
85void Keyboard::FinalRelease()
86{
87 uninit();
88 BaseFinalRelease();
89}
90
91// public methods
92////////////////////////////////////////////////////////////////////////////////
93
94/**
95 * Initializes the keyboard object.
96 *
97 * @returns COM result indicator
98 * @param aParent handle of our parent object
99 */
100HRESULT Keyboard::init(Console *aParent)
101{
102 LogFlowThisFunc(("aParent=%p\n", aParent));
103
104 ComAssertRet(aParent, E_INVALIDARG);
105
106 /* Enclose the state transition NotReady->InInit->Ready */
107 AutoInitSpan autoInitSpan(this);
108 AssertReturn(autoInitSpan.isOk(), E_FAIL);
109
110 unconst(mParent) = aParent;
111
112 unconst(mEventSource).createObject();
113 HRESULT rc = mEventSource->init();
114 AssertComRCReturnRC(rc);
115
116 /* Confirm a successful initialization */
117 autoInitSpan.setSucceeded();
118
119 return S_OK;
120}
121
122/**
123 * Uninitializes the instance and sets the ready flag to FALSE.
124 * Called either from FinalRelease() or by the parent when it gets destroyed.
125 */
126void Keyboard::uninit()
127{
128 LogFlowThisFunc(("\n"));
129
130 /* Enclose the state transition Ready->InUninit->NotReady */
131 AutoUninitSpan autoUninitSpan(this);
132 if (autoUninitSpan.uninitDone())
133 return;
134
135 for (unsigned i = 0; i < KEYBOARD_MAX_DEVICES; ++i)
136 {
137 if (mpDrv[i])
138 mpDrv[i]->pKeyboard = NULL;
139 mpDrv[i] = NULL;
140 }
141
142 mpVMMDev = NULL;
143 mfVMMDevInited = true;
144
145 menmLeds = PDMKEYBLEDS_NONE;
146
147 unconst(mParent) = NULL;
148 unconst(mEventSource).setNull();
149}
150
151/**
152 * Sends a scancode to the keyboard.
153 *
154 * @returns COM status code
155 * @param aScancode The scancode to send
156 */
157HRESULT Keyboard::putScancode(LONG aScancode)
158{
159 std::vector<LONG> scancodes;
160 scancodes.resize(1);
161 scancodes[0] = aScancode;
162 return putScancodes(scancodes, NULL);
163}
164
165/**
166 * Sends a list of scancodes to the keyboard.
167 *
168 * @returns COM status code
169 * @param aScancodes Pointer to the first scancode
170 * @param aCodesStored Address of variable to store the number
171 * of scancodes that were sent to the keyboard.
172 This value can be NULL.
173 */
174HRESULT Keyboard::putScancodes(const std::vector<LONG> &aScancodes,
175 ULONG *aCodesStored)
176{
177 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
178
179 CHECK_CONSOLE_DRV(mpDrv[0]);
180
181 /* Send input to the last enabled device. Relies on the fact that
182 * the USB keyboard is always initialized after the PS/2 keyboard.
183 */
184 PPDMIKEYBOARDPORT pUpPort = NULL;
185 for (int i = KEYBOARD_MAX_DEVICES - 1; i >= 0 ; --i)
186 {
187 if (mpDrv[i] && (mpDrv[i]->u32DevCaps & KEYBOARD_DEVCAP_ENABLED))
188 {
189 pUpPort = mpDrv[i]->pUpPort;
190 break;
191 }
192 }
193
194 /* No enabled keyboard - throw the input away. */
195 if (!pUpPort)
196 {
197 if (aCodesStored)
198 *aCodesStored = (uint32_t)aScancodes.size();
199 return S_OK;
200 }
201
202 int vrc = VINF_SUCCESS;
203
204 uint32_t sent;
205 for (sent = 0; (sent < aScancodes.size()) && RT_SUCCESS(vrc); ++sent)
206 vrc = pUpPort->pfnPutEventScan(pUpPort, (uint8_t)aScancodes[sent]);
207
208 if (aCodesStored)
209 *aCodesStored = sent;
210
211 com::SafeArray<LONG> keys(aScancodes.size());
212 for (size_t i = 0; i < aScancodes.size(); ++i)
213 keys[i] = aScancodes[i];
214
215 VBoxEventDesc evDesc;
216 evDesc.init(mEventSource, VBoxEventType_OnGuestKeyboard, ComSafeArrayAsInParam(keys));
217 evDesc.fire(0);
218
219 if (RT_FAILURE(vrc))
220 return setError(VBOX_E_IPRT_ERROR,
221 tr("Could not send all scan codes to the virtual keyboard (%Rrc)"),
222 vrc);
223
224 return S_OK;
225}
226
227/**
228 * Sends Control-Alt-Delete to the keyboard. This could be done otherwise
229 * but it's so common that we'll be nice and supply a convenience API.
230 *
231 * @returns COM status code
232 *
233 */
234HRESULT Keyboard::putCAD()
235{
236 std::vector<LONG> cadSequence;
237 cadSequence.resize(8);
238
239 cadSequence[0] = 0x1d; // Ctrl down
240 cadSequence[1] = 0x38; // Alt down
241 cadSequence[2] = 0xe0; // Del down 1
242 cadSequence[3] = 0x53; // Del down 2
243 cadSequence[4] = 0xe0; // Del up 1
244 cadSequence[5] = 0xd3; // Del up 2
245 cadSequence[6] = 0xb8; // Alt up
246 cadSequence[7] = 0x9d; // Ctrl up
247
248 return putScancodes(cadSequence, NULL);
249}
250
251/**
252 * Releases all currently held keys in the virtual keyboard.
253 *
254 * @returns COM status code
255 *
256 */
257HRESULT Keyboard::releaseKeys()
258{
259 std::vector<LONG> scancodes;
260 scancodes.resize(1);
261 scancodes[0] = 0xFC; /* Magic scancode, see PS/2 and USB keyboard devices. */
262 return putScancodes(scancodes, NULL);
263}
264
265HRESULT Keyboard::getKeyboardLEDs(std::vector<KeyboardLED_T> &aKeyboardLEDs)
266{
267 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
268
269 aKeyboardLEDs.resize(0);
270
271 if (menmLeds & PDMKEYBLEDS_NUMLOCK) aKeyboardLEDs.push_back(KeyboardLED_NumLock);
272 if (menmLeds & PDMKEYBLEDS_CAPSLOCK) aKeyboardLEDs.push_back(KeyboardLED_CapsLock);
273 if (menmLeds & PDMKEYBLEDS_SCROLLLOCK) aKeyboardLEDs.push_back(KeyboardLED_ScrollLock);
274
275 return S_OK;
276}
277
278HRESULT Keyboard::getEventSource(ComPtr<IEventSource> &aEventSource)
279{
280 // No need to lock - lifetime constant
281 mEventSource.queryInterfaceTo(aEventSource.asOutParam());
282
283 return S_OK;
284}
285
286//
287// private methods
288//
289void Keyboard::onKeyboardLedsChange(PDMKEYBLEDS enmLeds)
290{
291 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
292
293 /* Save the current status. */
294 menmLeds = enmLeds;
295
296 alock.release();
297
298 i_getParent()->i_onKeyboardLedsChange(RT_BOOL(enmLeds & PDMKEYBLEDS_NUMLOCK),
299 RT_BOOL(enmLeds & PDMKEYBLEDS_CAPSLOCK),
300 RT_BOOL(enmLeds & PDMKEYBLEDS_SCROLLLOCK));
301}
302
303DECLCALLBACK(void) Keyboard::i_keyboardLedStatusChange(PPDMIKEYBOARDCONNECTOR pInterface, PDMKEYBLEDS enmLeds)
304{
305 PDRVMAINKEYBOARD pDrv = RT_FROM_MEMBER(pInterface, DRVMAINKEYBOARD, IConnector);
306 pDrv->pKeyboard->onKeyboardLedsChange(enmLeds);
307}
308
309/**
310 * @interface_method_impl{PDMIKEYBOARDCONNECTOR,pfnSetActive}
311 */
312DECLCALLBACK(void) Keyboard::i_keyboardSetActive(PPDMIKEYBOARDCONNECTOR pInterface, bool fActive)
313{
314 PDRVMAINKEYBOARD pDrv = RT_FROM_MEMBER(pInterface, DRVMAINKEYBOARD, IConnector);
315 if (fActive)
316 pDrv->u32DevCaps |= KEYBOARD_DEVCAP_ENABLED;
317 else
318 pDrv->u32DevCaps &= ~KEYBOARD_DEVCAP_ENABLED;
319}
320
321
322/**
323 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
324 */
325DECLCALLBACK(void *) Keyboard::i_drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
326{
327 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
328 PDRVMAINKEYBOARD pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINKEYBOARD);
329
330 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
331 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIKEYBOARDCONNECTOR, &pDrv->IConnector);
332 return NULL;
333}
334
335
336/**
337 * Destruct a keyboard driver instance.
338 *
339 * @returns VBox status code.
340 * @param pDrvIns The driver instance data.
341 */
342DECLCALLBACK(void) Keyboard::i_drvDestruct(PPDMDRVINS pDrvIns)
343{
344 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
345 PDRVMAINKEYBOARD pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINKEYBOARD);
346 LogFlow(("Keyboard::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
347
348 if (pThis->pKeyboard)
349 {
350 AutoWriteLock kbdLock(pThis->pKeyboard COMMA_LOCKVAL_SRC_POS);
351 for (unsigned cDev = 0; cDev < KEYBOARD_MAX_DEVICES; ++cDev)
352 if (pThis->pKeyboard->mpDrv[cDev] == pThis)
353 {
354 pThis->pKeyboard->mpDrv[cDev] = NULL;
355 break;
356 }
357 pThis->pKeyboard->mpVMMDev = NULL;
358 }
359}
360
361/**
362 * Construct a keyboard driver instance.
363 *
364 * @copydoc FNPDMDRVCONSTRUCT
365 */
366DECLCALLBACK(int) Keyboard::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
367{
368 RT_NOREF(fFlags);
369 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
370 PDRVMAINKEYBOARD pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINKEYBOARD);
371 LogFlow(("Keyboard::drvConstruct: iInstance=%d\n", pDrvIns->iInstance));
372
373 /*
374 * Validate configuration.
375 */
376 if (!CFGMR3AreValuesValid(pCfg, "Object\0"))
377 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
378 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
379 ("Configuration error: Not possible to attach anything to this driver!\n"),
380 VERR_PDM_DRVINS_NO_ATTACH);
381
382 /*
383 * IBase.
384 */
385 pDrvIns->IBase.pfnQueryInterface = Keyboard::i_drvQueryInterface;
386
387 pThis->IConnector.pfnLedStatusChange = i_keyboardLedStatusChange;
388 pThis->IConnector.pfnSetActive = Keyboard::i_keyboardSetActive;
389
390 /*
391 * Get the IKeyboardPort interface of the above driver/device.
392 */
393 pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIKEYBOARDPORT);
394 if (!pThis->pUpPort)
395 {
396 AssertMsgFailed(("Configuration error: No keyboard port interface above!\n"));
397 return VERR_PDM_MISSING_INTERFACE_ABOVE;
398 }
399
400 /*
401 * Get the Keyboard object pointer and update the mpDrv member.
402 */
403 void *pv;
404 int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
405 if (RT_FAILURE(rc))
406 {
407 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
408 return rc;
409 }
410 pThis->pKeyboard = (Keyboard *)pv; /** @todo Check this cast! */
411 unsigned cDev;
412 for (cDev = 0; cDev < KEYBOARD_MAX_DEVICES; ++cDev)
413 if (!pThis->pKeyboard->mpDrv[cDev])
414 {
415 pThis->pKeyboard->mpDrv[cDev] = pThis;
416 break;
417 }
418 if (cDev == KEYBOARD_MAX_DEVICES)
419 return VERR_NO_MORE_HANDLES;
420
421 return VINF_SUCCESS;
422}
423
424
425/**
426 * Keyboard driver registration record.
427 */
428const PDMDRVREG Keyboard::DrvReg =
429{
430 /* u32Version */
431 PDM_DRVREG_VERSION,
432 /* szName */
433 "MainKeyboard",
434 /* szRCMod */
435 "",
436 /* szR0Mod */
437 "",
438 /* pszDescription */
439 "Main keyboard driver (Main as in the API).",
440 /* fFlags */
441 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
442 /* fClass. */
443 PDM_DRVREG_CLASS_KEYBOARD,
444 /* cMaxInstances */
445 ~0U,
446 /* cbInstance */
447 sizeof(DRVMAINKEYBOARD),
448 /* pfnConstruct */
449 Keyboard::i_drvConstruct,
450 /* pfnDestruct */
451 Keyboard::i_drvDestruct,
452 /* pfnRelocate */
453 NULL,
454 /* pfnIOCtl */
455 NULL,
456 /* pfnPowerOn */
457 NULL,
458 /* pfnReset */
459 NULL,
460 /* pfnSuspend */
461 NULL,
462 /* pfnResume */
463 NULL,
464 /* pfnAttach */
465 NULL,
466 /* pfnDetach */
467 NULL,
468 /* pfnPowerOff */
469 NULL,
470 /* pfnSoftReset */
471 NULL,
472 /* u32EndVersion */
473 PDM_DRVREG_VERSION
474};
475/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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