VirtualBox

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

Last change on this file since 73768 was 73003, checked in by vboxsync, 6 years ago

Main: Use setErrorBoth when we've got a VBox status code handy. (The COM status codes aren't too specfic and this may help us decode error messages and provide an alternative to strstr for API clients. setErrorBoth isn't new, btw.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.9 KB
Line 
1/* $Id: MouseImpl.cpp 73003 2018-07-09 11:09:32Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP LOG_GROUP_MAIN_MOUSE
19#include "LoggingNew.h"
20
21#include <iprt/cpp/utils.h>
22
23#include "MouseImpl.h"
24#include "DisplayImpl.h"
25#include "VMMDev.h"
26#include "MousePointerShapeWrap.h"
27
28#include "AutoCaller.h"
29
30#include <VBox/vmm/pdmdrv.h>
31#include <VBox/VMMDev.h>
32
33#include <iprt/asm.h>
34
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());
178 if (m.shape.size())
179 memcpy(&aShape.front(), &m.shape.front(), aShape.size());
180 return S_OK;
181}
182
183
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 */
191 MOUSE_DEVCAP_ABSOLUTE = 2,
192 /** The mouse device can do absolute reporting */
193 MOUSE_DEVCAP_MULTI_TOUCH = 4
194};
195/** @} */
196
197
198/**
199 * Mouse driver instance data.
200 */
201struct DRVMAINMOUSE
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. */
210 PDMIMOUSECONNECTOR IConnector;
211 /** The capabilities of this device. */
212 uint32_t u32DevCaps;
213};
214
215
216// constructor / destructor
217/////////////////////////////////////////////////////////////////////////////
218
219Mouse::Mouse()
220 : mParent(NULL)
221{
222}
223
224Mouse::~Mouse()
225{
226}
227
228
229HRESULT Mouse::FinalConstruct()
230{
231 RT_ZERO(mpDrv);
232 RT_ZERO(mPointerData);
233 mcLastX = 0x8000;
234 mcLastY = 0x8000;
235 mfLastButtons = 0;
236 mfVMMDevGuestCaps = 0;
237 return BaseFinalConstruct();
238}
239
240void Mouse::FinalRelease()
241{
242 uninit();
243 BaseFinalRelease();
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 */
255HRESULT Mouse::init (ConsoleMouseInterface *parent)
256{
257 LogFlowThisFunc(("\n"));
258
259 ComAssertRet(parent, E_INVALIDARG);
260
261 /* Enclose the state transition NotReady->InInit->Ready */
262 AutoInitSpan autoInitSpan(this);
263 AssertReturn(autoInitSpan.isOk(), E_FAIL);
264
265 unconst(mParent) = parent;
266
267 unconst(mEventSource).createObject();
268 HRESULT rc = mEventSource->init();
269 AssertComRCReturnRC(rc);
270 mMouseEvent.init(mEventSource, VBoxEventType_OnGuestMouse,
271 0, 0, 0, 0, 0, 0);
272
273 /* Confirm a successful initialization */
274 autoInitSpan.setSucceeded();
275
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{
285 LogFlowThisFunc(("\n"));
286
287 /* Enclose the state transition Ready->InUninit->NotReady */
288 AutoUninitSpan autoUninitSpan(this);
289 if (autoUninitSpan.uninitDone())
290 return;
291
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 }
298
299 mPointerShape.setNull();
300
301 RTMemFree(mPointerData.pu8Shape);
302 mPointerData.pu8Shape = NULL;
303 mPointerData.cbShape = 0;
304
305 mMouseEvent.uninit();
306 unconst(mEventSource).setNull();
307 unconst(mParent) = NULL;
308}
309
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);
316
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
339// IMouse properties
340/////////////////////////////////////////////////////////////////////////////
341
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! */
345HRESULT Mouse::i_updateVMMDevMouseCaps(uint32_t fCapsAdded,
346 uint32_t fCapsRemoved)
347{
348 VMMDevMouseInterface *pVMMDev = mParent->i_getVMMDevMouseInterface();
349 if (!pVMMDev)
350 return E_FAIL; /* No assertion, as the front-ends can send events
351 * at all sorts of inconvenient times. */
352 DisplayMouseInterface *pDisplay = mParent->i_getDisplayMouseInterface();
353 if (pDisplay == NULL)
354 return E_FAIL;
355 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
356 if (!pVMMDevPort)
357 return E_FAIL; /* same here */
358
359 int rc = pVMMDevPort->pfnUpdateMouseCapabilities(pVMMDevPort, fCapsAdded,
360 fCapsRemoved);
361 if (RT_FAILURE(rc))
362 return E_FAIL;
363 return pDisplay->i_reportHostCursorCapabilities(fCapsAdded, fCapsRemoved);
364}
365
366/**
367 * Returns whether the currently active device portfolio can accept absolute
368 * mouse events.
369 *
370 * @returns COM status code
371 * @param aAbsoluteSupported address of result variable
372 */
373HRESULT Mouse::getAbsoluteSupported(BOOL *aAbsoluteSupported)
374{
375 *aAbsoluteSupported = i_supportsAbs();
376 return S_OK;
377}
378
379/**
380 * Returns whether the currently active device portfolio can accept relative
381 * mouse events.
382 *
383 * @returns COM status code
384 * @param aRelativeSupported address of result variable
385 */
386HRESULT Mouse::getRelativeSupported(BOOL *aRelativeSupported)
387{
388 *aRelativeSupported = i_supportsRel();
389 return S_OK;
390}
391
392/**
393 * Returns whether the currently active device portfolio can accept multi-touch
394 * mouse events.
395 *
396 * @returns COM status code
397 * @param aMultiTouchSupported address of result variable
398 */
399HRESULT Mouse::getMultiTouchSupported(BOOL *aMultiTouchSupported)
400{
401 *aMultiTouchSupported = i_supportsMT();
402 return S_OK;
403}
404
405/**
406 * Returns whether the guest can currently switch to drawing the mouse cursor
407 * itself if it is asked to by the front-end.
408 *
409 * @returns COM status code
410 * @param aNeedsHostCursor address of result variable
411 */
412HRESULT Mouse::getNeedsHostCursor(BOOL *aNeedsHostCursor)
413{
414 *aNeedsHostCursor = i_guestNeedsHostCursor();
415 return S_OK;
416}
417
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
450// IMouse methods
451/////////////////////////////////////////////////////////////////////////////
452
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. */
456static uint32_t i_mouseButtonsToPDM(LONG buttonState)
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
472HRESULT Mouse::getEventSource(ComPtr<IEventSource> &aEventSource)
473{
474 // no need to lock - lifetime constant
475 mEventSource.queryInterfaceTo(aEventSource.asOutParam());
476 return S_OK;
477}
478
479/**
480 * Send a relative pointer event to the relative device we deem most
481 * appropriate.
482 *
483 * @returns COM status code
484 */
485HRESULT Mouse::i_reportRelEventToMouseDev(int32_t dx, int32_t dy, int32_t dz,
486 int32_t dw, uint32_t fButtons)
487{
488 if (dx || dy || dz || dw || fButtons != mfLastButtons)
489 {
490 PPDMIMOUSEPORT pUpPort = NULL;
491 {
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 }
499 }
500 if (!pUpPort)
501 return S_OK;
502
503 int vrc = pUpPort->pfnPutEvent(pUpPort, dx, dy, dz, dw, fButtons);
504
505 if (RT_FAILURE(vrc))
506 return setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
507 tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
508 vrc);
509 mfLastButtons = fButtons;
510 }
511 return S_OK;
512}
513
514
515/**
516 * Send an absolute pointer event to the emulated absolute device we deem most
517 * appropriate.
518 *
519 * @returns COM status code
520 */
521HRESULT Mouse::i_reportAbsEventToMouseDev(int32_t x, int32_t y,
522 int32_t dz, int32_t dw, uint32_t fButtons)
523{
524 if ( x < VMMDEV_MOUSE_RANGE_MIN
525 || x > VMMDEV_MOUSE_RANGE_MAX)
526 return S_OK;
527 if ( y < VMMDEV_MOUSE_RANGE_MIN
528 || y > VMMDEV_MOUSE_RANGE_MAX)
529 return S_OK;
530 if ( x != mcLastX || y != mcLastY
531 || dz || dw || fButtons != mfLastButtons)
532 {
533 PPDMIMOUSEPORT pUpPort = NULL;
534 {
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 }
542 }
543 if (!pUpPort)
544 return S_OK;
545
546 int vrc = pUpPort->pfnPutEventAbs(pUpPort, x, y, dz,
547 dw, fButtons);
548 if (RT_FAILURE(vrc))
549 return setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
550 tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
551 vrc);
552 mfLastButtons = fButtons;
553
554 }
555 return S_OK;
556}
557
558HRESULT Mouse::i_reportMultiTouchEventToDevice(uint8_t cContacts,
559 const uint64_t *pau64Contacts,
560 uint32_t u32ScanTime)
561{
562 HRESULT hrc = S_OK;
563
564 PPDMIMOUSEPORT pUpPort = NULL;
565 {
566 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
567
568 unsigned i;
569 for (i = 0; i < MOUSE_MAX_DEVICES; ++i)
570 {
571 if ( mpDrv[i]
572 && (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_MULTI_TOUCH))
573 {
574 pUpPort = mpDrv[i]->pUpPort;
575 break;
576 }
577 }
578 }
579
580 if (pUpPort)
581 {
582 int vrc = pUpPort->pfnPutEventMultiTouch(pUpPort, cContacts, pau64Contacts, u32ScanTime);
583 if (RT_FAILURE(vrc))
584 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
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;
594}
595
596
597/**
598 * Send an absolute position event to the VMM device.
599 * @note all calls out of this object are made with no locks held!
600 *
601 * @returns COM status code
602 */
603HRESULT Mouse::i_reportAbsEventToVMMDev(int32_t x, int32_t y)
604{
605 VMMDevMouseInterface *pVMMDev = mParent->i_getVMMDevMouseInterface();
606 ComAssertRet(pVMMDev, E_FAIL);
607 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
608 ComAssertRet(pVMMDevPort, E_FAIL);
609
610 if (x != mcLastX || y != mcLastY)
611 {
612 int vrc = pVMMDevPort->pfnSetAbsoluteMouse(pVMMDevPort,
613 x, y);
614 if (RT_FAILURE(vrc))
615 return setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
616 tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
617 vrc);
618 }
619 return S_OK;
620}
621
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 */
629HRESULT Mouse::i_reportAbsEventToInputDevices(int32_t x, int32_t y, int32_t dz, int32_t dw, uint32_t fButtons,
630 bool fUsesVMMDevEvent)
631{
632 HRESULT rc;
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
638 if (i_vmmdevCanAbs())
639 {
640 /*
641 * Send the absolute mouse position to the VMM device.
642 */
643 if (x != mcLastX || y != mcLastY)
644 {
645 rc = i_reportAbsEventToVMMDev(x, y);
646 cJiggle = !fUsesVMMDevEvent;
647 }
648 rc = i_reportRelEventToMouseDev(cJiggle, 0, dz, dw, fButtons);
649 }
650 else
651 rc = i_reportAbsEventToMouseDev(x, y, dz, dw, fButtons);
652
653 mcLastX = x;
654 mcLastY = y;
655 return rc;
656}
657
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
680void Mouse::i_fireMouseEvent(bool fAbsolute, LONG x, LONG y, LONG dz, LONG dw,
681 LONG fButtons)
682{
683 /* If mouse button is pressed, we generate new event, to avoid reusable events coalescing and thus
684 dropping key press events */
685 GuestMouseEventMode_T mode;
686 if (fAbsolute)
687 mode = GuestMouseEventMode_Absolute;
688 else
689 mode = GuestMouseEventMode_Relative;
690
691 if (fButtons != 0)
692 {
693 VBoxEventDesc evDesc;
694 evDesc.init(mEventSource, VBoxEventType_OnGuestMouse, mode, x, y,
695 dz, dw, fButtons);
696 evDesc.fire(0);
697 }
698 else
699 {
700 mMouseEvent.reinit(VBoxEventType_OnGuestMouse, mode, x, y, dz, dw,
701 fButtons);
702 mMouseEvent.fire(0);
703 }
704}
705
706void Mouse::i_fireMultiTouchEvent(uint8_t cContacts,
707 const LONG64 *paContacts,
708 uint32_t u32ScanTime)
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);
714
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
733/**
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
738 *
739 * @returns COM status code
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.
745 */
746HRESULT Mouse::putMouseEvent(LONG dx, LONG dy, LONG dz, LONG dw,
747 LONG aButtonState)
748{
749 HRESULT rc;
750 uint32_t fButtonsAdj;
751
752 LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d\n", __PRETTY_FUNCTION__,
753 dx, dy, dz, dw));
754
755 fButtonsAdj = i_mouseButtonsToPDM(aButtonState);
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. */
758 i_updateVMMDevMouseCaps(0, VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE);
759 rc = i_reportRelEventToMouseDev(dx, dy, dz, dw, fButtonsAdj);
760
761 i_fireMouseEvent(false, dx, dy, dz, dw, aButtonState);
762
763 return rc;
764}
765
766/**
767 * Convert an (X, Y) value pair in screen co-ordinates (starting from 1) to a
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.
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.
778 *
779 * @returns COM status value
780 */
781HRESULT Mouse::i_convertDisplayRes(LONG x, LONG y, int32_t *pxAdj, int32_t *pyAdj,
782 bool *pfValid)
783{
784 AssertPtrReturn(pxAdj, E_POINTER);
785 AssertPtrReturn(pyAdj, E_POINTER);
786 AssertPtrNullReturn(pfValid, E_POINTER);
787 DisplayMouseInterface *pDisplay = mParent->i_getDisplayMouseInterface();
788 ComAssertRet(pDisplay, E_FAIL);
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 */
792 enum { ADJUST_RANGE = - 3 * VMMDEV_MOUSE_RANGE / 4 };
793
794 if (pfValid)
795 *pfValid = true;
796 if (!(mfVMMDevGuestCaps & VMMDEV_MOUSE_NEW_PROTOCOL) && !pDisplay->i_isInputMappingSet())
797 {
798 ULONG displayWidth, displayHeight;
799 ULONG ulDummy;
800 LONG lDummy;
801 /* Takes the display lock */
802 HRESULT rc = pDisplay->i_getScreenResolution(0, &displayWidth,
803 &displayHeight, &ulDummy, &lDummy, &lDummy);
804 if (FAILED(rc))
805 return rc;
806
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;
811 }
812 else
813 {
814 int32_t x1, y1, x2, y2;
815 /* Takes the display lock */
816 pDisplay->i_getFramebufferDimensions(&x1, &y1, &x2, &y2);
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)
825 if (pfValid)
826 *pfValid = false;
827 }
828 return S_OK;
829}
830
831
832/**
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.
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!
840 *
841 * @returns COM status code
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
847 */
848HRESULT Mouse::putMouseEventAbsolute(LONG x, LONG y, LONG dz, LONG dw,
849 LONG aButtonState)
850{
851 LogRel3(("%s: x=%d, y=%d, dz=%d, dw=%d, fButtons=0x%x\n",
852 __PRETTY_FUNCTION__, x, y, dz, dw, aButtonState));
853
854 int32_t xAdj, yAdj;
855 uint32_t fButtonsAdj;
856 bool fValid;
857
858 /** @todo the front end should do this conversion to avoid races */
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. */
861 HRESULT rc = i_convertDisplayRes(x, y, &xAdj, &yAdj, &fValid);
862 if (FAILED(rc)) return rc;
863
864 fButtonsAdj = i_mouseButtonsToPDM(aButtonState);
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. */
868 i_updateVMMDevMouseCaps(VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE, 0);
869 if (fValid)
870 {
871 rc = i_reportAbsEventToInputDevices(xAdj, yAdj, dz, dw, fButtonsAdj,
872 RT_BOOL(mfVMMDevGuestCaps & VMMDEV_MOUSE_NEW_PROTOCOL));
873 if (FAILED(rc)) return rc;
874
875 i_fireMouseEvent(true, x, y, dz, dw, aButtonState);
876 }
877 rc = i_reportAbsEventToDisplayDevice(x, y);
878
879 return rc;
880}
881
882/**
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.
890 */
891HRESULT Mouse::putEventMultiTouch(LONG aCount,
892 const std::vector<LONG64> &aContacts,
893 ULONG aScanTime)
894{
895 LogRel3(("%s: aCount %d(actual %d), aScanTime %u\n",
896 __FUNCTION__, aCount, aContacts.size(), aScanTime));
897
898 HRESULT rc = S_OK;
899
900 if ((LONG)aContacts.size() >= aCount)
901 {
902 const LONG64 *paContacts = aCount > 0? &aContacts.front(): NULL;
903
904 rc = i_putEventMultiTouch(aCount, paContacts, aScanTime);
905 }
906 else
907 {
908 rc = E_INVALIDARG;
909 }
910
911 return rc;
912}
913
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 */
922HRESULT Mouse::putEventMultiTouchString(LONG aCount,
923 const com::Utf8Str &aContacts,
924 ULONG aScanTime)
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
934// private methods
935/////////////////////////////////////////////////////////////////////////////
936
937/* Used by PutEventMultiTouch and PutEventMultiTouchString. */
938HRESULT Mouse::i_putEventMultiTouch(LONG aCount,
939 const LONG64 *paContacts,
940 ULONG aScanTime)
941{
942 if (aCount >= 256)
943 {
944 return E_INVALIDARG;
945 }
946
947 DisplayMouseInterface *pDisplay = mParent->i_getDisplayMouseInterface();
948 ComAssertRet(pDisplay, E_FAIL);
949
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;
954
955 ULONG cWidth = 0;
956 ULONG cHeight = 0;
957 ULONG cBPP = 0;
958 LONG xOrigin = 0;
959 LONG yOrigin = 0;
960 HRESULT rc = pDisplay->i_getScreenResolution(uScreenId, &cWidth, &cHeight, &cBPP, &xOrigin, &yOrigin);
961 NOREF(cBPP);
962 ComAssertComRCRetRC(rc);
963
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 {
974 int32_t x1 = xOrigin;
975 int32_t y1 = yOrigin;
976 int32_t x2 = x1 + cWidth;
977 int32_t y2 = y1 + cHeight;
978
979 LogRel3(("%s: screen [%d] %d,%d %d,%d\n",
980 __FUNCTION__, uScreenId, x1, y1, x2, y2));
981
982 LONG i;
983 for (i = 0; i < aCount; i++)
984 {
985 uint32_t u32Lo = RT_LO_U32(paContacts[i]);
986 uint32_t u32Hi = RT_HI_U32(paContacts[i]);
987 int32_t x = (int16_t)u32Lo;
988 int32_t y = (int16_t)(u32Lo >> 16);
989 uint8_t contactId = RT_BYTE1(u32Hi);
990 bool fInContact = (RT_BYTE2(u32Hi) & 0x1) != 0;
991 bool fInRange = (RT_BYTE2(u32Hi) & 0x2) != 0;
992
993 LogRel3(("%s: [%d] %d,%d id %d, inContact %d, inRange %d\n",
994 __FUNCTION__, i, x, y, contactId, fInContact, fInRange));
995
996 /* x1,y1 are inclusive and x2,y2 are exclusive,
997 * while x,y start from 1 and are inclusive.
998 */
999 if (x <= x1 || x > x2 || y <= y1 || y > y2)
1000 {
1001 /* Out of range. Skip the contact. */
1002 continue;
1003 }
1004
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
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 {
1015 uint8_t fu8 = (uint8_t)( (fInContact? 0x01: 0x00)
1016 | (fInRange? 0x02: 0x00));
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 {
1033 rc = i_reportMultiTouchEventToDevice(cContacts, cContacts? pau64Contacts: NULL, (uint32_t)aScanTime);
1034
1035 /* Send the original contact information. */
1036 i_fireMultiTouchEvent(cContacts, cContacts? paContacts: NULL, (uint32_t)aScanTime);
1037 }
1038
1039 RTMemTmpFree(pau64Contacts);
1040
1041 return rc;
1042}
1043
1044
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? */
1047bool Mouse::i_guestNeedsHostCursor(void)
1048{
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
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 */
1060void Mouse::i_getDeviceCaps(bool *pfAbs, bool *pfRel, bool *pfMT)
1061{
1062 bool fAbsDev = false;
1063 bool fRelDev = false;
1064 bool fMTDev = false;
1065
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;
1075 if (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_MULTI_TOUCH)
1076 fMTDev = true;
1077 }
1078 if (pfAbs)
1079 *pfAbs = fAbsDev;
1080 if (pfRel)
1081 *pfRel = fRelDev;
1082 if (pfMT)
1083 *pfMT = fMTDev;
1084}
1085
1086
1087/** Does the VMM device currently support absolute reporting? */
1088bool Mouse::i_vmmdevCanAbs(void)
1089{
1090 bool fRelDev;
1091
1092 i_getDeviceCaps(NULL, &fRelDev, NULL);
1093 return (mfVMMDevGuestCaps & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE)
1094 && fRelDev;
1095}
1096
1097
1098/** Does the VMM device currently support absolute reporting? */
1099bool Mouse::i_deviceCanAbs(void)
1100{
1101 bool fAbsDev;
1102
1103 i_getDeviceCaps(&fAbsDev, NULL, NULL);
1104 return fAbsDev;
1105}
1106
1107
1108/** Can we currently send relative events to the guest? */
1109bool Mouse::i_supportsRel(void)
1110{
1111 bool fRelDev;
1112
1113 i_getDeviceCaps(NULL, &fRelDev, NULL);
1114 return fRelDev;
1115}
1116
1117
1118/** Can we currently send absolute events to the guest? */
1119bool Mouse::i_supportsAbs(void)
1120{
1121 bool fAbsDev;
1122
1123 i_getDeviceCaps(&fAbsDev, NULL, NULL);
1124 return fAbsDev || i_vmmdevCanAbs();
1125}
1126
1127
1128/** Can we currently send absolute events to the guest? */
1129bool Mouse::i_supportsMT(void)
1130{
1131 bool fMTDev;
1132
1133 i_getDeviceCaps(NULL, NULL, &fMTDev);
1134 return fMTDev;
1135}
1136
1137
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 */
1141void Mouse::i_sendMouseCapsNotifications(void)
1142{
1143 bool fRelDev, fMTDev, fCanAbs, fNeedsHostCursor;
1144
1145 {
1146 AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
1147
1148 i_getDeviceCaps(NULL, &fRelDev, &fMTDev);
1149 fCanAbs = i_supportsAbs();
1150 fNeedsHostCursor = i_guestNeedsHostCursor();
1151 }
1152 mParent->i_onMouseCapabilityChange(fCanAbs, fRelDev, fMTDev, fNeedsHostCursor);
1153}
1154
1155
1156/**
1157 * @interface_method_impl{PDMIMOUSECONNECTOR,pfnReportModes}
1158 * A virtual device is notifying us about its current state and capabilities
1159 */
1160DECLCALLBACK(void) Mouse::i_mouseReportModes(PPDMIMOUSECONNECTOR pInterface, bool fRelative,
1161 bool fAbsolute, bool fMultiTouch)
1162{
1163 PDRVMAINMOUSE pDrv = RT_FROM_MEMBER(pInterface, DRVMAINMOUSE, IConnector);
1164 if (fRelative)
1165 pDrv->u32DevCaps |= MOUSE_DEVCAP_RELATIVE;
1166 else
1167 pDrv->u32DevCaps &= ~MOUSE_DEVCAP_RELATIVE;
1168 if (fAbsolute)
1169 pDrv->u32DevCaps |= MOUSE_DEVCAP_ABSOLUTE;
1170 else
1171 pDrv->u32DevCaps &= ~MOUSE_DEVCAP_ABSOLUTE;
1172 if (fMultiTouch)
1173 pDrv->u32DevCaps |= MOUSE_DEVCAP_MULTI_TOUCH;
1174 else
1175 pDrv->u32DevCaps &= ~MOUSE_DEVCAP_MULTI_TOUCH;
1176
1177 pDrv->pMouse->i_sendMouseCapsNotifications();
1178}
1179
1180
1181/**
1182 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1183 */
1184DECLCALLBACK(void *) Mouse::i_drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1185{
1186 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1187 PDRVMAINMOUSE pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
1188
1189 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1190 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSECONNECTOR, &pDrv->IConnector);
1191 return NULL;
1192}
1193
1194
1195/**
1196 * Destruct a mouse driver instance.
1197 *
1198 * @returns VBox status code.
1199 * @param pDrvIns The driver instance data.
1200 */
1201DECLCALLBACK(void) Mouse::i_drvDestruct(PPDMDRVINS pDrvIns)
1202{
1203 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1204 PDRVMAINMOUSE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
1205 LogFlow(("Mouse::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
1206
1207 if (pThis->pMouse)
1208 {
1209 AutoWriteLock mouseLock(pThis->pMouse COMMA_LOCKVAL_SRC_POS);
1210 for (unsigned cDev = 0; cDev < MOUSE_MAX_DEVICES; ++cDev)
1211 if (pThis->pMouse->mpDrv[cDev] == pThis)
1212 {
1213 pThis->pMouse->mpDrv[cDev] = NULL;
1214 break;
1215 }
1216 }
1217}
1218
1219
1220/**
1221 * Construct a mouse driver instance.
1222 *
1223 * @copydoc FNPDMDRVCONSTRUCT
1224 */
1225DECLCALLBACK(int) Mouse::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1226{
1227 RT_NOREF(fFlags);
1228 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1229 PDRVMAINMOUSE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
1230 LogFlow(("drvMainMouse_Construct: iInstance=%d\n", pDrvIns->iInstance));
1231
1232 /*
1233 * Validate configuration.
1234 */
1235 if (!CFGMR3AreValuesValid(pCfg, "Object\0"))
1236 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
1237 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
1238 ("Configuration error: Not possible to attach anything to this driver!\n"),
1239 VERR_PDM_DRVINS_NO_ATTACH);
1240
1241 /*
1242 * IBase.
1243 */
1244 pDrvIns->IBase.pfnQueryInterface = Mouse::i_drvQueryInterface;
1245
1246 pThis->IConnector.pfnReportModes = Mouse::i_mouseReportModes;
1247
1248 /*
1249 * Get the IMousePort interface of the above driver/device.
1250 */
1251 pThis->pUpPort = (PPDMIMOUSEPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMIMOUSEPORT_IID);
1252 if (!pThis->pUpPort)
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;
1262 int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
1263 if (RT_FAILURE(rc))
1264 {
1265 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
1266 return rc;
1267 }
1268 pThis->pMouse = (Mouse *)pv; /** @todo Check this cast! */
1269 unsigned cDev;
1270 {
1271 AutoWriteLock mouseLock(pThis->pMouse COMMA_LOCKVAL_SRC_POS);
1272
1273 for (cDev = 0; cDev < MOUSE_MAX_DEVICES; ++cDev)
1274 if (!pThis->pMouse->mpDrv[cDev])
1275 {
1276 pThis->pMouse->mpDrv[cDev] = pThis;
1277 break;
1278 }
1279 }
1280 if (cDev == MOUSE_MAX_DEVICES)
1281 return VERR_NO_MORE_HANDLES;
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,
1294 /* szName */
1295 "MainMouse",
1296 /* szRCMod */
1297 "",
1298 /* szR0Mod */
1299 "",
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 */
1307 ~0U,
1308 /* cbInstance */
1309 sizeof(DRVMAINMOUSE),
1310 /* pfnConstruct */
1311 Mouse::i_drvConstruct,
1312 /* pfnDestruct */
1313 Mouse::i_drvDestruct,
1314 /* pfnRelocate */
1315 NULL,
1316 /* pfnIOCtl */
1317 NULL,
1318 /* pfnPowerOn */
1319 NULL,
1320 /* pfnReset */
1321 NULL,
1322 /* pfnSuspend */
1323 NULL,
1324 /* pfnResume */
1325 NULL,
1326 /* pfnAttach */
1327 NULL,
1328 /* pfnDetach */
1329 NULL,
1330 /* pfnPowerOff */
1331 NULL,
1332 /* pfnSoftReset */
1333 NULL,
1334 /* u32EndVersion */
1335 PDM_DRVREG_VERSION
1336};
1337/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use