VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/MouseImpl.cpp@ 47148

Last change on this file since 47148 was 46937, checked in by vboxsync, 11 years ago

Devices/Input/UsbMouse: add multi-touch mode to pfnReportModes in PDM, fix a burn.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.0 KB
Line 
1/* $Id: MouseImpl.cpp 46937 2013-07-03 13:42:06Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2012 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 <iprt/cpp/utils.h>
19
20#include "MouseImpl.h"
21#include "DisplayImpl.h"
22#include "VMMDev.h"
23
24#include "AutoCaller.h"
25#include "Logging.h"
26
27#include <VBox/vmm/pdmdrv.h>
28#include <VBox/VMMDev.h>
29
30#include <iprt/asm.h>
31
32/** @name Mouse device capabilities bitfield
33 * @{ */
34enum
35{
36 /** The mouse device can do relative reporting */
37 MOUSE_DEVCAP_RELATIVE = 1,
38 /** The mouse device can do absolute reporting */
39 MOUSE_DEVCAP_ABSOLUTE = 2
40};
41/** @} */
42
43
44/**
45 * Mouse driver instance data.
46 */
47struct DRVMAINMOUSE
48{
49 /** Pointer to the mouse object. */
50 Mouse *pMouse;
51 /** Pointer to the driver instance structure. */
52 PPDMDRVINS pDrvIns;
53 /** Pointer to the mouse port interface of the driver/device above us. */
54 PPDMIMOUSEPORT pUpPort;
55 /** Our mouse connector interface. */
56 PDMIMOUSECONNECTOR IConnector;
57 /** The capabilities of this device. */
58 uint32_t u32DevCaps;
59};
60
61
62// constructor / destructor
63/////////////////////////////////////////////////////////////////////////////
64
65Mouse::Mouse()
66 : mParent(NULL)
67{
68}
69
70Mouse::~Mouse()
71{
72}
73
74
75HRESULT Mouse::FinalConstruct()
76{
77 RT_ZERO(mpDrv);
78 mcLastAbsX = 0x8000;
79 mcLastAbsY = 0x8000;
80 mfLastButtons = 0;
81 mfVMMDevGuestCaps = 0;
82 return BaseFinalConstruct();
83}
84
85void Mouse::FinalRelease()
86{
87 uninit();
88 BaseFinalRelease();
89}
90
91// public methods only for internal purposes
92/////////////////////////////////////////////////////////////////////////////
93
94/**
95 * Initializes the mouse object.
96 *
97 * @returns COM result indicator
98 * @param parent handle of our parent object
99 */
100HRESULT Mouse::init (Console *parent)
101{
102 LogFlowThisFunc(("\n"));
103
104 ComAssertRet(parent, 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) = parent;
111
112 unconst(mEventSource).createObject();
113 HRESULT rc = mEventSource->init(static_cast<IMouse*>(this));
114 AssertComRCReturnRC(rc);
115 mMouseEvent.init(mEventSource, VBoxEventType_OnGuestMouse,
116 0, 0, 0, 0, 0);
117
118 /* Confirm a successful initialization */
119 autoInitSpan.setSucceeded();
120
121 return S_OK;
122}
123
124/**
125 * Uninitializes the instance and sets the ready flag to FALSE.
126 * Called either from FinalRelease() or by the parent when it gets destroyed.
127 */
128void Mouse::uninit()
129{
130 LogFlowThisFunc(("\n"));
131
132 /* Enclose the state transition Ready->InUninit->NotReady */
133 AutoUninitSpan autoUninitSpan(this);
134 if (autoUninitSpan.uninitDone())
135 return;
136
137 for (unsigned i = 0; i < MOUSE_MAX_DEVICES; ++i)
138 {
139 if (mpDrv[i])
140 mpDrv[i]->pMouse = NULL;
141 mpDrv[i] = NULL;
142 }
143
144 mMouseEvent.uninit();
145 unconst(mEventSource).setNull();
146 unconst(mParent) = NULL;
147}
148
149
150// IMouse properties
151/////////////////////////////////////////////////////////////////////////////
152
153/** Report the front-end's mouse handling capabilities to the VMM device and
154 * thus to the guest.
155 * @note all calls out of this object are made with no locks held! */
156HRESULT Mouse::updateVMMDevMouseCaps(uint32_t fCapsAdded,
157 uint32_t fCapsRemoved)
158{
159 VMMDev *pVMMDev = mParent->getVMMDev();
160 if (!pVMMDev)
161 return E_FAIL; /* No assertion, as the front-ends can send events
162 * at all sorts of inconvenient times. */
163 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
164 if (!pVMMDevPort)
165 return E_FAIL; /* same here */
166
167 int rc = pVMMDevPort->pfnUpdateMouseCapabilities(pVMMDevPort, fCapsAdded,
168 fCapsRemoved);
169 return RT_SUCCESS(rc) ? S_OK : E_FAIL;
170}
171
172/**
173 * Returns whether the current setup can accept absolute mouse events, either
174 * because an emulated absolute pointing device is active or because the Guest
175 * Additions are.
176 *
177 * @returns COM status code
178 * @param absoluteSupported address of result variable
179 */
180STDMETHODIMP Mouse::COMGETTER(AbsoluteSupported) (BOOL *absoluteSupported)
181{
182 if (!absoluteSupported)
183 return E_POINTER;
184
185 AutoCaller autoCaller(this);
186 if (FAILED(autoCaller.rc())) return autoCaller.rc();
187
188 *absoluteSupported = supportsAbs();
189 return S_OK;
190}
191
192/**
193 * Returns whether the current setup can accept relative mouse events, that is,
194 * whether an emulated relative pointing device is active.
195 *
196 * @returns COM status code
197 * @param relativeSupported address of result variable
198 */
199STDMETHODIMP Mouse::COMGETTER(RelativeSupported) (BOOL *relativeSupported)
200{
201 if (!relativeSupported)
202 return E_POINTER;
203
204 AutoCaller autoCaller(this);
205 if (FAILED(autoCaller.rc())) return autoCaller.rc();
206
207 *relativeSupported = supportsRel();
208 return S_OK;
209}
210
211/**
212 * Returns whether the guest can currently switch to drawing the mouse cursor
213 * itself if it is asked to by the front-end.
214 *
215 * @returns COM status code
216 * @param pfNeedsHostCursor address of result variable
217 */
218STDMETHODIMP Mouse::COMGETTER(NeedsHostCursor) (BOOL *pfNeedsHostCursor)
219{
220 if (!pfNeedsHostCursor)
221 return E_POINTER;
222
223 AutoCaller autoCaller(this);
224 if (FAILED(autoCaller.rc())) return autoCaller.rc();
225
226 *pfNeedsHostCursor = guestNeedsHostCursor();
227 return S_OK;
228}
229
230// IMouse methods
231/////////////////////////////////////////////////////////////////////////////
232
233/** Converts a bitfield containing information about mouse buttons currently
234 * held down from the format used by the front-end to the format used by PDM
235 * and the emulated pointing devices. */
236static uint32_t mouseButtonsToPDM(LONG buttonState)
237{
238 uint32_t fButtons = 0;
239 if (buttonState & MouseButtonState_LeftButton)
240 fButtons |= PDMIMOUSEPORT_BUTTON_LEFT;
241 if (buttonState & MouseButtonState_RightButton)
242 fButtons |= PDMIMOUSEPORT_BUTTON_RIGHT;
243 if (buttonState & MouseButtonState_MiddleButton)
244 fButtons |= PDMIMOUSEPORT_BUTTON_MIDDLE;
245 if (buttonState & MouseButtonState_XButton1)
246 fButtons |= PDMIMOUSEPORT_BUTTON_X1;
247 if (buttonState & MouseButtonState_XButton2)
248 fButtons |= PDMIMOUSEPORT_BUTTON_X2;
249 return fButtons;
250}
251
252STDMETHODIMP Mouse::COMGETTER(EventSource)(IEventSource ** aEventSource)
253{
254 CheckComArgOutPointerValid(aEventSource);
255
256 AutoCaller autoCaller(this);
257 if (FAILED(autoCaller.rc())) return autoCaller.rc();
258
259 // no need to lock - lifetime constant
260 mEventSource.queryInterfaceTo(aEventSource);
261
262 return S_OK;
263}
264
265/**
266 * Send a relative pointer event to the relative device we deem most
267 * appropriate.
268 *
269 * @returns COM status code
270 */
271HRESULT Mouse::reportRelEventToMouseDev(int32_t dx, int32_t dy, int32_t dz,
272 int32_t dw, uint32_t fButtons)
273{
274 if (dx || dy || dz || dw || fButtons != mfLastButtons)
275 {
276 PPDMIMOUSEPORT pUpPort = NULL;
277 {
278 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
279
280 for (unsigned i = 0; !pUpPort && i < MOUSE_MAX_DEVICES; ++i)
281 {
282 if (mpDrv[i] && (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_RELATIVE))
283 pUpPort = mpDrv[i]->pUpPort;
284 }
285 }
286 if (!pUpPort)
287 return S_OK;
288
289 int vrc = pUpPort->pfnPutEvent(pUpPort, dx, dy, dz, dw, fButtons);
290
291 if (RT_FAILURE(vrc))
292 return setError(VBOX_E_IPRT_ERROR,
293 tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
294 vrc);
295 mfLastButtons = fButtons;
296 }
297 return S_OK;
298}
299
300
301/**
302 * Send an absolute pointer event to the emulated absolute device we deem most
303 * appropriate.
304 *
305 * @returns COM status code
306 */
307HRESULT Mouse::reportAbsEventToMouseDev(int32_t mouseXAbs, int32_t mouseYAbs,
308 int32_t dz, int32_t dw, uint32_t fButtons)
309{
310 if ( mouseXAbs < VMMDEV_MOUSE_RANGE_MIN
311 || mouseXAbs > VMMDEV_MOUSE_RANGE_MAX)
312 return S_OK;
313 if ( mouseYAbs < VMMDEV_MOUSE_RANGE_MIN
314 || mouseYAbs > VMMDEV_MOUSE_RANGE_MAX)
315 return S_OK;
316 if ( mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY
317 || dz || dw || fButtons != mfLastButtons)
318 {
319 PPDMIMOUSEPORT pUpPort = NULL;
320 {
321 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
322
323 for (unsigned i = 0; !pUpPort && i < MOUSE_MAX_DEVICES; ++i)
324 {
325 if (mpDrv[i] && (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_ABSOLUTE))
326 pUpPort = mpDrv[i]->pUpPort;
327 }
328 }
329 if (!pUpPort)
330 return S_OK;
331
332 int vrc = pUpPort->pfnPutEventAbs(pUpPort, mouseXAbs, mouseYAbs, dz,
333 dw, fButtons);
334 if (RT_FAILURE(vrc))
335 return setError(VBOX_E_IPRT_ERROR,
336 tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
337 vrc);
338 mfLastButtons = fButtons;
339
340 }
341 return S_OK;
342}
343
344
345/**
346 * Send an absolute position event to the VMM device.
347 * @note all calls out of this object are made with no locks held!
348 *
349 * @returns COM status code
350 */
351HRESULT Mouse::reportAbsEventToVMMDev(int32_t mouseXAbs, int32_t mouseYAbs)
352{
353 VMMDev *pVMMDev = mParent->getVMMDev();
354 ComAssertRet(pVMMDev, E_FAIL);
355 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
356 ComAssertRet(pVMMDevPort, E_FAIL);
357
358 if (mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY)
359 {
360 int vrc = pVMMDevPort->pfnSetAbsoluteMouse(pVMMDevPort,
361 mouseXAbs, mouseYAbs);
362 if (RT_FAILURE(vrc))
363 return setError(VBOX_E_IPRT_ERROR,
364 tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
365 vrc);
366 }
367 return S_OK;
368}
369
370
371/**
372 * Send an absolute pointer event to a pointing device (the VMM device if
373 * possible or whatever emulated absolute device seems best to us if not).
374 *
375 * @returns COM status code
376 */
377HRESULT Mouse::reportAbsEvent(int32_t mouseXAbs, int32_t mouseYAbs,
378 int32_t dz, int32_t dw, uint32_t fButtons,
379 bool fUsesVMMDevEvent)
380{
381 HRESULT rc;
382 /** If we are using the VMMDev to report absolute position but without
383 * VMMDev IRQ support then we need to send a small "jiggle" to the emulated
384 * relative mouse device to alert the guest to changes. */
385 LONG cJiggle = 0;
386
387 if (vmmdevCanAbs())
388 {
389 /*
390 * Send the absolute mouse position to the VMM device.
391 */
392 if (mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY)
393 {
394 rc = reportAbsEventToVMMDev(mouseXAbs, mouseYAbs);
395 cJiggle = !fUsesVMMDevEvent;
396 }
397 rc = reportRelEventToMouseDev(cJiggle, 0, dz, dw, fButtons);
398 }
399 else
400 rc = reportAbsEventToMouseDev(mouseXAbs, mouseYAbs, dz, dw, fButtons);
401
402 mcLastAbsX = mouseXAbs;
403 mcLastAbsY = mouseYAbs;
404 return rc;
405}
406
407void Mouse::fireMouseEvent(bool fAbsolute, LONG x, LONG y, LONG dz, LONG dw, LONG Buttons)
408{
409 /* If mouse button is pressed, we generate new event, to avoid reusable events coalescing and thus
410 dropping key press events */
411 if (Buttons != 0)
412 {
413 VBoxEventDesc evDesc;
414 evDesc.init(mEventSource, VBoxEventType_OnGuestMouse, fAbsolute, x, y, dz, dw, Buttons);
415 evDesc.fire(0);
416 }
417 else
418 {
419 mMouseEvent.reinit(VBoxEventType_OnGuestMouse, fAbsolute, x, y, dz, dw, Buttons);
420 mMouseEvent.fire(0);
421 }
422}
423
424
425/**
426 * Send a relative mouse event to the guest.
427 * @note the VMMDev capability change is so that the guest knows we are sending
428 * real events over the PS/2 device and not dummy events to signal the
429 * arrival of new absolute pointer data
430 *
431 * @returns COM status code
432 * @param dx X movement
433 * @param dy Y movement
434 * @param dz Z movement
435 * @param buttonState The mouse button state
436 */
437STDMETHODIMP Mouse::PutMouseEvent(LONG dx, LONG dy, LONG dz, LONG dw, LONG buttonState)
438{
439 HRESULT rc;
440 uint32_t fButtons;
441
442 AutoCaller autoCaller(this);
443 if (FAILED(autoCaller.rc())) return autoCaller.rc();
444 LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d\n", __PRETTY_FUNCTION__,
445 dx, dy, dz, dw));
446
447 fButtons = mouseButtonsToPDM(buttonState);
448 /* Make sure that the guest knows that we are sending real movement
449 * events to the PS/2 device and not just dummy wake-up ones. */
450 updateVMMDevMouseCaps(0, VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE);
451 rc = reportRelEventToMouseDev(dx, dy, dz, dw, fButtons);
452
453 fireMouseEvent(false, dx, dy, dz, dw, buttonState);
454
455 return rc;
456}
457
458/**
459 * Convert an (X, Y) value pair in screen co-ordinates (starting from 1) to a
460 * value from VMMDEV_MOUSE_RANGE_MIN to VMMDEV_MOUSE_RANGE_MAX. Sets the
461 * optional validity value to false if the pair is not on an active screen and
462 * to true otherwise.
463 * @note since guests with recent versions of X.Org use a different method
464 * to everyone else to map the valuator value to a screen pixel (they
465 * multiply by the screen dimension, do a floating point divide by
466 * the valuator maximum and round the result, while everyone else
467 * does truncating integer operations) we adjust the value we send
468 * so that it maps to the right pixel both when the result is rounded
469 * and when it is truncated.
470 *
471 * @returns COM status value
472 */
473HRESULT Mouse::convertDisplayRes(LONG x, LONG y, int32_t *pcX, int32_t *pcY,
474 bool *pfValid)
475{
476 AssertPtrReturn(pcX, E_POINTER);
477 AssertPtrReturn(pcY, E_POINTER);
478 AssertPtrNullReturn(pfValid, E_POINTER);
479 Display *pDisplay = mParent->getDisplay();
480 ComAssertRet(pDisplay, E_FAIL);
481 /** The amount to add to the result (multiplied by the screen width/height)
482 * to compensate for differences in guest methods for mapping back to
483 * pixels */
484 enum { ADJUST_RANGE = - 3 * VMMDEV_MOUSE_RANGE / 4 };
485
486 if (pfValid)
487 *pfValid = true;
488 if (!(mfVMMDevGuestCaps & VMMDEV_MOUSE_NEW_PROTOCOL))
489 {
490 ULONG displayWidth, displayHeight;
491 /* Takes the display lock */
492 HRESULT rc = pDisplay->GetScreenResolution(0, &displayWidth,
493 &displayHeight, NULL);
494 if (FAILED(rc))
495 return rc;
496
497 *pcX = displayWidth ? (x * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
498 / (LONG) displayWidth: 0;
499 *pcY = displayHeight ? (y * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
500 / (LONG) displayHeight: 0;
501 }
502 else
503 {
504 int32_t x1, y1, x2, y2;
505 /* Takes the display lock */
506 pDisplay->getFramebufferDimensions(&x1, &y1, &x2, &y2);
507 *pcX = x1 < x2 ? ((x - x1) * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
508 / (x2 - x1) : 0;
509 *pcY = y1 < y2 ? ((y - y1) * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
510 / (y2 - y1) : 0;
511 if ( *pcX < VMMDEV_MOUSE_RANGE_MIN || *pcX > VMMDEV_MOUSE_RANGE_MAX
512 || *pcY < VMMDEV_MOUSE_RANGE_MIN || *pcY > VMMDEV_MOUSE_RANGE_MAX)
513 if (pfValid)
514 *pfValid = false;
515 }
516 return S_OK;
517}
518
519
520/**
521 * Send an absolute mouse event to the VM. This requires either VirtualBox-
522 * specific drivers installed in the guest or absolute pointing device
523 * emulation.
524 * @note the VMMDev capability change is so that the guest knows we are sending
525 * dummy events over the PS/2 device to signal the arrival of new
526 * absolute pointer data, and not pointer real movement data
527 * @note all calls out of this object are made with no locks held!
528 *
529 * @returns COM status code
530 * @param x X position (pixel), starting from 1
531 * @param y Y position (pixel), starting from 1
532 * @param dz Z movement
533 * @param buttonState The mouse button state
534 */
535STDMETHODIMP Mouse::PutMouseEventAbsolute(LONG x, LONG y, LONG dz, LONG dw,
536 LONG buttonState)
537{
538 AutoCaller autoCaller(this);
539 if (FAILED(autoCaller.rc())) return autoCaller.rc();
540
541 LogRel3(("%s: x=%d, y=%d, dz=%d, dw=%d, buttonState=0x%x\n",
542 __PRETTY_FUNCTION__, x, y, dz, dw, buttonState));
543
544 int32_t mouseXAbs, mouseYAbs;
545 uint32_t fButtons;
546 bool fValid;
547
548 /** @todo the front end should do this conversion to avoid races */
549 /** @note Or maybe not... races are pretty inherent in everything done in
550 * this object and not really bad as far as I can see. */
551 HRESULT rc = convertDisplayRes(x, y, &mouseXAbs, &mouseYAbs, &fValid);
552 if (FAILED(rc)) return rc;
553
554 fButtons = mouseButtonsToPDM(buttonState);
555 /* If we are doing old-style (IRQ-less) absolute reporting to the VMM
556 * device then make sure the guest is aware of it, so that it knows to
557 * ignore relative movement on the PS/2 device. */
558 updateVMMDevMouseCaps(VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE, 0);
559 if (fValid)
560 {
561 rc = reportAbsEvent(mouseXAbs, mouseYAbs, dz, dw, fButtons,
562 RT_BOOL( mfVMMDevGuestCaps
563 & VMMDEV_MOUSE_NEW_PROTOCOL));
564
565 fireMouseEvent(true, x, y, dz, dw, buttonState);
566 }
567
568 return rc;
569}
570
571// private methods
572/////////////////////////////////////////////////////////////////////////////
573
574
575/** Does the guest currently rely on the host to draw the mouse cursor or
576 * can it switch to doing it itself in software? */
577bool Mouse::guestNeedsHostCursor(void)
578{
579 return RT_BOOL(mfVMMDevGuestCaps & VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
580}
581
582
583/** Check what sort of reporting can be done using the devices currently
584 * enabled. Does not consider the VMM device. */
585void Mouse::getDeviceCaps(bool *pfAbs, bool *pfRel)
586{
587 bool fAbsDev = false;
588 bool fRelDev = false;
589
590 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
591
592 for (unsigned i = 0; i < MOUSE_MAX_DEVICES; ++i)
593 if (mpDrv[i])
594 {
595 if (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_ABSOLUTE)
596 fAbsDev = true;
597 if (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_RELATIVE)
598 fRelDev = true;
599 }
600 if (pfAbs)
601 *pfAbs = fAbsDev;
602 if (pfRel)
603 *pfRel = fRelDev;
604}
605
606
607/** Does the VMM device currently support absolute reporting? */
608bool Mouse::vmmdevCanAbs(void)
609{
610 bool fRelDev;
611
612 getDeviceCaps(NULL, &fRelDev);
613 return (mfVMMDevGuestCaps & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE)
614 && fRelDev;
615}
616
617
618/** Does the VMM device currently support absolute reporting? */
619bool Mouse::deviceCanAbs(void)
620{
621 bool fAbsDev;
622
623 getDeviceCaps(&fAbsDev, NULL);
624 return fAbsDev;
625}
626
627
628/** Can we currently send relative events to the guest? */
629bool Mouse::supportsRel(void)
630{
631 bool fRelDev;
632
633 getDeviceCaps(NULL, &fRelDev);
634 return fRelDev;
635}
636
637
638/** Can we currently send absolute events to the guest? */
639bool Mouse::supportsAbs(void)
640{
641 bool fAbsDev;
642
643 getDeviceCaps(&fAbsDev, NULL);
644 return fAbsDev || vmmdevCanAbs();
645}
646
647
648/** Check what sort of reporting can be done using the devices currently
649 * enabled (including the VMM device) and notify the guest and the front-end.
650 */
651void Mouse::sendMouseCapsNotifications(void)
652{
653 bool fAbsDev, fRelDev, fCanAbs, fNeedsHostCursor;
654
655 {
656 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
657
658 getDeviceCaps(&fAbsDev, &fRelDev);
659 fCanAbs = supportsAbs();
660 fNeedsHostCursor = guestNeedsHostCursor();
661 }
662 if (fAbsDev)
663 updateVMMDevMouseCaps(VMMDEV_MOUSE_HOST_HAS_ABS_DEV, 0);
664 else
665 updateVMMDevMouseCaps(0, VMMDEV_MOUSE_HOST_HAS_ABS_DEV);
666 /** @todo this call takes the Console lock in order to update the cached
667 * callback data atomically. However I can't see any sign that the cached
668 * data is ever used again. */
669 mParent->onMouseCapabilityChange(fCanAbs, fRelDev, fNeedsHostCursor);
670}
671
672
673/**
674 * @interface_method_impl{PDMIMOUSECONNECTOR,pfnReportModes}
675 * A virtual device is notifying us about its current state and capabilities
676 */
677DECLCALLBACK(void) Mouse::mouseReportModes(PPDMIMOUSECONNECTOR pInterface, bool fRel, bool fAbs, bool)
678{
679 PDRVMAINMOUSE pDrv = RT_FROM_MEMBER(pInterface, DRVMAINMOUSE, IConnector);
680 if (fRel)
681 pDrv->u32DevCaps |= MOUSE_DEVCAP_RELATIVE;
682 else
683 pDrv->u32DevCaps &= ~MOUSE_DEVCAP_RELATIVE;
684 if (fAbs)
685 pDrv->u32DevCaps |= MOUSE_DEVCAP_ABSOLUTE;
686 else
687 pDrv->u32DevCaps &= ~MOUSE_DEVCAP_ABSOLUTE;
688
689 pDrv->pMouse->sendMouseCapsNotifications();
690}
691
692
693/**
694 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
695 */
696DECLCALLBACK(void *) Mouse::drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
697{
698 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
699 PDRVMAINMOUSE pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
700
701 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
702 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSECONNECTOR, &pDrv->IConnector);
703 return NULL;
704}
705
706
707/**
708 * Destruct a mouse driver instance.
709 *
710 * @returns VBox status.
711 * @param pDrvIns The driver instance data.
712 */
713DECLCALLBACK(void) Mouse::drvDestruct(PPDMDRVINS pDrvIns)
714{
715 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
716 PDRVMAINMOUSE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
717 LogFlow(("Mouse::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
718
719 if (pThis->pMouse)
720 {
721 AutoWriteLock mouseLock(pThis->pMouse COMMA_LOCKVAL_SRC_POS);
722 for (unsigned cDev = 0; cDev < MOUSE_MAX_DEVICES; ++cDev)
723 if (pThis->pMouse->mpDrv[cDev] == pThis)
724 {
725 pThis->pMouse->mpDrv[cDev] = NULL;
726 break;
727 }
728 }
729}
730
731
732/**
733 * Construct a mouse driver instance.
734 *
735 * @copydoc FNPDMDRVCONSTRUCT
736 */
737DECLCALLBACK(int) Mouse::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
738{
739 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
740 PDRVMAINMOUSE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
741 LogFlow(("drvMainMouse_Construct: iInstance=%d\n", pDrvIns->iInstance));
742
743 /*
744 * Validate configuration.
745 */
746 if (!CFGMR3AreValuesValid(pCfg, "Object\0"))
747 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
748 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
749 ("Configuration error: Not possible to attach anything to this driver!\n"),
750 VERR_PDM_DRVINS_NO_ATTACH);
751
752 /*
753 * IBase.
754 */
755 pDrvIns->IBase.pfnQueryInterface = Mouse::drvQueryInterface;
756
757 pThis->IConnector.pfnReportModes = Mouse::mouseReportModes;
758
759 /*
760 * Get the IMousePort interface of the above driver/device.
761 */
762 pThis->pUpPort = (PPDMIMOUSEPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMIMOUSEPORT_IID);
763 if (!pThis->pUpPort)
764 {
765 AssertMsgFailed(("Configuration error: No mouse port interface above!\n"));
766 return VERR_PDM_MISSING_INTERFACE_ABOVE;
767 }
768
769 /*
770 * Get the Mouse object pointer and update the mpDrv member.
771 */
772 void *pv;
773 int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
774 if (RT_FAILURE(rc))
775 {
776 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
777 return rc;
778 }
779 pThis->pMouse = (Mouse *)pv; /** @todo Check this cast! */
780 unsigned cDev;
781 {
782 AutoReadLock mouseLock(pThis->pMouse COMMA_LOCKVAL_SRC_POS);
783
784 for (cDev = 0; cDev < MOUSE_MAX_DEVICES; ++cDev)
785 if (!pThis->pMouse->mpDrv[cDev])
786 {
787 pThis->pMouse->mpDrv[cDev] = pThis;
788 break;
789 }
790 }
791 if (cDev == MOUSE_MAX_DEVICES)
792 return VERR_NO_MORE_HANDLES;
793
794 return VINF_SUCCESS;
795}
796
797
798/**
799 * Main mouse driver registration record.
800 */
801const PDMDRVREG Mouse::DrvReg =
802{
803 /* u32Version */
804 PDM_DRVREG_VERSION,
805 /* szName */
806 "MainMouse",
807 /* szRCMod */
808 "",
809 /* szR0Mod */
810 "",
811 /* pszDescription */
812 "Main mouse driver (Main as in the API).",
813 /* fFlags */
814 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
815 /* fClass. */
816 PDM_DRVREG_CLASS_MOUSE,
817 /* cMaxInstances */
818 ~0U,
819 /* cbInstance */
820 sizeof(DRVMAINMOUSE),
821 /* pfnConstruct */
822 Mouse::drvConstruct,
823 /* pfnDestruct */
824 Mouse::drvDestruct,
825 /* pfnRelocate */
826 NULL,
827 /* pfnIOCtl */
828 NULL,
829 /* pfnPowerOn */
830 NULL,
831 /* pfnReset */
832 NULL,
833 /* pfnSuspend */
834 NULL,
835 /* pfnResume */
836 NULL,
837 /* pfnAttach */
838 NULL,
839 /* pfnDetach */
840 NULL,
841 /* pfnPowerOff */
842 NULL,
843 /* pfnSoftReset */
844 NULL,
845 /* u32EndVersion */
846 PDM_DRVREG_VERSION
847};
848/* 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