VirtualBox

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

Last change on this file since 24322 was 22810, checked in by vboxsync, 15 years ago

FE/Qt, Devices/Input, Main, FE/*: upgrade mouse device to an MS IntelliMouse Explorer (five buttons and tilt wheel)

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