VirtualBox

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

Last change on this file since 106028 was 105010, checked in by vboxsync, 5 months ago

Video Recording: Big revamp to improve overall performance. We now don't rely on the periodic display refresh callback anymore to render the entire framebuffer but now rely on delta updates ("dirty rectangles"). Also, we now only encode new frames when an area has changed. This also needed cursor position + change change notifications, as we render the cursor on the host side if mouse integration is enabled (requires 7.1 Guest Additions as of now). Optimized the BGRA32->YUV IV420 color space conversion as well as the overall amount of pixel data shuffled forth and back. Added a new testcase for the cropping/centering code [build fixes]. bugref:10650

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