VirtualBox

source: vbox/trunk/src/VBox/Main/MouseImpl.cpp@ 3392

Last change on this file since 3392 was 3155, checked in by vboxsync, 17 years ago

Allow the VM to start with NULL framebuffer.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.9 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22#include "MouseImpl.h"
23#include "DisplayImpl.h"
24#include "VMMDev.h"
25
26#include "Logging.h"
27
28#include <VBox/pdm.h>
29#include <VBox/cfgm.h>
30#include <VBox/err.h>
31#include <iprt/asm.h>
32#include <VBox/VBoxDev.h>
33
34/**
35 * Mouse driver instance data.
36 */
37typedef struct DRVMAINMOUSE
38{
39 /** Pointer to the mouse object. */
40 Mouse *pMouse;
41 /** Pointer to the driver instance structure. */
42 PPDMDRVINS pDrvIns;
43 /** Pointer to the mouse port interface of the driver/device above us. */
44 PPDMIMOUSEPORT pUpPort;
45 /** Our mouse connector interface. */
46 PDMIMOUSECONNECTOR Connector;
47} DRVMAINMOUSE, *PDRVMAINMOUSE;
48
49/** Converts PDMIMOUSECONNECTOR pointer to a DRVMAINMOUSE pointer. */
50#define PDMIMOUSECONNECTOR_2_MAINMOUSE(pInterface) ( (PDRVMAINMOUSE) ((uintptr_t)pInterface - OFFSETOF(DRVMAINMOUSE, Connector)) )
51
52
53// constructor / destructor
54/////////////////////////////////////////////////////////////////////////////
55
56HRESULT Mouse::FinalConstruct()
57{
58 mParent = NULL;
59 mpDrv = NULL;
60 return S_OK;
61}
62
63void Mouse::FinalRelease()
64{
65 if (isReady())
66 uninit();
67}
68
69// public methods only for internal purposes
70/////////////////////////////////////////////////////////////////////////////
71
72/**
73 * Initializes the mouse object.
74 *
75 * @returns COM result indicator
76 * @param parent handle of our parent object
77 */
78HRESULT Mouse::init (Console *parent)
79{
80 LogFlow(("Mouse::init(): isReady=%d\n", isReady()));
81
82 ComAssertRet (parent, E_INVALIDARG);
83
84 AutoLock alock (this);
85 ComAssertRet (!isReady(), E_UNEXPECTED);
86
87 mParent = parent;
88
89#ifdef __L4ENV__
90 /* L4 console has no own mouse cursor */
91 uHostCaps = VMMDEV_MOUSEHOSTCANNOTHWPOINTER;
92#else
93 uHostCaps = 0;
94#endif
95
96 setReady (true);
97 return S_OK;
98}
99
100/**
101 * Uninitializes the instance and sets the ready flag to FALSE.
102 * Called either from FinalRelease() or by the parent when it gets destroyed.
103 */
104void Mouse::uninit()
105{
106 LogFlow(("Mouse::uninit(): isReady=%d\n", isReady()));
107
108 AutoLock alock (this);
109 AssertReturn (isReady(), (void) 0);
110
111 if (mpDrv)
112 mpDrv->pMouse = NULL;
113 mpDrv = NULL;
114
115 setReady (false);
116}
117
118// IMouse properties
119/////////////////////////////////////////////////////////////////////////////
120
121/**
122 * Returns whether the current setup can accept absolute mouse
123 * events.
124 *
125 * @returns COM status code
126 * @param absoluteSupported address of result variable
127 */
128STDMETHODIMP Mouse::COMGETTER(AbsoluteSupported) (BOOL *absoluteSupported)
129{
130 if (!absoluteSupported)
131 return E_POINTER;
132
133 AutoLock alock (this);
134 CHECK_READY();
135
136 CHECK_CONSOLE_DRV (mpDrv);
137
138 ComAssertRet (mParent->getVMMDev(), E_FAIL);
139 ComAssertRet (mParent->getVMMDev()->getVMMDevPort(), E_FAIL);
140
141 *absoluteSupported = FALSE;
142 uint32_t mouseCaps;
143 mParent->getVMMDev()->getVMMDevPort()->pfnQueryMouseCapabilities(mParent->getVMMDev()->getVMMDevPort(), &mouseCaps);
144 *absoluteSupported = mouseCaps & VMMDEV_MOUSEGUESTWANTSABS;
145 return S_OK;
146}
147
148/**
149 * Returns whether the current setup can accept relative mouse
150 * events.
151 *
152 * @returns COM status code
153 * @param absoluteSupported address of result variable
154 */
155STDMETHODIMP Mouse::COMGETTER(NeedsHostCursor) (BOOL *needsHostCursor)
156{
157 if (!needsHostCursor)
158 return E_POINTER;
159
160 AutoLock alock (this);
161 CHECK_READY();
162
163 CHECK_CONSOLE_DRV (mpDrv);
164
165 ComAssertRet (mParent->getVMMDev(), E_FAIL);
166 ComAssertRet (mParent->getVMMDev()->getVMMDevPort(), E_FAIL);
167
168 *needsHostCursor = FALSE;
169 uint32_t mouseCaps;
170 mParent->getVMMDev()->getVMMDevPort()->pfnQueryMouseCapabilities(mParent->getVMMDev()->getVMMDevPort(), &mouseCaps);
171 *needsHostCursor = mouseCaps & VMMDEV_MOUSEGUESTNEEDSHOSTCUR;
172 return S_OK;
173}
174
175// IMouse methods
176/////////////////////////////////////////////////////////////////////////////
177
178/**
179 * Send a mouse event.
180 *
181 * @returns COM status code
182 * @param dx X movement
183 * @param dy Y movement
184 * @param dz Z movement
185 * @param buttonState The mouse button state
186 */
187STDMETHODIMP Mouse::PutMouseEvent(LONG dx, LONG dy, LONG dz, LONG buttonState)
188{
189 AutoLock alock (this);
190 CHECK_READY();
191
192 CHECK_CONSOLE_DRV (mpDrv);
193
194 ComAssertRet (mParent->getVMMDev(), E_FAIL);
195 ComAssertRet (mParent->getVMMDev()->getVMMDevPort(), E_FAIL);
196
197 uint32_t mouseCaps;
198 mParent->getVMMDev()->getVMMDevPort()
199 ->pfnQueryMouseCapabilities(mParent->getVMMDev()->getVMMDevPort(),
200 &mouseCaps);
201 /*
202 * This method being called implies that the host no
203 * longer wants to use absolute coordinates. If the VMM
204 * device isn't aware of that yet, tell it.
205 */
206 if (mouseCaps & VMMDEV_MOUSEHOSTWANTSABS)
207 {
208 mParent->getVMMDev()->getVMMDevPort()
209 ->pfnSetMouseCapabilities(mParent->getVMMDev()->getVMMDevPort(), uHostCaps);
210 }
211
212 uint32_t fButtons = 0;
213 if (buttonState & MouseButtonState_LeftButton)
214 fButtons |= PDMIMOUSEPORT_BUTTON_LEFT;
215 if (buttonState & MouseButtonState_RightButton)
216 fButtons |= PDMIMOUSEPORT_BUTTON_RIGHT;
217 if (buttonState & MouseButtonState_MiddleButton)
218 fButtons |= PDMIMOUSEPORT_BUTTON_MIDDLE;
219
220 int vrc = mpDrv->pUpPort->pfnPutEvent(mpDrv->pUpPort, dx, dy, dz, fButtons);
221 if (VBOX_FAILURE (vrc))
222 return setError (E_FAIL,
223 tr ("Could not send the mouse event to the virtual mouse (%Vrc)"),
224 vrc);
225
226 return S_OK;
227}
228
229/**
230 * Send an absolute mouse event to the VM. This only works
231 * when the required guest support has been installed.
232 *
233 * @returns COM status code
234 * @param x X position (pixel)
235 * @param y Y position (pixel)
236 * @param dz Z movement
237 * @param buttonState The mouse button state
238 */
239STDMETHODIMP Mouse::PutMouseEventAbsolute(LONG x, LONG y, LONG dz,
240 LONG buttonState)
241{
242 AutoLock alock (this);
243 CHECK_READY();
244
245 CHECK_CONSOLE_DRV (mpDrv);
246
247 ComAssertRet (mParent->getVMMDev(), E_FAIL);
248 ComAssertRet (mParent->getVMMDev()->getVMMDevPort(), E_FAIL);
249
250 uint32_t mouseCaps;
251 mParent->getVMMDev()->getVMMDevPort()
252 ->pfnQueryMouseCapabilities(mParent->getVMMDev()->getVMMDevPort(),
253 &mouseCaps);
254 /*
255 * This method being called implies that the host wants
256 * to use absolute coordinates. If the VMM device isn't
257 * aware of that yet, tell it.
258 */
259 if (!(mouseCaps & VMMDEV_MOUSEHOSTWANTSABS))
260 {
261 mParent->getVMMDev()->getVMMDevPort()
262 ->pfnSetMouseCapabilities(mParent->getVMMDev()->getVMMDevPort(),
263 uHostCaps | VMMDEV_MOUSEHOSTWANTSABS);
264 }
265
266 Display *pDisplay = mParent->getDisplay();
267 ComAssertRet (pDisplay, E_FAIL);
268
269 ULONG displayWidth;
270 ULONG displayHeight;
271 HRESULT rc = pDisplay->COMGETTER(Width)(&displayWidth);
272 ComAssertComRCRet (rc, rc);
273 rc = pDisplay->COMGETTER(Height)(&displayHeight);
274 ComAssertComRCRet (rc, rc);
275
276 uint32_t mouseXAbs = displayWidth? (x * 0xFFFF) / displayWidth: 0;
277 uint32_t mouseYAbs = displayHeight? (y * 0xFFFF) / displayHeight: 0;
278
279 /*
280 * Send the absolute mouse position to the VMM device
281 */
282 int vrc = mParent->getVMMDev()->getVMMDevPort()
283 ->pfnSetAbsoluteMouse(mParent->getVMMDev()->getVMMDevPort(),
284 mouseXAbs, mouseYAbs);
285 ComAssertRCRet (vrc, E_FAIL);
286
287 // check if the guest actually wants absolute mouse positions
288 if (mouseCaps & VMMDEV_MOUSEGUESTWANTSABS)
289 {
290 uint32_t fButtons = 0;
291 if (buttonState & MouseButtonState_LeftButton)
292 fButtons |= PDMIMOUSEPORT_BUTTON_LEFT;
293 if (buttonState & MouseButtonState_RightButton)
294 fButtons |= PDMIMOUSEPORT_BUTTON_RIGHT;
295 if (buttonState & MouseButtonState_MiddleButton)
296 fButtons |= PDMIMOUSEPORT_BUTTON_MIDDLE;
297
298 vrc = mpDrv->pUpPort->pfnPutEvent(mpDrv->pUpPort, 1, 1, dz,
299 fButtons);
300 if (VBOX_FAILURE (vrc))
301 return setError (E_FAIL,
302 tr ("Could not send the mouse event to the virtual mouse (%Vrc)"),
303 vrc);
304 }
305
306 return S_OK;
307}
308
309// private methods
310/////////////////////////////////////////////////////////////////////////////
311
312/**
313 * Queries an interface to the driver.
314 *
315 * @returns Pointer to interface.
316 * @returns NULL if the interface was not supported by the driver.
317 * @param pInterface Pointer to this interface structure.
318 * @param enmInterface The requested interface identification.
319 */
320DECLCALLBACK(void *) Mouse::drvQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
321{
322 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
323 PDRVMAINMOUSE pDrv = PDMINS2DATA(pDrvIns, PDRVMAINMOUSE);
324 switch (enmInterface)
325 {
326 case PDMINTERFACE_BASE:
327 return &pDrvIns->IBase;
328 case PDMINTERFACE_MOUSE_CONNECTOR:
329 return &pDrv->Connector;
330 default:
331 return NULL;
332 }
333}
334
335
336/**
337 * Destruct a mouse driver instance.
338 *
339 * @returns VBox status.
340 * @param pDrvIns The driver instance data.
341 */
342DECLCALLBACK(void) Mouse::drvDestruct(PPDMDRVINS pDrvIns)
343{
344 PDRVMAINMOUSE pData = PDMINS2DATA(pDrvIns, PDRVMAINMOUSE);
345 LogFlow(("Mouse::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
346 if (pData->pMouse)
347 {
348 AutoLock mouseLock (pData->pMouse);
349 pData->pMouse->mpDrv = NULL;
350 }
351}
352
353
354/**
355 * Construct a mouse driver instance.
356 *
357 * @returns VBox status.
358 * @param pDrvIns The driver instance data.
359 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
360 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
361 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
362 * iInstance it's expected to be used a bit in this function.
363 */
364DECLCALLBACK(int) Mouse::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
365{
366 PDRVMAINMOUSE pData = PDMINS2DATA(pDrvIns, PDRVMAINMOUSE);
367 LogFlow(("drvMainMouse_Construct: iInstance=%d\n", pDrvIns->iInstance));
368
369 /*
370 * Validate configuration.
371 */
372 if (!CFGMR3AreValuesValid(pCfgHandle, "Object\0"))
373 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
374 PPDMIBASE pBaseIgnore;
375 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBaseIgnore);
376 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
377 {
378 AssertMsgFailed(("Configuration error: Not possible to attach anything to this driver!\n"));
379 return VERR_PDM_DRVINS_NO_ATTACH;
380 }
381
382 /*
383 * IBase.
384 */
385 pDrvIns->IBase.pfnQueryInterface = Mouse::drvQueryInterface;
386
387 /*
388 * Get the IMousePort interface of the above driver/device.
389 */
390 pData->pUpPort = (PPDMIMOUSEPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_MOUSE_PORT);
391 if (!pData->pUpPort)
392 {
393 AssertMsgFailed(("Configuration error: No mouse port interface above!\n"));
394 return VERR_PDM_MISSING_INTERFACE_ABOVE;
395 }
396
397 /*
398 * Get the Mouse object pointer and update the mpDrv member.
399 */
400 void *pv;
401 rc = CFGMR3QueryPtr(pCfgHandle, "Object", &pv);
402 if (VBOX_FAILURE(rc))
403 {
404 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Vrc\n", rc));
405 return rc;
406 }
407 pData->pMouse = (Mouse *)pv; /** @todo Check this cast! */
408 pData->pMouse->mpDrv = pData;
409
410 return VINF_SUCCESS;
411}
412
413
414/**
415 * Main mouse driver registration record.
416 */
417const PDMDRVREG Mouse::DrvReg =
418{
419 /* u32Version */
420 PDM_DRVREG_VERSION,
421 /* szDriverName */
422 "MainMouse",
423 /* pszDescription */
424 "Main mouse driver (Main as in the API).",
425 /* fFlags */
426 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
427 /* fClass. */
428 PDM_DRVREG_CLASS_MOUSE,
429 /* cMaxInstances */
430 ~0,
431 /* cbInstance */
432 sizeof(DRVMAINMOUSE),
433 /* pfnConstruct */
434 Mouse::drvConstruct,
435 /* pfnDestruct */
436 Mouse::drvDestruct,
437 /* pfnIOCtl */
438 NULL,
439 /* pfnPowerOn */
440 NULL,
441 /* pfnReset */
442 NULL,
443 /* pfnSuspend */
444 NULL,
445 /* pfnResume */
446 NULL,
447 /* pfnDetach */
448 NULL
449};
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