KeyboardImpl.cpp revision c2590a722c15520a45551ed7dc02d4831fb1a48e
77b1a2d8b5dbe2c0b5200794914239fee3c8ee5dvboxsync * VirtualBox COM class implementation
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Copyright (C) 2006-2012 Oracle Corporation
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * available from http://www.virtualbox.org. This file is free software;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync////////////////////////////////////////////////////////////////////////////////
9496f2d398b49813176939d7a339ae513d5175efvboxsync////////////////////////////////////////////////////////////////////////////////
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync/** @name Keyboard device capabilities bitfield
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /** The keyboard device does not wish to receive keystrokes. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /** The keyboard device does wishes to receive keystrokes. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Keyboard driver instance data.
a3369a746b56a8966dd78619f4d191c9662f400dvboxsync /** Pointer to the keyboard object. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** Pointer to the driver instance structure. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** Pointer to the keyboard port interface of the driver/device above us. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** Our keyboard connector interface. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** The capabilities of this device. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** Converts PDMIVMMDEVCONNECTOR pointer to a DRVMAINVMMDEV pointer. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#define PPDMIKEYBOARDCONNECTOR_2_MAINKEYBOARD(pInterface) ( (PDRVMAINKEYBOARD) ((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINKEYBOARD, IConnector)) )
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync// constructor / destructor
0abd77741a608f6c41c8dfcd4781b8b84adf1044vboxsync////////////////////////////////////////////////////////////////////////////////
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync// public methods
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync////////////////////////////////////////////////////////////////////////////////
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * Initializes the keyboard object.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @returns COM result indicator
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @param parent handle of our parent object
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* Enclose the state transition NotReady->InInit->Ready */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync /* Confirm a successful initialization */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Uninitializes the instance and sets the ready flag to FALSE.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Called either from FinalRelease() or by the parent when it gets destroyed.
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync /* Enclose the state transition Ready->InUninit->NotReady */
9496f2d398b49813176939d7a339ae513d5175efvboxsync for (unsigned i = 0; i < KEYBOARD_MAX_DEVICES; ++i)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Sends a scancode to the keyboard.
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @returns COM status code
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @param scancode The scancode to send
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync return PutScancodes(ComSafeArrayAsInParam(scancodes), NULL);
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * Sends a list of scancodes to the keyboard.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @returns COM status code
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @param scancodes Pointer to the first scancode
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @param count Number of scancodes
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @param codesStored Address of variable to store the number
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * of scancodes that were sent to the keyboard.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync This value can be NULL.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsyncSTDMETHODIMP Keyboard::PutScancodes(ComSafeArrayIn(LONG, scancodes),
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync if (FAILED(autoCaller.rc())) return autoCaller.rc();
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync com::SafeArray<LONG> keys(ComSafeArrayInArg(scancodes));
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync /* Send input to the last enabled device. Relies on the fact that
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * the USB keyboard is always initialized after the PS/2 keyboard.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync for (int i = KEYBOARD_MAX_DEVICES - 1; i >= 0 ; --i)
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (mpDrv[i] && (mpDrv[i]->u32DevCaps & KEYBOARD_DEVCAP_ENABLED))
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* No enabled keyboard - throw the input away. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync for (sent = 0; (sent < keys.size()) && RT_SUCCESS(vrc); sent++)
9496f2d398b49813176939d7a339ae513d5175efvboxsync vrc = pUpPort->pfnPutEvent(pUpPort, (uint8_t)keys[sent]);
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* Only signal the keys in the event which have been actually sent. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync memcpy(keysSent.raw(), keys.raw(), sent*sizeof(LONG));
9496f2d398b49813176939d7a339ae513d5175efvboxsync evDesc.init(mEventSource, VBoxEventType_OnGuestKeyboard, ComSafeArrayAsInParam(keys));
9496f2d398b49813176939d7a339ae513d5175efvboxsync tr("Could not send all scan codes to the virtual keyboard (%Rrc)"),
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Sends Control-Alt-Delete to the keyboard. This could be done otherwise
9496f2d398b49813176939d7a339ae513d5175efvboxsync * but it's so common that we'll be nice and supply a convenience API.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @returns COM status code
9496f2d398b49813176939d7a339ae513d5175efvboxsync return PutScancodes(ComSafeArrayAsInParam(cadSequence), NULL);
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Releases all currently held keys in the virtual keyboard.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @returns COM status code
9496f2d398b49813176939d7a339ae513d5175efvboxsync scancodes[0] = 0xFC; /* Magic scancode, see PS/2 and USB keyboard devices. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync return PutScancodes(ComSafeArrayAsInParam(scancodes), NULL);
9496f2d398b49813176939d7a339ae513d5175efvboxsyncSTDMETHODIMP Keyboard::COMGETTER(EventSource)(IEventSource ** aEventSource)
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (FAILED(autoCaller.rc())) return autoCaller.rc();
9496f2d398b49813176939d7a339ae513d5175efvboxsync // no need to lock - lifetime constant
9496f2d398b49813176939d7a339ae513d5175efvboxsync// private methods
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsyncDECLCALLBACK(void) Keyboard::keyboardLedStatusChange(PPDMIKEYBOARDCONNECTOR pInterface, PDMKEYBLEDS enmLeds)
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync PDRVMAINKEYBOARD pDrv = PPDMIKEYBOARDCONNECTOR_2_MAINKEYBOARD(pInterface);
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync pDrv->pKeyboard->getParent()->onKeyboardLedsChange(RT_BOOL(enmLeds & PDMKEYBLEDS_NUMLOCK),
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync * @interface_method_impl{PDMIKEYBOARDCONNECTOR,pfnSetActive}
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsyncDECLCALLBACK(void) Keyboard::keyboardSetActive(PPDMIKEYBOARDCONNECTOR pInterface, bool fActive)
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync PDRVMAINKEYBOARD pDrv = PPDMIKEYBOARDCONNECTOR_2_MAINKEYBOARD(pInterface);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsyncDECLCALLBACK(void *) Keyboard::drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync PDRVMAINKEYBOARD pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINKEYBOARD);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIKEYBOARDCONNECTOR, &pDrv->IConnector);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Destruct a keyboard driver instance.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * @returns VBox status.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * @param pDrvIns The driver instance data.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsyncDECLCALLBACK(void) Keyboard::drvDestruct(PPDMDRVINS pDrvIns)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync PDRVMAINKEYBOARD pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINKEYBOARD);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync LogFlow(("Keyboard::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync AutoWriteLock kbdLock(pThis->pKeyboard COMMA_LOCKVAL_SRC_POS);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync for (unsigned cDev = 0; cDev < KEYBOARD_MAX_DEVICES; ++cDev)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Construct a keyboard driver instance.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * @copydoc FNPDMDRVCONSTRUCT
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsyncDECLCALLBACK(int) Keyboard::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync PDRVMAINKEYBOARD pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINKEYBOARD);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync LogFlow(("Keyboard::drvConstruct: iInstance=%d\n", pDrvIns->iInstance));
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Validate configuration.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync ("Configuration error: Not possible to attach anything to this driver!\n"),
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pDrvIns->IBase.pfnQueryInterface = Keyboard::drvQueryInterface;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pThis->IConnector.pfnLedStatusChange = keyboardLedStatusChange;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pThis->IConnector.pfnSetActive = Keyboard::keyboardSetActive;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Get the IKeyboardPort interface of the above driver/device.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIKEYBOARDPORT);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync AssertMsgFailed(("Configuration error: No keyboard port interface above!\n"));
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Get the Keyboard object pointer and update the mpDrv member.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pThis->pKeyboard = (Keyboard *)pv; /** @todo Check this cast! */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync for (cDev = 0; cDev < KEYBOARD_MAX_DEVICES; ++cDev)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Keyboard driver registration record.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* u32Version */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* szName */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync "MainKeyboard",
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* szRCMod */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* szR0Mod */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* pszDescription */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync "Main keyboard driver (Main as in the API).",
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* fFlags */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* fClass. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* cMaxInstances */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* cbInstance */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* pfnConstruct */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* pfnDestruct */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* pfnRelocate */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* pfnIOCtl */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* pfnPowerOn */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* pfnReset */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* pfnSuspend */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* pfnResume */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* pfnAttach */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* pfnDetach */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* pfnPowerOff */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* pfnSoftReset */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* u32EndVersion */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync/* vi: set tabstop=4 shiftwidth=4 expandtab: */