VirtualBox

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

Last change on this file since 26548 was 26235, checked in by vboxsync, 15 years ago

Main: coding style

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.3 KB
Line 
1/* $Id: MouseImpl.cpp 26235 2010-02-04 13:55:00Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include "MouseImpl.h"
23#include "DisplayImpl.h"
24#include "VMMDev.h"
25
26#include "AutoCaller.h"
27#include "Logging.h"
28
29#include <VBox/pdmdrv.h>
30#include <iprt/asm.h>
31#include <VBox/VMMDev.h>
32
33/**
34 * Mouse driver instance data.
35 */
36typedef struct DRVMAINMOUSE
37{
38 /** Pointer to the mouse object. */
39 Mouse *pMouse;
40 /** Pointer to the driver instance structure. */
41 PPDMDRVINS pDrvIns;
42 /** Pointer to the mouse port interface of the driver/device above us. */
43 PPDMIMOUSEPORT pUpPort;
44 /** Our mouse connector interface. */
45 PDMIMOUSECONNECTOR IConnector;
46} DRVMAINMOUSE, *PDRVMAINMOUSE;
47
48
49
50// constructor / destructor
51/////////////////////////////////////////////////////////////////////////////
52
53DEFINE_EMPTY_CTOR_DTOR (Mouse)
54
55HRESULT Mouse::FinalConstruct()
56{
57 mpDrv = NULL;
58 mLastAbsX = 0;
59 mLastAbsY = 0;
60 return S_OK;
61}
62
63void Mouse::FinalRelease()
64{
65 uninit();
66}
67
68// public methods only for internal purposes
69/////////////////////////////////////////////////////////////////////////////
70
71/**
72 * Initializes the mouse object.
73 *
74 * @returns COM result indicator
75 * @param parent handle of our parent object
76 */
77HRESULT Mouse::init (Console *parent)
78{
79 LogFlowThisFunc(("\n"));
80
81 ComAssertRet(parent, E_INVALIDARG);
82
83 /* Enclose the state transition NotReady->InInit->Ready */
84 AutoInitSpan autoInitSpan(this);
85 AssertReturn(autoInitSpan.isOk(), E_FAIL);
86
87 unconst(mParent) = parent;
88
89#ifdef RT_OS_L4
90 /* L4 console has no own mouse cursor */
91 uHostCaps = VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER;
92#else
93 uHostCaps = 0;
94#endif
95
96 /* Confirm a successful initialization */
97 autoInitSpan.setSucceeded();
98
99 return S_OK;
100}
101
102/**
103 * Uninitializes the instance and sets the ready flag to FALSE.
104 * Called either from FinalRelease() or by the parent when it gets destroyed.
105 */
106void Mouse::uninit()
107{
108 LogFlowThisFunc(("\n"));
109
110 /* Enclose the state transition Ready->InUninit->NotReady */
111 AutoUninitSpan autoUninitSpan(this);
112 if (autoUninitSpan.uninitDone())
113 return;
114
115 if (mpDrv)
116 mpDrv->pMouse = NULL;
117 mpDrv = NULL;
118
119 unconst(mParent).setNull();
120}
121
122// IMouse properties
123/////////////////////////////////////////////////////////////////////////////
124
125/**
126 * Returns whether the current setup can accept absolute mouse
127 * events.
128 *
129 * @returns COM status code
130 * @param absoluteSupported address of result variable
131 */
132STDMETHODIMP Mouse::COMGETTER(AbsoluteSupported) (BOOL *absoluteSupported)
133{
134 if (!absoluteSupported)
135 return E_POINTER;
136
137 AutoCaller autoCaller(this);
138 if (FAILED(autoCaller.rc())) return autoCaller.rc();
139
140 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
141
142 CHECK_CONSOLE_DRV (mpDrv);
143
144 ComAssertRet(mParent->getVMMDev(), E_FAIL);
145 ComAssertRet(mParent->getVMMDev()->getVMMDevPort(), E_FAIL);
146
147 *absoluteSupported = FALSE;
148 uint32_t mouseCaps;
149 mParent->getVMMDev()->getVMMDevPort()->pfnQueryMouseCapabilities(mParent->getVMMDev()->getVMMDevPort(), &mouseCaps);
150 *absoluteSupported = mouseCaps & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE;
151
152 return S_OK;
153}
154
155/**
156 * Returns whether the current setup can accept relative mouse
157 * events.
158 *
159 * @returns COM status code
160 * @param absoluteSupported address of result variable
161 */
162STDMETHODIMP Mouse::COMGETTER(NeedsHostCursor) (BOOL *needsHostCursor)
163{
164 if (!needsHostCursor)
165 return E_POINTER;
166
167 AutoCaller autoCaller(this);
168 if (FAILED(autoCaller.rc())) return autoCaller.rc();
169
170 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
171
172 CHECK_CONSOLE_DRV (mpDrv);
173
174 ComAssertRet(mParent->getVMMDev(), E_FAIL);
175 ComAssertRet(mParent->getVMMDev()->getVMMDevPort(), E_FAIL);
176
177 *needsHostCursor = FALSE;
178 uint32_t mouseCaps;
179 mParent->getVMMDev()->getVMMDevPort()->pfnQueryMouseCapabilities(mParent->getVMMDev()->getVMMDevPort(), &mouseCaps);
180 *needsHostCursor = mouseCaps & VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR;
181
182 return S_OK;
183}
184
185// IMouse methods
186/////////////////////////////////////////////////////////////////////////////
187
188/**
189 * Send a mouse event.
190 *
191 * @returns COM status code
192 * @param dx X movement
193 * @param dy Y movement
194 * @param dz Z movement
195 * @param buttonState The mouse button state
196 */
197STDMETHODIMP Mouse::PutMouseEvent(LONG dx, LONG dy, LONG dz, LONG dw, LONG buttonState)
198{
199 HRESULT rc = S_OK;
200
201 AutoCaller autoCaller(this);
202 if (FAILED(autoCaller.rc())) return autoCaller.rc();
203
204 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
205
206 CHECK_CONSOLE_DRV (mpDrv);
207
208 ComAssertRet(mParent->getVMMDev(), E_FAIL);
209 ComAssertRet(mParent->getVMMDev()->getVMMDevPort(), E_FAIL);
210
211 uint32_t mouseCaps;
212 LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d\n", __PRETTY_FUNCTION__,
213 dx, dy, dz, dw));
214 mParent->getVMMDev()->getVMMDevPort()
215 ->pfnQueryMouseCapabilities(mParent->getVMMDev()->getVMMDevPort(),
216 &mouseCaps);
217 /*
218 * This method being called implies that the host no
219 * longer wants to use absolute coordinates. If the VMM
220 * device isn't aware of that yet, tell it.
221 */
222 if (mouseCaps & VMMDEV_MOUSE_HOST_CAN_ABSOLUTE)
223 {
224 mParent->getVMMDev()->getVMMDevPort()->pfnSetMouseCapabilities(
225 mParent->getVMMDev()->getVMMDevPort(), uHostCaps);
226 }
227
228 uint32_t fButtons = 0;
229 if (buttonState & MouseButtonState_LeftButton)
230 fButtons |= PDMIMOUSEPORT_BUTTON_LEFT;
231 if (buttonState & MouseButtonState_RightButton)
232 fButtons |= PDMIMOUSEPORT_BUTTON_RIGHT;
233 if (buttonState & MouseButtonState_MiddleButton)
234 fButtons |= PDMIMOUSEPORT_BUTTON_MIDDLE;
235 if (buttonState & MouseButtonState_XButton1)
236 fButtons |= PDMIMOUSEPORT_BUTTON_X1;
237 if (buttonState & MouseButtonState_XButton2)
238 fButtons |= PDMIMOUSEPORT_BUTTON_X2;
239
240 int vrc = mpDrv->pUpPort->pfnPutEvent(mpDrv->pUpPort, dx, dy, dz, dw, fButtons);
241 if (RT_FAILURE(vrc))
242 rc = setError(VBOX_E_IPRT_ERROR,
243 tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
244 vrc);
245
246 return rc;
247}
248
249/**
250 * Send an absolute mouse event to the VM. This only works
251 * when the required guest support has been installed.
252 *
253 * @returns COM status code
254 * @param x X position (pixel)
255 * @param y Y position (pixel)
256 * @param dz Z movement
257 * @param buttonState The mouse button state
258 */
259STDMETHODIMP Mouse::PutMouseEventAbsolute(LONG x, LONG y, LONG dz, LONG dw,
260 LONG buttonState)
261{
262 HRESULT rc = S_OK;
263
264 AutoCaller autoCaller(this);
265 if (FAILED(autoCaller.rc())) return autoCaller.rc();
266
267 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
268
269 CHECK_CONSOLE_DRV (mpDrv);
270
271 ComAssertRet(mParent->getVMMDev(), E_FAIL);
272 ComAssertRet(mParent->getVMMDev()->getVMMDevPort(), E_FAIL);
273
274 uint32_t mouseCaps;
275 LogRel3(("%s: x=%d, y=%d, dz=%d, dw=%d\n", __PRETTY_FUNCTION__,
276 x, y, dz, dw));
277 mParent->getVMMDev()->getVMMDevPort()
278 ->pfnQueryMouseCapabilities(mParent->getVMMDev()->getVMMDevPort(),
279 &mouseCaps);
280 /*
281 * This method being called implies that the host wants
282 * to use absolute coordinates. If the VMM device isn't
283 * aware of that yet, tell it.
284 */
285 if (!(mouseCaps & VMMDEV_MOUSE_HOST_CAN_ABSOLUTE))
286 {
287 mParent->getVMMDev()->getVMMDevPort()->pfnSetMouseCapabilities(
288 mParent->getVMMDev()->getVMMDevPort(),
289 uHostCaps | VMMDEV_MOUSE_HOST_CAN_ABSOLUTE);
290 }
291
292 Display *pDisplay = mParent->getDisplay();
293 ComAssertRet(pDisplay, E_FAIL);
294
295 ULONG displayWidth;
296 ULONG displayHeight;
297 rc = pDisplay->COMGETTER(Width)(&displayWidth);
298 ComAssertComRCRet(rc, rc);
299 rc = pDisplay->COMGETTER(Height)(&displayHeight);
300 ComAssertComRCRet(rc, rc);
301
302 uint32_t mouseXAbs = displayWidth? (x * 0xFFFF) / displayWidth: 0;
303 uint32_t mouseYAbs = displayHeight? (y * 0xFFFF) / displayHeight: 0;
304
305 /*
306 * Send the absolute mouse position to the VMM device.
307 */
308 int vrc = mParent->getVMMDev()->getVMMDevPort()
309 ->pfnSetAbsoluteMouse(mParent->getVMMDev()->getVMMDevPort(),
310 mouseXAbs, mouseYAbs);
311 ComAssertRCRet (vrc, E_FAIL);
312
313 // Check if the guest actually wants absolute mouse positions.
314 if (mouseCaps & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE)
315 {
316 uint32_t fButtons = 0;
317 if (buttonState & MouseButtonState_LeftButton)
318 fButtons |= PDMIMOUSEPORT_BUTTON_LEFT;
319 if (buttonState & MouseButtonState_RightButton)
320 fButtons |= PDMIMOUSEPORT_BUTTON_RIGHT;
321 if (buttonState & MouseButtonState_MiddleButton)
322 fButtons |= PDMIMOUSEPORT_BUTTON_MIDDLE;
323 if (buttonState & MouseButtonState_XButton1)
324 fButtons |= PDMIMOUSEPORT_BUTTON_X1;
325 if (buttonState & MouseButtonState_XButton2)
326 fButtons |= PDMIMOUSEPORT_BUTTON_X2;
327
328 /* This is a workaround. In order to alert the Guest Additions to the
329 * fact that the absolute pointer position has changed, we send a
330 * a minute movement event to the PS/2 mouse device. But in order
331 * to avoid the mouse jiggling every time the use clicks, we check to
332 * see if the position has really changed since the last mouse event.
333 */
334 if ( ((mLastAbsX == mouseXAbs) && (mLastAbsY == mouseYAbs))
335 || (mouseCaps & VMMDEV_MOUSE_GUEST_USES_VMMDEV))
336 vrc = mpDrv->pUpPort->pfnPutEvent(mpDrv->pUpPort, 0, 0, dz, dw,
337 fButtons);
338 else
339 vrc = mpDrv->pUpPort->pfnPutEvent(mpDrv->pUpPort, 1, 1, dz, dw,
340 fButtons);
341 mLastAbsX = mouseXAbs;
342 mLastAbsY = mouseYAbs;
343 if (RT_FAILURE(vrc))
344 rc = setError(VBOX_E_IPRT_ERROR,
345 tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
346 vrc);
347 }
348
349 return rc;
350}
351
352// private methods
353/////////////////////////////////////////////////////////////////////////////
354
355/**
356 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
357 */
358DECLCALLBACK(void *) Mouse::drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
359{
360 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
361 PDRVMAINMOUSE pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
362
363 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
364 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSECONNECTOR, &pDrv->IConnector);
365 return NULL;
366}
367
368
369/**
370 * Destruct a mouse driver instance.
371 *
372 * @returns VBox status.
373 * @param pDrvIns The driver instance data.
374 */
375DECLCALLBACK(void) Mouse::drvDestruct(PPDMDRVINS pDrvIns)
376{
377 PDRVMAINMOUSE pData = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
378 LogFlow(("Mouse::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
379 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
380
381 if (pData->pMouse)
382 {
383 AutoWriteLock mouseLock(pData->pMouse COMMA_LOCKVAL_SRC_POS);
384 pData->pMouse->mpDrv = NULL;
385 }
386}
387
388
389/**
390 * Construct a mouse driver instance.
391 *
392 * @copydoc FNPDMDRVCONSTRUCT
393 */
394DECLCALLBACK(int) Mouse::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
395{
396 PDRVMAINMOUSE pData = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
397 LogFlow(("drvMainMouse_Construct: iInstance=%d\n", pDrvIns->iInstance));
398 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
399
400 /*
401 * Validate configuration.
402 */
403 if (!CFGMR3AreValuesValid(pCfg, "Object\0"))
404 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
405 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
406 ("Configuration error: Not possible to attach anything to this driver!\n"),
407 VERR_PDM_DRVINS_NO_ATTACH);
408
409 /*
410 * IBase.
411 */
412 pDrvIns->IBase.pfnQueryInterface = Mouse::drvQueryInterface;
413
414 /*
415 * Get the IMousePort interface of the above driver/device.
416 */
417 pData->pUpPort = (PPDMIMOUSEPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMIMOUSEPORT_IID);
418 if (!pData->pUpPort)
419 {
420 AssertMsgFailed(("Configuration error: No mouse port interface above!\n"));
421 return VERR_PDM_MISSING_INTERFACE_ABOVE;
422 }
423
424 /*
425 * Get the Mouse object pointer and update the mpDrv member.
426 */
427 void *pv;
428 int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
429 if (RT_FAILURE(rc))
430 {
431 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
432 return rc;
433 }
434 pData->pMouse = (Mouse *)pv; /** @todo Check this cast! */
435 pData->pMouse->mpDrv = pData;
436
437 return VINF_SUCCESS;
438}
439
440
441/**
442 * Main mouse driver registration record.
443 */
444const PDMDRVREG Mouse::DrvReg =
445{
446 /* u32Version */
447 PDM_DRVREG_VERSION,
448 /* szName */
449 "MainMouse",
450 /* szRCMod */
451 "",
452 /* szR0Mod */
453 "",
454 /* pszDescription */
455 "Main mouse driver (Main as in the API).",
456 /* fFlags */
457 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
458 /* fClass. */
459 PDM_DRVREG_CLASS_MOUSE,
460 /* cMaxInstances */
461 ~0,
462 /* cbInstance */
463 sizeof(DRVMAINMOUSE),
464 /* pfnConstruct */
465 Mouse::drvConstruct,
466 /* pfnDestruct */
467 Mouse::drvDestruct,
468 /* pfnRelocate */
469 NULL,
470 /* pfnIOCtl */
471 NULL,
472 /* pfnPowerOn */
473 NULL,
474 /* pfnReset */
475 NULL,
476 /* pfnSuspend */
477 NULL,
478 /* pfnResume */
479 NULL,
480 /* pfnAttach */
481 NULL,
482 /* pfnDetach */
483 NULL,
484 /* pfnPowerOff */
485 NULL,
486 /* pfnSoftReset */
487 NULL,
488 /* u32EndVersion */
489 PDM_DRVREG_VERSION
490};
491/* 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