VirtualBox

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

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

Devices/Input: most of the Main plumbing for guest multi-touch.

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