VirtualBox

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

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

Main/MouseImpl: try to send absolute position data that both Windows and (recent) X.Org guests interpret corrently

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