VirtualBox

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

Last change on this file since 40310 was 40310, checked in by vboxsync, 13 years ago

Devices/VMMDev and Additions: use a single definition for the value range of the Additions pointer position reporting.

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