VirtualBox

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

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

Main/Mouse: ignore mouse events on disabled screens properly

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

© 2023 Oracle
ContactPrivacy policyTerms of Use