VirtualBox

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

Last change on this file since 70772 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.8 KB
RevLine 
[13607]1/* $Id: MouseImpl.cpp 69500 2017-10-28 15:14:05Z vboxsync $ */
[1]2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
[69500]7 * Copyright (C) 2006-2017 Oracle Corporation
[1]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
[5999]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.
[1]16 */
17
[67914]18#define LOG_GROUP LOG_GROUP_MAIN_MOUSE
19#include "LoggingNew.h"
20
[30681]21#include <iprt/cpp/utils.h>
22
[1]23#include "MouseImpl.h"
24#include "DisplayImpl.h"
25#include "VMMDev.h"
[52921]26#include "MousePointerShapeWrap.h"
[1]27
[25860]28#include "AutoCaller.h"
[1]29
[35346]30#include <VBox/vmm/pdmdrv.h>
[33758]31#include <VBox/VMMDev.h>
[30681]32
[1]33#include <iprt/asm.h>
[30681]34
[52921]35class ATL_NO_VTABLE MousePointerShape:
36 public MousePointerShapeWrap
37{
38public:
39
40 DECLARE_EMPTY_CTOR_DTOR(MousePointerShape)
41
42 HRESULT FinalConstruct();
43 void FinalRelease();
44
45 /* Public initializer/uninitializer for internal purposes only. */
46 HRESULT init(ComObjPtr<Mouse> pMouse,
47 bool fVisible, bool fAlpha,
48 uint32_t hotX, uint32_t hotY,
49 uint32_t width, uint32_t height,
50 const uint8_t *pu8Shape, uint32_t cbShape);
51 void uninit();
52
53private:
54 // wrapped IMousePointerShape properties
55 virtual HRESULT getVisible(BOOL *aVisible);
56 virtual HRESULT getAlpha(BOOL *aAlpha);
57 virtual HRESULT getHotX(ULONG *aHotX);
58 virtual HRESULT getHotY(ULONG *aHotY);
59 virtual HRESULT getWidth(ULONG *aWidth);
60 virtual HRESULT getHeight(ULONG *aHeight);
61 virtual HRESULT getShape(std::vector<BYTE> &aShape);
62
63 struct Data
64 {
65 ComObjPtr<Mouse> pMouse;
66 bool fVisible;
67 bool fAlpha;
68 uint32_t hotX;
69 uint32_t hotY;
70 uint32_t width;
71 uint32_t height;
72 std::vector<BYTE> shape;
73 };
74
75 Data m;
76};
77
78/*
79 * MousePointerShape implementation.
80 */
81DEFINE_EMPTY_CTOR_DTOR(MousePointerShape)
82
83HRESULT MousePointerShape::FinalConstruct()
84{
85 return BaseFinalConstruct();
86}
87
88void MousePointerShape::FinalRelease()
89{
90 uninit();
91
92 BaseFinalRelease();
93}
94
95HRESULT MousePointerShape::init(ComObjPtr<Mouse> pMouse,
96 bool fVisible, bool fAlpha,
97 uint32_t hotX, uint32_t hotY,
98 uint32_t width, uint32_t height,
99 const uint8_t *pu8Shape, uint32_t cbShape)
100{
101 LogFlowThisFunc(("v %d, a %d, h %d,%d, %dx%d, cb %d\n",
102 fVisible, fAlpha, hotX, hotY, width, height, cbShape));
103
104 /* Enclose the state transition NotReady->InInit->Ready */
105 AutoInitSpan autoInitSpan(this);
106 AssertReturn(autoInitSpan.isOk(), E_FAIL);
107
108 m.pMouse = pMouse;
109 m.fVisible = fVisible;
110 m.fAlpha = fAlpha;
111 m.hotX = hotX;
112 m.hotY = hotY;
113 m.width = width;
114 m.height = height;
115 m.shape.resize(cbShape);
116 if (cbShape)
117 {
118 memcpy(&m.shape.front(), pu8Shape, cbShape);
119 }
120
121 /* Confirm a successful initialization */
122 autoInitSpan.setSucceeded();
123
124 return S_OK;
125}
126
127void MousePointerShape::uninit()
128{
129 LogFlowThisFunc(("\n"));
130
131 /* Enclose the state transition Ready->InUninit->NotReady */
132 AutoUninitSpan autoUninitSpan(this);
133 if (autoUninitSpan.uninitDone())
134 return;
135
136 m.pMouse.setNull();
137}
138
139HRESULT MousePointerShape::getVisible(BOOL *aVisible)
140{
141 *aVisible = m.fVisible;
142 return S_OK;
143}
144
145HRESULT MousePointerShape::getAlpha(BOOL *aAlpha)
146{
147 *aAlpha = m.fAlpha;
148 return S_OK;
149}
150
151HRESULT MousePointerShape::getHotX(ULONG *aHotX)
152{
153 *aHotX = m.hotX;
154 return S_OK;
155}
156
157HRESULT MousePointerShape::getHotY(ULONG *aHotY)
158{
159 *aHotY = m.hotY;
160 return S_OK;
161}
162
163HRESULT MousePointerShape::getWidth(ULONG *aWidth)
164{
165 *aWidth = m.width;
166 return S_OK;
167}
168
169HRESULT MousePointerShape::getHeight(ULONG *aHeight)
170{
171 *aHeight = m.height;
172 return S_OK;
173}
174
175HRESULT MousePointerShape::getShape(std::vector<BYTE> &aShape)
176{
177 aShape.resize(m.shape.size());
[59858]178 if (m.shape.size())
179 memcpy(&aShape.front(), &m.shape.front(), aShape.size());
[52921]180 return S_OK;
181}
182
183
[27060]184/** @name Mouse device capabilities bitfield
185 * @{ */
186enum
187{
188 /** The mouse device can do relative reporting */
189 MOUSE_DEVCAP_RELATIVE = 1,
190 /** The mouse device can do absolute reporting */
[47174]191 MOUSE_DEVCAP_ABSOLUTE = 2,
192 /** The mouse device can do absolute reporting */
193 MOUSE_DEVCAP_MULTI_TOUCH = 4
[27060]194};
195/** @} */
196
[36161]197
[1]198/**
199 * Mouse driver instance data.
200 */
[27060]201struct DRVMAINMOUSE
[1]202{
203 /** Pointer to the mouse object. */
204 Mouse *pMouse;
205 /** Pointer to the driver instance structure. */
206 PPDMDRVINS pDrvIns;
207 /** Pointer to the mouse port interface of the driver/device above us. */
208 PPDMIMOUSEPORT pUpPort;
209 /** Our mouse connector interface. */
[25985]210 PDMIMOUSECONNECTOR IConnector;
[27060]211 /** The capabilities of this device. */
212 uint32_t u32DevCaps;
213};
[1]214
[30764]215
[1]216// constructor / destructor
217/////////////////////////////////////////////////////////////////////////////
218
[27607]219Mouse::Mouse()
220 : mParent(NULL)
221{
222}
[13606]223
[27607]224Mouse::~Mouse()
225{
226}
227
228
[1]229HRESULT Mouse::FinalConstruct()
230{
[27060]231 RT_ZERO(mpDrv);
[52921]232 RT_ZERO(mPointerData);
[47208]233 mcLastX = 0x8000;
234 mcLastY = 0x8000;
[33758]235 mfLastButtons = 0;
[33779]236 mfVMMDevGuestCaps = 0;
[35638]237 return BaseFinalConstruct();
[1]238}
239
240void Mouse::FinalRelease()
241{
[13606]242 uninit();
[35638]243 BaseFinalRelease();
[1]244}
245
246// public methods only for internal purposes
247/////////////////////////////////////////////////////////////////////////////
248
249/**
250 * Initializes the mouse object.
251 *
252 * @returns COM result indicator
253 * @param parent handle of our parent object
254 */
[47190]255HRESULT Mouse::init (ConsoleMouseInterface *parent)
[1]256{
[21878]257 LogFlowThisFunc(("\n"));
[1]258
[26235]259 ComAssertRet(parent, E_INVALIDARG);
[1]260
[13606]261 /* Enclose the state transition NotReady->InInit->Ready */
[21878]262 AutoInitSpan autoInitSpan(this);
263 AssertReturn(autoInitSpan.isOk(), E_FAIL);
[1]264
[13606]265 unconst(mParent) = parent;
[1]266
[33061]267 unconst(mEventSource).createObject();
[50544]268 HRESULT rc = mEventSource->init();
[33061]269 AssertComRCReturnRC(rc);
[34393]270 mMouseEvent.init(mEventSource, VBoxEventType_OnGuestMouse,
[47804]271 0, 0, 0, 0, 0, 0);
[33061]272
[13606]273 /* Confirm a successful initialization */
274 autoInitSpan.setSucceeded();
275
[1]276 return S_OK;
277}
278
279/**
280 * Uninitializes the instance and sets the ready flag to FALSE.
281 * Called either from FinalRelease() or by the parent when it gets destroyed.
282 */
283void Mouse::uninit()
284{
[21878]285 LogFlowThisFunc(("\n"));
[1]286
[13606]287 /* Enclose the state transition Ready->InUninit->NotReady */
[21878]288 AutoUninitSpan autoUninitSpan(this);
[13606]289 if (autoUninitSpan.uninitDone())
290 return;
[1]291
[27060]292 for (unsigned i = 0; i < MOUSE_MAX_DEVICES; ++i)
293 {
294 if (mpDrv[i])
295 mpDrv[i]->pMouse = NULL;
296 mpDrv[i] = NULL;
297 }
[1]298
[52921]299 mPointerShape.setNull();
300
301 RTMemFree(mPointerData.pu8Shape);
302 mPointerData.pu8Shape = NULL;
303 mPointerData.cbShape = 0;
304
[33061]305 mMouseEvent.uninit();
306 unconst(mEventSource).setNull();
[27607]307 unconst(mParent) = NULL;
[1]308}
309
[52921]310void Mouse::updateMousePointerShape(bool fVisible, bool fAlpha,
311 uint32_t hotX, uint32_t hotY,
312 uint32_t width, uint32_t height,
313 const uint8_t *pu8Shape, uint32_t cbShape)
314{
315 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
[26624]316
[52921]317 RTMemFree(mPointerData.pu8Shape);
318 mPointerData.pu8Shape = NULL;
319 mPointerData.cbShape = 0;
320
321 mPointerData.fVisible = fVisible;
322 mPointerData.fAlpha = fAlpha;
323 mPointerData.hotX = hotX;
324 mPointerData.hotY = hotY;
325 mPointerData.width = width;
326 mPointerData.height = height;
327 if (cbShape)
328 {
329 mPointerData.pu8Shape = (uint8_t *)RTMemDup(pu8Shape, cbShape);
330 if (mPointerData.pu8Shape)
331 {
332 mPointerData.cbShape = cbShape;
333 }
334 }
335
336 mPointerShape.setNull();
337}
338
[1]339// IMouse properties
340/////////////////////////////////////////////////////////////////////////////
341
[32828]342/** Report the front-end's mouse handling capabilities to the VMM device and
343 * thus to the guest.
344 * @note all calls out of this object are made with no locks held! */
[50613]345HRESULT Mouse::i_updateVMMDevMouseCaps(uint32_t fCapsAdded,
346 uint32_t fCapsRemoved)
[26624]347{
[51612]348 VMMDevMouseInterface *pVMMDev = mParent->i_getVMMDevMouseInterface();
[33758]349 if (!pVMMDev)
350 return E_FAIL; /* No assertion, as the front-ends can send events
351 * at all sorts of inconvenient times. */
[53965]352 DisplayMouseInterface *pDisplay = mParent->i_getDisplayMouseInterface();
353 if (pDisplay == NULL)
354 return E_FAIL;
[26624]355 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
[41131]356 if (!pVMMDevPort)
357 return E_FAIL; /* same here */
[26624]358
[33758]359 int rc = pVMMDevPort->pfnUpdateMouseCapabilities(pVMMDevPort, fCapsAdded,
360 fCapsRemoved);
[53965]361 if (RT_FAILURE(rc))
362 return E_FAIL;
363 return pDisplay->i_reportHostCursorCapabilities(fCapsAdded, fCapsRemoved);
[26624]364}
365
[1]366/**
[47174]367 * Returns whether the currently active device portfolio can accept absolute
368 * mouse events.
[1]369 *
370 * @returns COM status code
[65103]371 * @param aAbsoluteSupported address of result variable
[1]372 */
[50613]373HRESULT Mouse::getAbsoluteSupported(BOOL *aAbsoluteSupported)
[1]374{
[50613]375 *aAbsoluteSupported = i_supportsAbs();
[1]376 return S_OK;
377}
378
379/**
[47174]380 * Returns whether the currently active device portfolio can accept relative
381 * mouse events.
[26782]382 *
383 * @returns COM status code
[65103]384 * @param aRelativeSupported address of result variable
[26782]385 */
[50613]386HRESULT Mouse::getRelativeSupported(BOOL *aRelativeSupported)
[26782]387{
[50613]388 *aRelativeSupported = i_supportsRel();
[26782]389 return S_OK;
390}
391
392/**
[47174]393 * Returns whether the currently active device portfolio can accept multi-touch
394 * mouse events.
395 *
396 * @returns COM status code
[65103]397 * @param aMultiTouchSupported address of result variable
[47174]398 */
[50613]399HRESULT Mouse::getMultiTouchSupported(BOOL *aMultiTouchSupported)
[47174]400{
[50613]401 *aMultiTouchSupported = i_supportsMT();
[47174]402 return S_OK;
403}
404
405/**
[32828]406 * Returns whether the guest can currently switch to drawing the mouse cursor
407 * itself if it is asked to by the front-end.
[1]408 *
409 * @returns COM status code
[65103]410 * @param aNeedsHostCursor address of result variable
[1]411 */
[50613]412HRESULT Mouse::getNeedsHostCursor(BOOL *aNeedsHostCursor)
[1]413{
[50613]414 *aNeedsHostCursor = i_guestNeedsHostCursor();
[1]415 return S_OK;
416}
417
[52921]418HRESULT Mouse::getPointerShape(ComPtr<IMousePointerShape> &aPointerShape)
419{
420 HRESULT hr = S_OK;
421
422 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
423
424 if (mPointerShape.isNull())
425 {
426 ComObjPtr<MousePointerShape> obj;
427 hr = obj.createObject();
428 if (SUCCEEDED(hr))
429 {
430 hr = obj->init(this, mPointerData.fVisible, mPointerData.fAlpha,
431 mPointerData.hotX, mPointerData.hotY,
432 mPointerData.width, mPointerData.height,
433 mPointerData.pu8Shape, mPointerData.cbShape);
434 }
435
436 if (SUCCEEDED(hr))
437 {
438 mPointerShape = obj;
439 }
440 }
441
442 if (SUCCEEDED(hr))
443 {
444 aPointerShape = mPointerShape;
445 }
446
447 return hr;
448}
449
[1]450// IMouse methods
451/////////////////////////////////////////////////////////////////////////////
452
[32828]453/** Converts a bitfield containing information about mouse buttons currently
454 * held down from the format used by the front-end to the format used by PDM
455 * and the emulated pointing devices. */
[50613]456static uint32_t i_mouseButtonsToPDM(LONG buttonState)
[26624]457{
458 uint32_t fButtons = 0;
459 if (buttonState & MouseButtonState_LeftButton)
460 fButtons |= PDMIMOUSEPORT_BUTTON_LEFT;
461 if (buttonState & MouseButtonState_RightButton)
462 fButtons |= PDMIMOUSEPORT_BUTTON_RIGHT;
463 if (buttonState & MouseButtonState_MiddleButton)
464 fButtons |= PDMIMOUSEPORT_BUTTON_MIDDLE;
465 if (buttonState & MouseButtonState_XButton1)
466 fButtons |= PDMIMOUSEPORT_BUTTON_X1;
467 if (buttonState & MouseButtonState_XButton2)
468 fButtons |= PDMIMOUSEPORT_BUTTON_X2;
469 return fButtons;
470}
471
[50613]472HRESULT Mouse::getEventSource(ComPtr<IEventSource> &aEventSource)
[33061]473{
474 // no need to lock - lifetime constant
[50613]475 mEventSource.queryInterfaceTo(aEventSource.asOutParam());
[33061]476 return S_OK;
477}
478
[1]479/**
[32828]480 * Send a relative pointer event to the relative device we deem most
481 * appropriate.
[26624]482 *
483 * @returns COM status code
484 */
[50613]485HRESULT Mouse::i_reportRelEventToMouseDev(int32_t dx, int32_t dy, int32_t dz,
486 int32_t dw, uint32_t fButtons)
[26624]487{
[33758]488 if (dx || dy || dz || dw || fButtons != mfLastButtons)
[26624]489 {
[27060]490 PPDMIMOUSEPORT pUpPort = NULL;
491 {
[32817]492 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
493
494 for (unsigned i = 0; !pUpPort && i < MOUSE_MAX_DEVICES; ++i)
495 {
496 if (mpDrv[i] && (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_RELATIVE))
497 pUpPort = mpDrv[i]->pUpPort;
498 }
[27060]499 }
500 if (!pUpPort)
[27129]501 return S_OK;
[27060]502
[26624]503 int vrc = pUpPort->pfnPutEvent(pUpPort, dx, dy, dz, dw, fButtons);
504
505 if (RT_FAILURE(vrc))
[27160]506 return setError(VBOX_E_IPRT_ERROR,
507 tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
508 vrc);
[33758]509 mfLastButtons = fButtons;
[26624]510 }
511 return S_OK;
512}
513
514
515/**
[32828]516 * Send an absolute pointer event to the emulated absolute device we deem most
517 * appropriate.
[26624]518 *
519 * @returns COM status code
520 */
[50613]521HRESULT Mouse::i_reportAbsEventToMouseDev(int32_t x, int32_t y,
522 int32_t dz, int32_t dw, uint32_t fButtons)
[26624]523{
[47208]524 if ( x < VMMDEV_MOUSE_RANGE_MIN
525 || x > VMMDEV_MOUSE_RANGE_MAX)
[36161]526 return S_OK;
[47208]527 if ( y < VMMDEV_MOUSE_RANGE_MIN
528 || y > VMMDEV_MOUSE_RANGE_MAX)
[36161]529 return S_OK;
[47208]530 if ( x != mcLastX || y != mcLastY
[33758]531 || dz || dw || fButtons != mfLastButtons)
[26624]532 {
[27060]533 PPDMIMOUSEPORT pUpPort = NULL;
534 {
[32817]535 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
536
537 for (unsigned i = 0; !pUpPort && i < MOUSE_MAX_DEVICES; ++i)
538 {
539 if (mpDrv[i] && (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_ABSOLUTE))
540 pUpPort = mpDrv[i]->pUpPort;
541 }
[27060]542 }
543 if (!pUpPort)
[27129]544 return S_OK;
[27060]545
[47208]546 int vrc = pUpPort->pfnPutEventAbs(pUpPort, x, y, dz,
[27060]547 dw, fButtons);
[26624]548 if (RT_FAILURE(vrc))
[27160]549 return setError(VBOX_E_IPRT_ERROR,
550 tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
551 vrc);
[33758]552 mfLastButtons = fButtons;
[33075]553
[26624]554 }
555 return S_OK;
556}
557
[50613]558HRESULT Mouse::i_reportMultiTouchEventToDevice(uint8_t cContacts,
559 const uint64_t *pau64Contacts,
560 uint32_t u32ScanTime)
[47571]561{
562 HRESULT hrc = S_OK;
[26624]563
[47208]564 PPDMIMOUSEPORT pUpPort = NULL;
565 {
566 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
567
[47571]568 unsigned i;
569 for (i = 0; i < MOUSE_MAX_DEVICES; ++i)
[47208]570 {
571 if ( mpDrv[i]
572 && (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_MULTI_TOUCH))
[47571]573 {
[47208]574 pUpPort = mpDrv[i]->pUpPort;
[47571]575 break;
576 }
[47208]577 }
578 }
579
[47571]580 if (pUpPort)
581 {
582 int vrc = pUpPort->pfnPutEventMultiTouch(pUpPort, cContacts, pau64Contacts, u32ScanTime);
583 if (RT_FAILURE(vrc))
584 hrc = setError(VBOX_E_IPRT_ERROR,
585 tr("Could not send the multi-touch event to the virtual device (%Rrc)"),
586 vrc);
587 }
588 else
589 {
590 hrc = E_UNEXPECTED;
591 }
592
593 return hrc;
[47174]594}
595
596
597/**
[26624]598 * Send an absolute position event to the VMM device.
[32828]599 * @note all calls out of this object are made with no locks held!
[26624]600 *
601 * @returns COM status code
602 */
[50613]603HRESULT Mouse::i_reportAbsEventToVMMDev(int32_t x, int32_t y)
[26624]604{
[51612]605 VMMDevMouseInterface *pVMMDev = mParent->i_getVMMDevMouseInterface();
[26624]606 ComAssertRet(pVMMDev, E_FAIL);
607 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
608 ComAssertRet(pVMMDevPort, E_FAIL);
609
[47208]610 if (x != mcLastX || y != mcLastY)
[26624]611 {
612 int vrc = pVMMDevPort->pfnSetAbsoluteMouse(pVMMDevPort,
[47208]613 x, y);
[26624]614 if (RT_FAILURE(vrc))
[27160]615 return setError(VBOX_E_IPRT_ERROR,
616 tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
617 vrc);
[26624]618 }
619 return S_OK;
620}
621
[32828]622
623/**
624 * Send an absolute pointer event to a pointing device (the VMM device if
625 * possible or whatever emulated absolute device seems best to us if not).
626 *
627 * @returns COM status code
628 */
[53965]629HRESULT Mouse::i_reportAbsEventToInputDevices(int32_t x, int32_t y, int32_t dz, int32_t dw, uint32_t fButtons,
630 bool fUsesVMMDevEvent)
[32817]631{
[47841]632 HRESULT rc;
[32817]633 /** If we are using the VMMDev to report absolute position but without
634 * VMMDev IRQ support then we need to send a small "jiggle" to the emulated
635 * relative mouse device to alert the guest to changes. */
636 LONG cJiggle = 0;
637
[50613]638 if (i_vmmdevCanAbs())
[32817]639 {
[47841]640 /*
641 * Send the absolute mouse position to the VMM device.
642 */
643 if (x != mcLastX || y != mcLastY)
[32817]644 {
[50613]645 rc = i_reportAbsEventToVMMDev(x, y);
[33261]646 cJiggle = !fUsesVMMDevEvent;
[32817]647 }
[50613]648 rc = i_reportRelEventToMouseDev(cJiggle, 0, dz, dw, fButtons);
[32817]649 }
[47841]650 else
[50613]651 rc = i_reportAbsEventToMouseDev(x, y, dz, dw, fButtons);
[32817]652
[47208]653 mcLastX = x;
654 mcLastY = y;
[32817]655 return rc;
656}
657
[53965]658
659/**
660 * Send an absolute position event to the display device.
661 * @note all calls out of this object are made with no locks held!
662 * @param x Cursor X position in pixels relative to the first screen, where
663 * (1, 1) is the upper left corner.
664 * @param y Cursor Y position in pixels relative to the first screen, where
665 * (1, 1) is the upper left corner.
666 */
667HRESULT Mouse::i_reportAbsEventToDisplayDevice(int32_t x, int32_t y)
668{
669 DisplayMouseInterface *pDisplay = mParent->i_getDisplayMouseInterface();
670 ComAssertRet(pDisplay, E_FAIL);
671
672 if (x != mcLastX || y != mcLastY)
673 {
674 pDisplay->i_reportHostCursorPosition(x - 1, y - 1);
675 }
676 return S_OK;
677}
678
679
[50613]680void Mouse::i_fireMouseEvent(bool fAbsolute, LONG x, LONG y, LONG dz, LONG dw,
681 LONG fButtons)
[35871]682{
683 /* If mouse button is pressed, we generate new event, to avoid reusable events coalescing and thus
684 dropping key press events */
[47805]685 GuestMouseEventMode_T mode;
686 if (fAbsolute)
687 mode = GuestMouseEventMode_Absolute;
688 else
689 mode = GuestMouseEventMode_Relative;
690
[47215]691 if (fButtons != 0)
[35871]692 {
693 VBoxEventDesc evDesc;
[47804]694 evDesc.init(mEventSource, VBoxEventType_OnGuestMouse, mode, x, y,
695 dz, dw, fButtons);
[35871]696 evDesc.fire(0);
697 }
698 else
699 {
[47804]700 mMouseEvent.reinit(VBoxEventType_OnGuestMouse, mode, x, y, dz, dw,
701 fButtons);
[35871]702 mMouseEvent.fire(0);
703 }
704}
705
[50613]706void Mouse::i_fireMultiTouchEvent(uint8_t cContacts,
707 const LONG64 *paContacts,
708 uint32_t u32ScanTime)
[47848]709{
710 com::SafeArray<SHORT> xPositions(cContacts);
711 com::SafeArray<SHORT> yPositions(cContacts);
712 com::SafeArray<USHORT> contactIds(cContacts);
713 com::SafeArray<USHORT> contactFlags(cContacts);
[35871]714
[47848]715 uint8_t i;
716 for (i = 0; i < cContacts; i++)
717 {
718 uint32_t u32Lo = RT_LO_U32(paContacts[i]);
719 uint32_t u32Hi = RT_HI_U32(paContacts[i]);
720 xPositions[i] = (int16_t)u32Lo;
721 yPositions[i] = (int16_t)(u32Lo >> 16);
722 contactIds[i] = RT_BYTE1(u32Hi);
723 contactFlags[i] = RT_BYTE2(u32Hi);
724 }
725
726 VBoxEventDesc evDesc;
727 evDesc.init(mEventSource, VBoxEventType_OnGuestMultiTouch,
728 cContacts, ComSafeArrayAsInParam(xPositions), ComSafeArrayAsInParam(yPositions),
729 ComSafeArrayAsInParam(contactIds), ComSafeArrayAsInParam(contactFlags), u32ScanTime);
730 evDesc.fire(0);
731}
732
[26624]733/**
[32828]734 * Send a relative mouse event to the guest.
735 * @note the VMMDev capability change is so that the guest knows we are sending
736 * real events over the PS/2 device and not dummy events to signal the
737 * arrival of new absolute pointer data
[1]738 *
739 * @returns COM status code
[65103]740 * @param dx X movement.
741 * @param dy Y movement.
742 * @param dz Z movement.
743 * @param dw Mouse wheel movement.
744 * @param aButtonState The mouse button state.
[1]745 */
[50613]746HRESULT Mouse::putMouseEvent(LONG dx, LONG dy, LONG dz, LONG dw,
747 LONG aButtonState)
[1]748{
[32817]749 HRESULT rc;
[47215]750 uint32_t fButtonsAdj;
[13606]751
[33758]752 LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d\n", __PRETTY_FUNCTION__,
[32817]753 dx, dy, dz, dw));
754
[50613]755 fButtonsAdj = i_mouseButtonsToPDM(aButtonState);
[33758]756 /* Make sure that the guest knows that we are sending real movement
757 * events to the PS/2 device and not just dummy wake-up ones. */
[50613]758 i_updateVMMDevMouseCaps(0, VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE);
759 rc = i_reportRelEventToMouseDev(dx, dy, dz, dw, fButtonsAdj);
[1]760
[50613]761 i_fireMouseEvent(false, dx, dy, dz, dw, aButtonState);
[33075]762
[13606]763 return rc;
[1]764}
765
766/**
[32817]767 * Convert an (X, Y) value pair in screen co-ordinates (starting from 1) to a
[40310]768 * value from VMMDEV_MOUSE_RANGE_MIN to VMMDEV_MOUSE_RANGE_MAX. Sets the
769 * optional validity value to false if the pair is not on an active screen and
770 * to true otherwise.
[38590]771 * @note since guests with recent versions of X.Org use a different method
772 * to everyone else to map the valuator value to a screen pixel (they
773 * multiply by the screen dimension, do a floating point divide by
774 * the valuator maximum and round the result, while everyone else
775 * does truncating integer operations) we adjust the value we send
776 * so that it maps to the right pixel both when the result is rounded
777 * and when it is truncated.
[26624]778 *
779 * @returns COM status value
780 */
[50613]781HRESULT Mouse::i_convertDisplayRes(LONG x, LONG y, int32_t *pxAdj, int32_t *pyAdj,
782 bool *pfValid)
[26624]783{
[47215]784 AssertPtrReturn(pxAdj, E_POINTER);
785 AssertPtrReturn(pyAdj, E_POINTER);
[35212]786 AssertPtrNullReturn(pfValid, E_POINTER);
[51612]787 DisplayMouseInterface *pDisplay = mParent->i_getDisplayMouseInterface();
[26624]788 ComAssertRet(pDisplay, E_FAIL);
[38590]789 /** The amount to add to the result (multiplied by the screen width/height)
790 * to compensate for differences in guest methods for mapping back to
791 * pixels */
[40310]792 enum { ADJUST_RANGE = - 3 * VMMDEV_MOUSE_RANGE / 4 };
[26624]793
[35212]794 if (pfValid)
795 *pfValid = true;
[54495]796 if (!(mfVMMDevGuestCaps & VMMDEV_MOUSE_NEW_PROTOCOL) && !pDisplay->i_isInputMappingSet())
[34754]797 {
798 ULONG displayWidth, displayHeight;
[52064]799 ULONG ulDummy;
800 LONG lDummy;
[34754]801 /* Takes the display lock */
[52064]802 HRESULT rc = pDisplay->i_getScreenResolution(0, &displayWidth,
803 &displayHeight, &ulDummy, &lDummy, &lDummy);
[34754]804 if (FAILED(rc))
805 return rc;
[26624]806
[47215]807 *pxAdj = displayWidth ? (x * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
808 / (LONG) displayWidth: 0;
809 *pyAdj = displayHeight ? (y * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
810 / (LONG) displayHeight: 0;
[34754]811 }
812 else
813 {
814 int32_t x1, y1, x2, y2;
[34835]815 /* Takes the display lock */
[52064]816 pDisplay->i_getFramebufferDimensions(&x1, &y1, &x2, &y2);
[47215]817 *pxAdj = x1 < x2 ? ((x - x1) * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
818 / (x2 - x1) : 0;
819 *pyAdj = y1 < y2 ? ((y - y1) * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
820 / (y2 - y1) : 0;
821 if ( *pxAdj < VMMDEV_MOUSE_RANGE_MIN
822 || *pxAdj > VMMDEV_MOUSE_RANGE_MAX
823 || *pyAdj < VMMDEV_MOUSE_RANGE_MIN
824 || *pyAdj > VMMDEV_MOUSE_RANGE_MAX)
[35212]825 if (pfValid)
826 *pfValid = false;
[34754]827 }
[26624]828 return S_OK;
829}
830
831
832/**
[32817]833 * Send an absolute mouse event to the VM. This requires either VirtualBox-
834 * specific drivers installed in the guest or absolute pointing device
835 * emulation.
[32828]836 * @note the VMMDev capability change is so that the guest knows we are sending
837 * dummy events over the PS/2 device to signal the arrival of new
838 * absolute pointer data, and not pointer real movement data
839 * @note all calls out of this object are made with no locks held!
[1]840 *
841 * @returns COM status code
[65103]842 * @param x X position (pixel), starting from 1
843 * @param y Y position (pixel), starting from 1
844 * @param dz Z movement
845 * @param dw mouse wheel movement
846 * @param aButtonState The mouse button state
[1]847 */
[50613]848HRESULT Mouse::putMouseEventAbsolute(LONG x, LONG y, LONG dz, LONG dw,
849 LONG aButtonState)
[1]850{
[47215]851 LogRel3(("%s: x=%d, y=%d, dz=%d, dw=%d, fButtons=0x%x\n",
[50613]852 __PRETTY_FUNCTION__, x, y, dz, dw, aButtonState));
[1]853
[47208]854 int32_t xAdj, yAdj;
[47215]855 uint32_t fButtonsAdj;
[35212]856 bool fValid;
[32817]857
[27208]858 /** @todo the front end should do this conversion to avoid races */
[32817]859 /** @note Or maybe not... races are pretty inherent in everything done in
860 * this object and not really bad as far as I can see. */
[50613]861 HRESULT rc = i_convertDisplayRes(x, y, &xAdj, &yAdj, &fValid);
[27160]862 if (FAILED(rc)) return rc;
863
[50613]864 fButtonsAdj = i_mouseButtonsToPDM(aButtonState);
[32817]865 /* If we are doing old-style (IRQ-less) absolute reporting to the VMM
866 * device then make sure the guest is aware of it, so that it knows to
867 * ignore relative movement on the PS/2 device. */
[50613]868 i_updateVMMDevMouseCaps(VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE, 0);
[35212]869 if (fValid)
870 {
[53965]871 rc = i_reportAbsEventToInputDevices(xAdj, yAdj, dz, dw, fButtonsAdj,
872 RT_BOOL(mfVMMDevGuestCaps & VMMDEV_MOUSE_NEW_PROTOCOL));
873 if (FAILED(rc)) return rc;
[27060]874
[50613]875 i_fireMouseEvent(true, x, y, dz, dw, aButtonState);
[35212]876 }
[53965]877 rc = i_reportAbsEventToDisplayDevice(x, y);
[33075]878
[13606]879 return rc;
[1]880}
881
[47208]882/**
[47571]883 * Send a multi-touch event. This requires multi-touch pointing device emulation.
884 * @note all calls out of this object are made with no locks held!
885 *
886 * @returns COM status code.
887 * @param aCount Number of contacts.
888 * @param aContacts Information about each contact.
889 * @param aScanTime Timestamp.
[47208]890 */
[50613]891HRESULT Mouse::putEventMultiTouch(LONG aCount,
892 const std::vector<LONG64> &aContacts,
893 ULONG aScanTime)
[47208]894{
[47571]895 LogRel3(("%s: aCount %d(actual %d), aScanTime %u\n",
[52934]896 __FUNCTION__, aCount, aContacts.size(), aScanTime));
[47208]897
[47571]898 HRESULT rc = S_OK;
[47208]899
[52934]900 if ((LONG)aContacts.size() >= aCount)
[47208]901 {
[52934]902 const LONG64 *paContacts = aCount > 0? &aContacts.front(): NULL;
[47208]903
[50613]904 rc = i_putEventMultiTouch(aCount, paContacts, aScanTime);
[47208]905 }
[47571]906 else
907 {
908 rc = E_INVALIDARG;
909 }
[47208]910
911 return rc;
912}
913
[47571]914/**
915 * Send a multi-touch event. Version for scripting languages.
916 *
917 * @returns COM status code.
918 * @param aCount Number of contacts.
919 * @param aContacts Information about each contact.
920 * @param aScanTime Timestamp.
921 */
[50613]922HRESULT Mouse::putEventMultiTouchString(LONG aCount,
923 const com::Utf8Str &aContacts,
924 ULONG aScanTime)
[47571]925{
926 /** @todo implement: convert the string to LONG64 array and call putEventMultiTouch. */
927 NOREF(aCount);
928 NOREF(aContacts);
929 NOREF(aScanTime);
930 return E_NOTIMPL;
931}
932
933
[1]934// private methods
935/////////////////////////////////////////////////////////////////////////////
936
[47571]937/* Used by PutEventMultiTouch and PutEventMultiTouchString. */
[50613]938HRESULT Mouse::i_putEventMultiTouch(LONG aCount,
[52934]939 const LONG64 *paContacts,
[50613]940 ULONG aScanTime)
[47571]941{
942 if (aCount >= 256)
943 {
944 return E_INVALIDARG;
945 }
[26650]946
[51612]947 DisplayMouseInterface *pDisplay = mParent->i_getDisplayMouseInterface();
[47571]948 ComAssertRet(pDisplay, E_FAIL);
949
[47795]950 /* Touch events are mapped to the primary monitor, because the emulated USB
951 * touchscreen device is associated with one (normally the primary) screen in the guest.
952 */
953 ULONG uScreenId = 0;
[47571]954
[47795]955 ULONG cWidth = 0;
956 ULONG cHeight = 0;
[52064]957 ULONG cBPP = 0;
[47795]958 LONG xOrigin = 0;
959 LONG yOrigin = 0;
[52064]960 HRESULT rc = pDisplay->i_getScreenResolution(uScreenId, &cWidth, &cHeight, &cBPP, &xOrigin, &yOrigin);
961 NOREF(cBPP);
[47795]962 ComAssertComRCRetRC(rc);
963
[47571]964 uint64_t* pau64Contacts = NULL;
965 uint8_t cContacts = 0;
966
967 /* Deliver 0 contacts too, touch device may use this to reset the state. */
968 if (aCount > 0)
969 {
970 /* Create a copy with converted coords. */
971 pau64Contacts = (uint64_t *)RTMemTmpAlloc(aCount * sizeof(uint64_t));
972 if (pau64Contacts)
973 {
[47795]974 int32_t x1 = xOrigin;
975 int32_t y1 = yOrigin;
976 int32_t x2 = x1 + cWidth;
977 int32_t y2 = y1 + cHeight;
[47571]978
[47798]979 LogRel3(("%s: screen [%d] %d,%d %d,%d\n",
980 __FUNCTION__, uScreenId, x1, y1, x2, y2));
[47795]981
[47571]982 LONG i;
983 for (i = 0; i < aCount; i++)
984 {
[47582]985 uint32_t u32Lo = RT_LO_U32(paContacts[i]);
986 uint32_t u32Hi = RT_HI_U32(paContacts[i]);
[47576]987 int32_t x = (int16_t)u32Lo;
988 int32_t y = (int16_t)(u32Lo >> 16);
[47575]989 uint8_t contactId = RT_BYTE1(u32Hi);
990 bool fInContact = (RT_BYTE2(u32Hi) & 0x1) != 0;
991 bool fInRange = (RT_BYTE2(u32Hi) & 0x2) != 0;
[47571]992
993 LogRel3(("%s: [%d] %d,%d id %d, inContact %d, inRange %d\n",
[47701]994 __FUNCTION__, i, x, y, contactId, fInContact, fInRange));
[47571]995
[47798]996 /* x1,y1 are inclusive and x2,y2 are exclusive,
997 * while x,y start from 1 and are inclusive.
[47571]998 */
[47798]999 if (x <= x1 || x > x2 || y <= y1 || y > y2)
[47795]1000 {
1001 /* Out of range. Skip the contact. */
1002 continue;
1003 }
[47571]1004
[47795]1005 int32_t xAdj = x1 < x2? ((x - 1 - x1) * VMMDEV_MOUSE_RANGE) / (x2 - x1) : 0;
1006 int32_t yAdj = y1 < y2? ((y - 1 - y1) * VMMDEV_MOUSE_RANGE) / (y2 - y1) : 0;
1007
[47571]1008 bool fValid = ( xAdj >= VMMDEV_MOUSE_RANGE_MIN
1009 && xAdj <= VMMDEV_MOUSE_RANGE_MAX
1010 && yAdj >= VMMDEV_MOUSE_RANGE_MIN
1011 && yAdj <= VMMDEV_MOUSE_RANGE_MAX);
1012
1013 if (fValid)
1014 {
[62379]1015 uint8_t fu8 = (uint8_t)( (fInContact? 0x01: 0x00)
1016 | (fInRange? 0x02: 0x00));
[47571]1017 pau64Contacts[cContacts] = RT_MAKE_U64_FROM_U16((uint16_t)xAdj,
1018 (uint16_t)yAdj,
1019 RT_MAKE_U16(contactId, fu8),
1020 0);
1021 cContacts++;
1022 }
1023 }
1024 }
1025 else
1026 {
1027 rc = E_OUTOFMEMORY;
1028 }
1029 }
1030
1031 if (SUCCEEDED(rc))
1032 {
[50613]1033 rc = i_reportMultiTouchEventToDevice(cContacts, cContacts? pau64Contacts: NULL, (uint32_t)aScanTime);
[47571]1034
[47848]1035 /* Send the original contact information. */
[50613]1036 i_fireMultiTouchEvent(cContacts, cContacts? paContacts: NULL, (uint32_t)aScanTime);
[47571]1037 }
1038
1039 RTMemTmpFree(pau64Contacts);
1040
1041 return rc;
1042}
1043
1044
[33758]1045/** Does the guest currently rely on the host to draw the mouse cursor or
1046 * can it switch to doing it itself in software? */
[50613]1047bool Mouse::i_guestNeedsHostCursor(void)
[26782]1048{
[33758]1049 return RT_BOOL(mfVMMDevGuestCaps & VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
1050}
1051
1052
1053/** Check what sort of reporting can be done using the devices currently
[65103]1054 * enabled. Does not consider the VMM device.
1055 *
1056 * @param pfAbs supports absolute mouse coordinates.
1057 * @param pfRel supports relative mouse coordinates.
1058 * @param pfMT supports multitouch.
1059 */
[50613]1060void Mouse::i_getDeviceCaps(bool *pfAbs, bool *pfRel, bool *pfMT)
[33758]1061{
[27060]1062 bool fAbsDev = false;
1063 bool fRelDev = false;
[47174]1064 bool fMTDev = false;
[32851]1065
[33758]1066 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
1067
1068 for (unsigned i = 0; i < MOUSE_MAX_DEVICES; ++i)
1069 if (mpDrv[i])
1070 {
1071 if (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_ABSOLUTE)
1072 fAbsDev = true;
1073 if (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_RELATIVE)
1074 fRelDev = true;
[47174]1075 if (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_MULTI_TOUCH)
1076 fMTDev = true;
[33758]1077 }
1078 if (pfAbs)
1079 *pfAbs = fAbsDev;
1080 if (pfRel)
1081 *pfRel = fRelDev;
[47358]1082 if (pfMT)
1083 *pfMT = fMTDev;
[33758]1084}
1085
1086
1087/** Does the VMM device currently support absolute reporting? */
[50613]1088bool Mouse::i_vmmdevCanAbs(void)
[33758]1089{
1090 bool fRelDev;
1091
[50613]1092 i_getDeviceCaps(NULL, &fRelDev, NULL);
[33758]1093 return (mfVMMDevGuestCaps & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE)
1094 && fRelDev;
1095}
1096
1097
1098/** Does the VMM device currently support absolute reporting? */
[50613]1099bool Mouse::i_deviceCanAbs(void)
[33758]1100{
1101 bool fAbsDev;
1102
[50613]1103 i_getDeviceCaps(&fAbsDev, NULL, NULL);
[33758]1104 return fAbsDev;
1105}
1106
1107
1108/** Can we currently send relative events to the guest? */
[50613]1109bool Mouse::i_supportsRel(void)
[33758]1110{
1111 bool fRelDev;
1112
[50613]1113 i_getDeviceCaps(NULL, &fRelDev, NULL);
[33758]1114 return fRelDev;
1115}
1116
1117
1118/** Can we currently send absolute events to the guest? */
[50613]1119bool Mouse::i_supportsAbs(void)
[33758]1120{
1121 bool fAbsDev;
1122
[50613]1123 i_getDeviceCaps(&fAbsDev, NULL, NULL);
1124 return fAbsDev || i_vmmdevCanAbs();
[33758]1125}
1126
1127
[47174]1128/** Can we currently send absolute events to the guest? */
[50613]1129bool Mouse::i_supportsMT(void)
[47174]1130{
1131 bool fMTDev;
1132
[50613]1133 i_getDeviceCaps(NULL, NULL, &fMTDev);
[47174]1134 return fMTDev;
1135}
1136
1137
[33758]1138/** Check what sort of reporting can be done using the devices currently
1139 * enabled (including the VMM device) and notify the guest and the front-end.
1140 */
[50613]1141void Mouse::i_sendMouseCapsNotifications(void)
[33758]1142{
[54054]1143 bool fRelDev, fMTDev, fCanAbs, fNeedsHostCursor;
[33758]1144
[32817]1145 {
[33758]1146 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
[32817]1147
[54054]1148 i_getDeviceCaps(NULL, &fRelDev, &fMTDev);
[50613]1149 fCanAbs = i_supportsAbs();
1150 fNeedsHostCursor = i_guestNeedsHostCursor();
[32817]1151 }
[51612]1152 mParent->i_onMouseCapabilityChange(fCanAbs, fRelDev, fMTDev, fNeedsHostCursor);
[26782]1153}
1154
1155
[1]1156/**
[26935]1157 * @interface_method_impl{PDMIMOUSECONNECTOR,pfnReportModes}
[32828]1158 * A virtual device is notifying us about its current state and capabilities
[26650]1159 */
[65103]1160DECLCALLBACK(void) Mouse::i_mouseReportModes(PPDMIMOUSECONNECTOR pInterface, bool fRelative,
1161 bool fAbsolute, bool fMultiTouch)
[26650]1162{
1163 PDRVMAINMOUSE pDrv = RT_FROM_MEMBER(pInterface, DRVMAINMOUSE, IConnector);
[65103]1164 if (fRelative)
[27060]1165 pDrv->u32DevCaps |= MOUSE_DEVCAP_RELATIVE;
[26935]1166 else
[27060]1167 pDrv->u32DevCaps &= ~MOUSE_DEVCAP_RELATIVE;
[65103]1168 if (fAbsolute)
[27060]1169 pDrv->u32DevCaps |= MOUSE_DEVCAP_ABSOLUTE;
[26650]1170 else
[27060]1171 pDrv->u32DevCaps &= ~MOUSE_DEVCAP_ABSOLUTE;
[65103]1172 if (fMultiTouch)
[47174]1173 pDrv->u32DevCaps |= MOUSE_DEVCAP_MULTI_TOUCH;
1174 else
1175 pDrv->u32DevCaps &= ~MOUSE_DEVCAP_MULTI_TOUCH;
[26650]1176
[50613]1177 pDrv->pMouse->i_sendMouseCapsNotifications();
[26650]1178}
1179
1180
1181/**
[25966]1182 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
[1]1183 */
[50613]1184DECLCALLBACK(void *) Mouse::i_drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
[1]1185{
[25966]1186 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1187 PDRVMAINMOUSE pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
[25985]1188
1189 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1190 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSECONNECTOR, &pDrv->IConnector);
[25966]1191 return NULL;
[1]1192}
1193
1194
1195/**
1196 * Destruct a mouse driver instance.
1197 *
[58170]1198 * @returns VBox status code.
[1]1199 * @param pDrvIns The driver instance data.
1200 */
[50613]1201DECLCALLBACK(void) Mouse::i_drvDestruct(PPDMDRVINS pDrvIns)
[1]1202{
[45029]1203 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
[45030]1204 PDRVMAINMOUSE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
[1]1205 LogFlow(("Mouse::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
[26001]1206
[45030]1207 if (pThis->pMouse)
[1]1208 {
[45030]1209 AutoWriteLock mouseLock(pThis->pMouse COMMA_LOCKVAL_SRC_POS);
[27208]1210 for (unsigned cDev = 0; cDev < MOUSE_MAX_DEVICES; ++cDev)
[45030]1211 if (pThis->pMouse->mpDrv[cDev] == pThis)
[27208]1212 {
[45030]1213 pThis->pMouse->mpDrv[cDev] = NULL;
[27208]1214 break;
1215 }
[1]1216 }
1217}
1218
1219
1220/**
1221 * Construct a mouse driver instance.
1222 *
[22277]1223 * @copydoc FNPDMDRVCONSTRUCT
[1]1224 */
[50613]1225DECLCALLBACK(int) Mouse::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
[1]1226{
[63244]1227 RT_NOREF(fFlags);
[45029]1228 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
[45030]1229 PDRVMAINMOUSE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
[1]1230 LogFlow(("drvMainMouse_Construct: iInstance=%d\n", pDrvIns->iInstance));
1231
1232 /*
1233 * Validate configuration.
1234 */
[47841]1235 if (!CFGMR3AreValuesValid(pCfg, "Object\0"))
[1]1236 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
[25149]1237 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
[22277]1238 ("Configuration error: Not possible to attach anything to this driver!\n"),
1239 VERR_PDM_DRVINS_NO_ATTACH);
[1]1240
1241 /*
1242 * IBase.
1243 */
[50613]1244 pDrvIns->IBase.pfnQueryInterface = Mouse::i_drvQueryInterface;
[1]1245
[50613]1246 pThis->IConnector.pfnReportModes = Mouse::i_mouseReportModes;
[26624]1247
[1]1248 /*
1249 * Get the IMousePort interface of the above driver/device.
1250 */
[45030]1251 pThis->pUpPort = (PPDMIMOUSEPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMIMOUSEPORT_IID);
1252 if (!pThis->pUpPort)
[1]1253 {
1254 AssertMsgFailed(("Configuration error: No mouse port interface above!\n"));
1255 return VERR_PDM_MISSING_INTERFACE_ABOVE;
1256 }
1257
1258 /*
1259 * Get the Mouse object pointer and update the mpDrv member.
1260 */
1261 void *pv;
[26173]1262 int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
[13835]1263 if (RT_FAILURE(rc))
[1]1264 {
[13837]1265 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
[1]1266 return rc;
1267 }
[45030]1268 pThis->pMouse = (Mouse *)pv; /** @todo Check this cast! */
[27060]1269 unsigned cDev;
[32817]1270 {
[59995]1271 AutoWriteLock mouseLock(pThis->pMouse COMMA_LOCKVAL_SRC_POS);
[32817]1272
1273 for (cDev = 0; cDev < MOUSE_MAX_DEVICES; ++cDev)
[47841]1274 if (!pThis->pMouse->mpDrv[cDev])
[32817]1275 {
[47841]1276 pThis->pMouse->mpDrv[cDev] = pThis;
[32817]1277 break;
1278 }
1279 }
[27060]1280 if (cDev == MOUSE_MAX_DEVICES)
1281 return VERR_NO_MORE_HANDLES;
[1]1282
1283 return VINF_SUCCESS;
1284}
1285
1286
1287/**
1288 * Main mouse driver registration record.
1289 */
1290const PDMDRVREG Mouse::DrvReg =
1291{
1292 /* u32Version */
1293 PDM_DRVREG_VERSION,
[26166]1294 /* szName */
[1]1295 "MainMouse",
[25893]1296 /* szRCMod */
1297 "",
1298 /* szR0Mod */
1299 "",
[1]1300 /* pszDescription */
1301 "Main mouse driver (Main as in the API).",
1302 /* fFlags */
1303 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1304 /* fClass. */
1305 PDM_DRVREG_CLASS_MOUSE,
1306 /* cMaxInstances */
[40282]1307 ~0U,
[1]1308 /* cbInstance */
1309 sizeof(DRVMAINMOUSE),
1310 /* pfnConstruct */
[50613]1311 Mouse::i_drvConstruct,
[1]1312 /* pfnDestruct */
[50613]1313 Mouse::i_drvDestruct,
[25893]1314 /* pfnRelocate */
1315 NULL,
[1]1316 /* pfnIOCtl */
1317 NULL,
1318 /* pfnPowerOn */
1319 NULL,
1320 /* pfnReset */
1321 NULL,
1322 /* pfnSuspend */
1323 NULL,
1324 /* pfnResume */
1325 NULL,
[22277]1326 /* pfnAttach */
1327 NULL,
[1]1328 /* pfnDetach */
[25149]1329 NULL,
[22277]1330 /* pfnPowerOff */
[25149]1331 NULL,
[22277]1332 /* pfnSoftReset */
1333 NULL,
1334 /* u32EndVersion */
1335 PDM_DRVREG_VERSION
[1]1336};
[14772]1337/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use