VirtualBox

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

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