VirtualBox

Changeset 47571 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Aug 7, 2013 9:49:33 AM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
87771
Message:

include,Devices,Main,VirtualBox: multi-touch input.

Location:
trunk/src/VBox
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Input/DevPS2.cpp

    r47259 r47571  
    13911391
    13921392/**
    1393  * @interface_method_impl{PDMIMOUSEPORT, pfnPutEventMT}
    1394  */
    1395 static DECLCALLBACK(int) kbdMousePutEventMT(PPDMIMOUSEPORT pInterface,
    1396                                             uint32_t x, uint32_t y,
    1397                                             uint32_t cContact,
    1398                                             uint32_t fContact)
     1393 * @interface_method_impl{PDMIMOUSEPORT, pfnPutEventMultiTouch}
     1394 */
     1395static DECLCALLBACK(int) kbdMousePutEventMultiTouch(PPDMIMOUSEPORT pInterface,
     1396                                                    uint8_t cContacts,
     1397                                                    const uint64_t *pau64Contacts,
     1398                                                    uint32_t u32ScanTime)
    13991399{
    14001400    AssertFailedReturn(VERR_NOT_SUPPORTED);
    1401     NOREF(pInterface); NOREF(x); NOREF(y); NOREF(cContact); NOREF(fContact);
     1401    NOREF(pInterface); NOREF(cContacts); NOREF(pau64Contacts); NOREF(u32ScanTime);
    14021402}
    14031403
     
    15681568    pThis->Mouse.IPort.pfnPutEvent          = kbdMousePutEvent;
    15691569    pThis->Mouse.IPort.pfnPutEventAbs       = kbdMousePutEventAbs;
    1570     pThis->Mouse.IPort.pfnPutEventMT        = kbdMousePutEventMT;
     1570    pThis->Mouse.IPort.pfnPutEventMultiTouch = kbdMousePutEventMultiTouch;
    15711571
    15721572    /*
  • trunk/src/VBox/Devices/Input/DrvMouseQueue.cpp

    r47360 r47571  
    6161 * Event type for @a DRVMOUSEQUEUEITEM
    6262 */
    63 enum EVENTTYPE { RELATIVE, ABSOLUTE, MULTITOUCH };
     63enum EVENTTYPE { RELATIVE, ABSOLUTE };
    6464
    6565/**
     
    9090            int32_t     dw;
    9191        } Absolute;
    92         struct
    93         {
    94             uint32_t    fContact;
    95             uint32_t    x;
    96             uint32_t    y;
    97             uint32_t    cContact;
    98         } MultiTouch;
    9992    } u;
    10093} DRVMOUSEQUEUEITEM, *PDRVMOUSEQUEUEITEM;
     
    181174
    182175
    183 /**
    184  * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventMT}
    185  */
    186 static DECLCALLBACK(int) drvMouseQueuePutEventMT(PPDMIMOUSEPORT pInterface,
    187                                                  uint32_t x, uint32_t y,
    188                                                  uint32_t cContact,
    189                                                  uint32_t fContact)
    190 {
    191     PDRVMOUSEQUEUE pDrv = IMOUSEPORT_2_DRVMOUSEQUEUE(pInterface);
    192     if (pDrv->fInactive)
    193         return VINF_SUCCESS;
    194 
    195     PDRVMOUSEQUEUEITEM pItem = (PDRVMOUSEQUEUEITEM)PDMQueueAlloc(pDrv->pQueue);
    196     if (pItem)
    197     {
    198         RT_ZERO(pItem->u.padding);
    199         pItem->enmType               = MULTITOUCH;
    200         pItem->u.MultiTouch.x        = x;
    201         pItem->u.MultiTouch.y        = y;
    202         pItem->u.MultiTouch.cContact = cContact;
    203         pItem->u.MultiTouch.fContact = fContact;
    204         PDMQueueInsert(pDrv->pQueue, &pItem->Core);
    205         return VINF_SUCCESS;
    206     }
    207     return VERR_PDM_NO_QUEUE_ITEMS;
    208 }
    209 
     176static DECLCALLBACK(int) drvMouseQueuePutEventMultiTouch(PPDMIMOUSEPORT pInterface,
     177                                                         uint8_t cContacts,
     178                                                         const uint64_t *pau64Contacts,
     179                                                         uint32_t u32ScanTime)
     180{
     181    PDRVMOUSEQUEUE pThis = IMOUSEPORT_2_DRVMOUSEQUEUE(pInterface);
     182    return pThis->pUpPort->pfnPutEventMultiTouch(pThis->pUpPort, cContacts, pau64Contacts, u32ScanTime);
     183}
    210184
    211185/* -=-=-=-=- IConnector -=-=-=-=- */
     
    260234                                            pItem->u.Absolute.dw,
    261235                                            pItem->u.Absolute.fButtons);
    262     else if (pItem->enmType == MULTITOUCH)
    263         rc = pThis->pUpPort->pfnPutEventMT(pThis->pUpPort,
    264                                            pItem->u.MultiTouch.x,
    265                                            pItem->u.MultiTouch.y,
    266                                            pItem->u.MultiTouch.cContact,
    267                                            pItem->u.MultiTouch.fContact);
    268236    else
    269237        return false;
     
    366334    pDrv->IPort.pfnPutEvent                 = drvMouseQueuePutEvent;
    367335    pDrv->IPort.pfnPutEventAbs              = drvMouseQueuePutEventAbs;
    368     pDrv->IPort.pfnPutEventMT               = drvMouseQueuePutEventMT;
     336    pDrv->IPort.pfnPutEventMultiTouch       = drvMouseQueuePutEventMultiTouch;
    369337
    370338    /*
  • trunk/src/VBox/Devices/Input/UsbMouse.cpp

    r47468 r47571  
    139139            uint32_t    fButtons;
    140140        } Absolute;
    141         struct
    142         {
    143             uint32_t    fContact;
    144             uint32_t    x;
    145             uint32_t    y;
    146             uint32_t    cContact;
    147         } MultiTouch;
    148141    } u;
    149142} USBHIDM_ACCUM, *PUSBHIDM_ACCUM;
     143
     144#define MT_CONTACTS_PER_REPORT 5
     145
     146#define MT_CONTACT_MAX_COUNT 10
     147
     148#define MT_CONTACT_F_IN_CONTACT 0x01
     149#define MT_CONTACT_F_IN_RANGE   0x02
     150
     151#define MT_CONTACT_S_ACTIVE    0x01 /* Contact must be reported to the guest. */
     152#define MT_CONTACT_S_CANCELLED 0x02 /* Contact loss must be reported to the guest. */
     153#define MT_CONTACT_S_REUSED    0x04 /* Report contact loss for the oldId and then new contact for the id. */
     154#define MT_CONTACT_S_DIRTY     0x08 /* Temporary flag used to track already processed elements. */
     155
     156typedef struct MTCONTACT
     157{
     158    uint16_t x;
     159    uint16_t y;
     160    uint8_t  id;
     161    uint8_t  flags;
     162    uint8_t  status;
     163    uint8_t  oldId; /* Valid only if MT_CONTACT_S_REUSED is set. */
     164} MTCONTACT;
    150165
    151166
     
    211226    } Lun0;
    212227
     228    MTCONTACT aCurrentContactState[MT_CONTACT_MAX_COUNT];
     229    MTCONTACT aReportingContactState[MT_CONTACT_MAX_COUNT];
     230    uint32_t u32LastTouchScanTime;
     231    bool fTouchReporting;
    213232} USBHID;
    214233/** Pointer to the USB HID instance data. */
    215234typedef USBHID *PUSBHID;
    216235
     236#pragma pack(1)
    217237/**
    218238 * The USB HID report structure for relative device.
     
    238258
    239259/**
    240  * The USB HID report structure for the multi-touch device.
    241  */
    242 
    243 typedef struct USBHIDMT_REPORT
    244 {
    245     uint8_t     idReport;
    246     uint8_t     fContact;
    247     uint16_t    x;
    248     uint16_t    y;
    249     uint8_t     cContact;
    250 } USBHIDMT_REPORT, *PUSBHIDMT_REPORT;
    251 
    252 /**
    253  * The combined USB HID report union for relative, absolute and multi-touch
     260 * The combined USB HID report union for relative and absolute
    254261 * devices.
    255262 */
     
    258265    USBHIDM_REPORT      m;
    259266    USBHIDT_REPORT      t;
    260     USBHIDMT_REPORT     mt;
    261267} USBHIDTM_REPORT, *PUSBHIDTM_REPORT;
     268
     269/**
     270 * The USB HID report structure for the multi-touch device.
     271 */
     272typedef struct USBHIDMT_REPORT
     273{
     274    uint8_t     idReport;
     275    uint8_t     cContacts;
     276    struct
     277    {
     278        uint8_t     fContact;
     279        uint8_t     cContact;
     280        uint16_t    x;
     281        uint16_t    y;
     282    } aContacts[MT_CONTACTS_PER_REPORT];
     283    uint32_t    u32ScanTime;
     284} USBHIDMT_REPORT, *PUSBHIDMT_REPORT;
     285#pragma pack()
    262286
    263287/*******************************************************************************
     
    303327            /* .bmAttributes = */       3 /* interrupt */,
    304328            /* .wMaxPacketSize = */     6,
     329            /* .bInterval = */          10,
     330        },
     331        /* .pvMore = */     NULL,
     332        /* .pvClass = */    NULL,
     333        /* .cbClass = */    0
     334    },
     335};
     336
     337static const VUSBDESCENDPOINTEX g_aUsbHidMTEndpointDescs[] =
     338{
     339    {
     340        {
     341            /* .bLength = */            sizeof(VUSBDESCENDPOINT),
     342            /* .bDescriptorType = */    VUSB_DT_ENDPOINT,
     343            /* .bEndpointAddress = */   0x81 /* ep=1, in */,
     344            /* .bmAttributes = */       3 /* interrupt */,
     345            /* .wMaxPacketSize = */     64,
    305346            /* .bInterval = */          10,
    306347        },
     
    384425};
    385426
     427/*
     428 * Multi-touch device implementation based on "Windows Pointer Device Data Delivery Protocol"
     429 * specification.
     430 */
     431
     432#define REPORTID_TOUCH_POINTER   1
     433#define REPORTID_TOUCH_EVENT     2
     434#define REPORTID_TOUCH_MAX_COUNT 3
     435#define REPORTID_TOUCH_QABLOB    4
     436#define REPORTID_TOUCH_DEVCONFIG 5
     437
    386438static const uint8_t g_UsbHidMTReportDesc[] =
    387439{
    388     /* Usage Page */                0x05, 0x0D,     /* Digitisers */
    389     /* Usage */                     0x09, 0x04,     /* Touch Screen */
    390     /* Collection */                0xA1, 0x01,     /* Application */
    391     /* Report ID */                 0x85, REPORTID_MOUSE,
    392     /* Usage */                     0x09, 0x22,     /* Finger */
    393     /* Collection */                0xA1, 0x00,     /* Physical */
    394     /* Usage */                     0x09, 0x42,     /* Tip Switch */
    395     /* Usage */                     0x09, 0x32,     /* In Range */
    396     /* Logical Minimum */           0x15, 0x00,     /* 0 */
    397     /* Logical Maximum */           0x25, 0x01,     /* 1 */
    398     /* Report Count */              0x95, 0x02,     /* 2 */
    399     /* Report Size */               0x75, 0x01,     /* 1 */
    400     /* Input */                     0x81, 0x02,     /* Data, Value, Absolute, Bit field */
    401     /* Report Count */              0x95, 0x06,     /* 6 (padding bits) */
    402     /* Input */                     0x81, 0x03,     /* Constant, Value, Absolute, Bit field */
    403     /* Usage Page */                0x05, 0x01,     /* Generic Desktop */
    404     /* Usage */                     0x09, 0x30,     /* X */
    405     /* Usage */                     0x09, 0x31,     /* Y */
    406     /* Logical Minimum */           0x15, 0x00,     /* 0 */
    407     /* Logical Maximum */           0x26, 0xFF,0x7F,/* 0x7fff */
    408     /* Physical Minimum */          0x35, 0x00,     /* 0 */
    409     /* Physical Maximum */          0x46, 0xFF,0x7F,/* 0x7fff */
    410     /* Report Size */               0x75, 0x10,     /* 16 */
    411     /* Report Count */              0x95, 0x02,     /* 2 */
    412     /* Input */                     0x81, 0x02,     /* Data, Value, Absolute, Bit field */
    413     /* Usage Page */                0x05, 0x0D,     /* Digitisers */
    414     /* Usage */                     0x09, 0x51,     /* Contact Identifier */
    415     /* Report Count */              0x95, 0x01,     /* 1 */
    416     /* Report Size */               0x75, 0x08,     /* 8 */
    417     /* Input */                     0x81, 0x02,     /* Data, Value, Absolute, Bit field */
    418     /* End Collection */            0xC0,
    419     /* Report ID */                 0x85, REPORTID_MAX_COUNT,
    420     /* Usage */                     0x09, 0x55,     /* Contact Count Maximum */
    421     /* Report Count */              0x95, 0x01,     /* 1 */
    422     /* Logical Maximum */           0x25, 0x40,     /* 64 */
    423     /* Feature */                   0xB1, 0x03,     /* Constant, Value, Absolute, Bit field */
    424     /* End Collection */            0xC0
     440/* Usage Page (Digitizer)                */ 0x05, 0x0D,
     441/* Usage (Touch Screen)                  */ 0x09, 0x04,
     442/* Collection (Application)              */ 0xA1, 0x01,
     443/*     Report ID                         */ 0x85, REPORTID_TOUCH_EVENT,
     444/*     Usage Page (Digitizer)            */ 0x05, 0x0D,
     445/*     Usage (Contact count)             */ 0x09, 0x54,
     446/*     Report Size (8)                   */ 0x75, 0x08,
     447/*     Logical Minimum (0)               */ 0x15, 0x00,
     448/*     Logical Maximum (12)              */ 0x25, 0x0C,
     449/*     Report Count (1)                  */ 0x95, 0x01,
     450/*     Input (Var)                       */ 0x81, 0x02,
     451
     452/* MT_CONTACTS_PER_REPORT structs u8TipSwitch, u8ContactIdentifier, u16X, u16Y */
     453/* 1 of 5 */
     454/*     Usage (Finger)                    */ 0x09, 0x22,
     455/*     Collection (Logical)              */ 0xA1, 0x02,
     456/*         Usage (Tip Switch)            */ 0x09, 0x42,
     457/*         Logical Minimum (0)           */ 0x15, 0x00,
     458/*         Logical Maximum (1)           */ 0x25, 0x01,
     459/*         Report Size (1)               */ 0x75, 0x01,
     460/*         Report Count (1)              */ 0x95, 0x01,
     461/*         Input (Var)                   */ 0x81, 0x02,
     462
     463/*         Usage (In Range)              */ 0x09, 0x32,
     464/*         Logical Minimum (0)           */ 0x15, 0x00,
     465/*         Logical Maximum (1)           */ 0x25, 0x01,
     466/*         Report Size (1)               */ 0x75, 0x01,
     467/*         Report Count (1)              */ 0x95, 0x01,
     468/*         Input (Var)                   */ 0x81, 0x02,
     469
     470/*         Report Count (6)              */ 0x95, 0x06,
     471/*         Input (Cnst,Var)              */ 0x81, 0x03,
     472
     473/*         Report Size (8)               */ 0x75, 0x08,
     474/*         Usage (Contact identifier)    */ 0x09, 0x51,
     475/*         Report Count (1)              */ 0x95, 0x01,
     476/*         Logical Minimum (0)           */ 0x15, 0x00,
     477/*         Logical Maximum (32)          */ 0x25, 0x20,
     478/*         Input (Var)                   */ 0x81, 0x02,
     479
     480/*         Usage Page (Generic Desktop)  */ 0x05, 0x01,
     481/*         Logical Maximum (32K)         */ 0x26, 0xFF, 0x7F,
     482/*         Report Size (16)              */ 0x75, 0x10,
     483/*         Usage (X)                     */ 0x09, 0x30,
     484/*         Input (Var)                   */ 0x81, 0x02,
     485
     486/*         Usage (Y)                     */ 0x09, 0x31,
     487/*         Input (Var)                   */ 0x81, 0x02,
     488/*     End Collection                    */ 0xC0,
     489/* 2 of 5 */
     490/*     Usage Page (Digitizer)            */ 0x05, 0x0D,
     491/*     Usage (Finger)                    */ 0x09, 0x22,
     492/*     Collection (Logical)              */ 0xA1, 0x02,
     493/*         Usage (Tip Switch)            */ 0x09, 0x42,
     494/*         Logical Minimum (0)           */ 0x15, 0x00,
     495/*         Logical Maximum (1)           */ 0x25, 0x01,
     496/*         Report Size (1)               */ 0x75, 0x01,
     497/*         Report Count (1)              */ 0x95, 0x01,
     498/*         Input (Var)                   */ 0x81, 0x02,
     499/*         Usage (In Range)              */ 0x09, 0x32,
     500/*         Logical Minimum (0)           */ 0x15, 0x00,
     501/*         Logical Maximum (1)           */ 0x25, 0x01,
     502/*         Report Size (1)               */ 0x75, 0x01,
     503/*         Report Count (1)              */ 0x95, 0x01,
     504/*         Input (Var)                   */ 0x81, 0x02,
     505/*         Report Count (6)              */ 0x95, 0x06,
     506/*         Input (Cnst,Var)              */ 0x81, 0x03,
     507/*         Report Size (8)               */ 0x75, 0x08,
     508/*         Usage (Contact identifier)    */ 0x09, 0x51,
     509/*         Report Count (1)              */ 0x95, 0x01,
     510/*         Logical Minimum (0)           */ 0x15, 0x00,
     511/*         Logical Maximum (32)          */ 0x25, 0x20,
     512/*         Input (Var)                   */ 0x81, 0x02,
     513/*         Usage Page (Generic Desktop)  */ 0x05, 0x01,
     514/*         Logical Maximum (32K)         */ 0x26, 0xFF, 0x7F,
     515/*         Report Size (16)              */ 0x75, 0x10,
     516/*         Usage (X)                     */ 0x09, 0x30,
     517/*         Input (Var)                   */ 0x81, 0x02,
     518/*         Usage (Y)                     */ 0x09, 0x31,
     519/*         Input (Var)                   */ 0x81, 0x02,
     520/*     End Collection                    */ 0xC0,
     521/* 3 of 5 */
     522/*     Usage Page (Digitizer)            */ 0x05, 0x0D,
     523/*     Usage (Finger)                    */ 0x09, 0x22,
     524/*     Collection (Logical)              */ 0xA1, 0x02,
     525/*         Usage (Tip Switch)            */ 0x09, 0x42,
     526/*         Logical Minimum (0)           */ 0x15, 0x00,
     527/*         Logical Maximum (1)           */ 0x25, 0x01,
     528/*         Report Size (1)               */ 0x75, 0x01,
     529/*         Report Count (1)              */ 0x95, 0x01,
     530/*         Input (Var)                   */ 0x81, 0x02,
     531/*         Usage (In Range)              */ 0x09, 0x32,
     532/*         Logical Minimum (0)           */ 0x15, 0x00,
     533/*         Logical Maximum (1)           */ 0x25, 0x01,
     534/*         Report Size (1)               */ 0x75, 0x01,
     535/*         Report Count (1)              */ 0x95, 0x01,
     536/*         Input (Var)                   */ 0x81, 0x02,
     537/*         Report Count (6)              */ 0x95, 0x06,
     538/*         Input (Cnst,Var)              */ 0x81, 0x03,
     539/*         Report Size (8)               */ 0x75, 0x08,
     540/*         Usage (Contact identifier)    */ 0x09, 0x51,
     541/*         Report Count (1)              */ 0x95, 0x01,
     542/*         Logical Minimum (0)           */ 0x15, 0x00,
     543/*         Logical Maximum (32)          */ 0x25, 0x20,
     544/*         Input (Var)                   */ 0x81, 0x02,
     545/*         Usage Page (Generic Desktop)  */ 0x05, 0x01,
     546/*         Logical Maximum (32K)         */ 0x26, 0xFF, 0x7F,
     547/*         Report Size (16)              */ 0x75, 0x10,
     548/*         Usage (X)                     */ 0x09, 0x30,
     549/*         Input (Var)                   */ 0x81, 0x02,
     550/*         Usage (Y)                     */ 0x09, 0x31,
     551/*         Input (Var)                   */ 0x81, 0x02,
     552/*     End Collection                    */ 0xC0,
     553/* 4 of 5 */
     554/*     Usage Page (Digitizer)            */ 0x05, 0x0D,
     555/*     Usage (Finger)                    */ 0x09, 0x22,
     556/*     Collection (Logical)              */ 0xA1, 0x02,
     557/*         Usage (Tip Switch)            */ 0x09, 0x42,
     558/*         Logical Minimum (0)           */ 0x15, 0x00,
     559/*         Logical Maximum (1)           */ 0x25, 0x01,
     560/*         Report Size (1)               */ 0x75, 0x01,
     561/*         Report Count (1)              */ 0x95, 0x01,
     562/*         Input (Var)                   */ 0x81, 0x02,
     563/*         Usage (In Range)              */ 0x09, 0x32,
     564/*         Logical Minimum (0)           */ 0x15, 0x00,
     565/*         Logical Maximum (1)           */ 0x25, 0x01,
     566/*         Report Size (1)               */ 0x75, 0x01,
     567/*         Report Count (1)              */ 0x95, 0x01,
     568/*         Input (Var)                   */ 0x81, 0x02,
     569/*         Report Count (6)              */ 0x95, 0x06,
     570/*         Input (Cnst,Var)              */ 0x81, 0x03,
     571/*         Report Size (8)               */ 0x75, 0x08,
     572/*         Usage (Contact identifier)    */ 0x09, 0x51,
     573/*         Report Count (1)              */ 0x95, 0x01,
     574/*         Logical Minimum (0)           */ 0x15, 0x00,
     575/*         Logical Maximum (32)          */ 0x25, 0x20,
     576/*         Input (Var)                   */ 0x81, 0x02,
     577/*         Usage Page (Generic Desktop)  */ 0x05, 0x01,
     578/*         Logical Maximum (32K)         */ 0x26, 0xFF, 0x7F,
     579/*         Report Size (16)              */ 0x75, 0x10,
     580/*         Usage (X)                     */ 0x09, 0x30,
     581/*         Input (Var)                   */ 0x81, 0x02,
     582/*         Usage (Y)                     */ 0x09, 0x31,
     583/*         Input (Var)                   */ 0x81, 0x02,
     584/*     End Collection                    */ 0xC0,
     585/* 5 of 5 */
     586/*     Usage Page (Digitizer)            */ 0x05, 0x0D,
     587/*     Usage (Finger)                    */ 0x09, 0x22,
     588/*     Collection (Logical)              */ 0xA1, 0x02,
     589/*         Usage (Tip Switch)            */ 0x09, 0x42,
     590/*         Logical Minimum (0)           */ 0x15, 0x00,
     591/*         Logical Maximum (1)           */ 0x25, 0x01,
     592/*         Report Size (1)               */ 0x75, 0x01,
     593/*         Report Count (1)              */ 0x95, 0x01,
     594/*         Input (Var)                   */ 0x81, 0x02,
     595/*         Usage (In Range)              */ 0x09, 0x32,
     596/*         Logical Minimum (0)           */ 0x15, 0x00,
     597/*         Logical Maximum (1)           */ 0x25, 0x01,
     598/*         Report Size (1)               */ 0x75, 0x01,
     599/*         Report Count (1)              */ 0x95, 0x01,
     600/*         Input (Var)                   */ 0x81, 0x02,
     601/*         Report Count (6)              */ 0x95, 0x06,
     602/*         Input (Cnst,Var)              */ 0x81, 0x03,
     603/*         Report Size (8)               */ 0x75, 0x08,
     604/*         Usage (Contact identifier)    */ 0x09, 0x51,
     605/*         Report Count (1)              */ 0x95, 0x01,
     606/*         Logical Minimum (0)           */ 0x15, 0x00,
     607/*         Logical Maximum (32)          */ 0x25, 0x20,
     608/*         Input (Var)                   */ 0x81, 0x02,
     609/*         Usage Page (Generic Desktop)  */ 0x05, 0x01,
     610/*         Logical Maximum (32K)         */ 0x26, 0xFF, 0x7F,
     611/*         Report Size (16)              */ 0x75, 0x10,
     612/*         Usage (X)                     */ 0x09, 0x30,
     613/*         Input (Var)                   */ 0x81, 0x02,
     614/*         Usage (Y)                     */ 0x09, 0x31,
     615/*         Input (Var)                   */ 0x81, 0x02,
     616/*     End Collection                    */ 0xC0,
     617
     618/* Note: "Scan time" usage is required for all touch devices (in 100microseconds units). */
     619/*     Usage Page (Digitizer)            */ 0x05, 0x0D,
     620/*     Logical Minimum (0)               */ 0x17, 0x00, 0x00, 0x00, 0x00,
     621/*     Logical Maximum (2147483647)      */ 0x27, 0xFF, 0xFF, 0xFF, 0x7F,
     622/*     Report Size (32)                  */ 0x75, 0x20,
     623/*     Report Count (1)                  */ 0x95, 0x01,
     624/*     Unit Exponent (0)                 */ 0x55, 0x00,
     625/*     Unit (None)                       */ 0x65, 0x00,
     626/*     Usage (Scan time)                 */ 0x09, 0x56,
     627/*     Input (Var)                       */ 0x81, 0x02,
     628
     629/*     Report ID                         */ 0x85, REPORTID_TOUCH_MAX_COUNT,
     630/*     Usage (Contact count maximum)     */ 0x09, 0x55, 
     631/*     Usage (Device identifier)         */ 0x09, 0x53, 
     632/*     Report Size (8)                   */ 0x75, 0x08, 
     633/*     Report Count (2)                  */ 0x95, 0x02, 
     634/*     Logical Maximum (255)             */ 0x26, 0xFF, 0x00,
     635/*     Feature (Var)                     */ 0xB1, 0x02, 
     636
     637/*     Usage Page (Vendor-Defined 1)     */ 0x06, 0x00, 0xFF,
     638/*     Usage (QA blob)                   */ 0x09, 0xC5,
     639/*     Report ID                         */ 0x85, REPORTID_TOUCH_QABLOB,
     640/*     Logical Minimum (0)               */ 0x15, 0x00,
     641/*     Logical Maximum (255)             */ 0x26, 0xFF, 0x00,
     642/*     Report Size (8)                   */ 0x75, 0x08,
     643/*     Report Count (256)                */ 0x96, 0x00, 0x01,
     644/*     Feature (Var)                     */ 0xB1, 0x02,
     645/* End Collection                        */ 0xC0,
     646
     647/* Note: the pointer report is required by specification:
     648 * "The report descriptor for a multiple input device must include at least
     649 * one top-level collection for the primary device and a separate top-level
     650 * collection for the mouse."
     651 */
     652/* Usage Page (Generic Desktop)          */ 0x05, 0x01,
     653/* Usage (Pointer)                       */ 0x09, 0x01,
     654/* Collection (Application)              */ 0xA1, 0x01,
     655/*     Report ID                         */ 0x85, REPORTID_TOUCH_POINTER,
     656/*     Usage (Pointer)                   */ 0x09, 0x01,
     657/*     Collection (Logical)              */ 0xA1, 0x02,
     658/*         Usage Page (Button)           */ 0x05, 0x09,
     659/*         Usage Minimum (Button 1)      */ 0x19, 0x01,
     660/*         Usage Maximum (Button 2)      */ 0x29, 0x02,
     661/*         Logical Minimum (0)           */ 0x15, 0x00,
     662/*         Logical Maximum (1)           */ 0x25, 0x01,
     663/*         Report Count (2)              */ 0x95, 0x02,
     664/*         Report Size (1)               */ 0x75, 0x01,
     665/*         Input (Var)                   */ 0x81, 0x02,
     666/*         Report Count (1)              */ 0x95, 0x01,
     667/*         Report Size (6)               */ 0x75, 0x06,
     668/*         Input (Cnst,Ary,Abs)          */ 0x81, 0x01,
     669/*         Usage Page (Generic Desktop)  */ 0x05, 0x01,
     670/*         Usage (X)                     */ 0x09, 0x30,
     671/*         Usage (Y)                     */ 0x09, 0x31,
     672/*         Logical Minimum (0)           */ 0x16, 0x00, 0x00,
     673/*         Logical Maximum (32K)         */ 0x26, 0xFF, 0x7F,
     674/*         Physical Minimum (0)          */ 0x36, 0x00, 0x00,
     675/*         Physical Maximum (32K)        */ 0x46, 0xFF, 0x7F,
     676/*         Unit (None)                   */ 0x66, 0x00, 0x00,
     677/*         Report Size (16)              */ 0x75, 0x10,
     678/*         Report Count (2)              */ 0x95, 0x02,
     679/*         Input (Var)                   */ 0x81, 0x02,
     680/*     End Collection                    */ 0xC0,
     681/* End Collection                        */ 0xC0,
     682
     683/* Usage Page (Digitizer)                */ 0x05, 0x0D, 
     684/* Usage (Device configuration)          */ 0x09, 0x0E, 
     685/* Collection (Application)              */ 0xA1, 0x01, 
     686/*     Report ID                         */ 0x85, REPORTID_TOUCH_DEVCONFIG, 
     687/*     Usage (Device settings)           */ 0x09, 0x23, 
     688/*     Collection (Logical)              */ 0xA1, 0x02, 
     689/*         Usage (Device mode)           */ 0x09, 0x52, 
     690/*         Usage (Device identifier)     */ 0x09, 0x53, 
     691/*         Logical Minimum (0)           */ 0x15, 0x00, 
     692/*         Logical Maximum (10)          */ 0x25, 0x0A, 
     693/*         Report Size (8)               */ 0x75, 0x08, 
     694/*         Report Count (2)              */ 0x95, 0x02, 
     695/*         Feature (Var)                 */ 0xB1, 0x02, 
     696/*     End Collection                    */ 0xC0, 
     697/* End Collection                        */ 0xC0
    425698};
    426699
     
    455728    /* .bLength = */                0x09,
    456729    /* .bDescriptorType = */        0x21,       /* HID */
    457     /* .bcdHID = */                 0x10, 0x01, /* 1.1 */
     730    /* .bcdHID = */                 0x10, 0x02, /* 2.1 */
    458731    /* .bCountryCode = */           0,
    459732    /* .bNumDescriptors = */        1,
    460733    /* .bDescriptorType = */        0x22,       /* Report */
    461     /* .wDescriptorLength = */      sizeof(g_UsbHidMTReportDesc), 0x00
     734    /* .wDescriptorLength = */      RT_LO_U8(sizeof(g_UsbHidMTReportDesc)), RT_HI_U8(sizeof(g_UsbHidMTReportDesc))
    462735};
    463736
     
    520793    /* .pvClass = */    &g_UsbHidMTIfHidDesc,
    521794    /* .cbClass = */    sizeof(g_UsbHidMTIfHidDesc),
    522     &g_aUsbHidTEndpointDescs[0],
     795    &g_aUsbHidMTEndpointDescs[0],
    523796    /* .pIAD = */ NULL,
    524797    /* .cbIAD = */ 0
     
    7401013    PVUSBURB pCur = pQueue->pHead;
    7411014    if (pCur == pUrb)
     1015    {
    7421016        pQueue->pHead = pUrb->Dev.pNext;
     1017        if (!pUrb->Dev.pNext)
     1018            pQueue->ppTail = &pQueue->pHead;
     1019    }
    7431020    else
    7441021    {
     
    7541031        if (!pCur)
    7551032            return false;
    756     }
    757     if (!pUrb->Dev.pNext)
    758         pQueue->ppTail = &pQueue->pHead;
     1033        if (!pUrb->Dev.pNext)
     1034            pQueue->ppTail = &pCur->Dev.pNext;
     1035    }
     1036    pUrb->Dev.pNext = NULL;
    7591037    return true;
    7601038}
     
    9191197                 pReport->m.fButtons, cbCopy));
    9201198        break;
    921     case USBHIDMODE_MULTI_TOUCH:
    922         pReport->mt.idReport         = REPORTID_MOUSE;
    923         pReport->mt.cContact         = pAccumulated->u.MultiTouch.cContact;
    924         pReport->mt.x                = pAccumulated->u.MultiTouch.x;
    925         pReport->mt.y                = pAccumulated->u.MultiTouch.y;
    926         pReport->mt.fContact         = pAccumulated->u.MultiTouch.fContact;
    927 
    928         cbCopy = sizeof(pReport->mt);
    929         LogRel3(("Multi-touch event, x=%u, y=%u, cContact=%u, fContact=%02x, report size %d\n",
    930                  (unsigned)pReport->mt.x, (unsigned)pReport->mt.y,
    931                  (unsigned)pReport->mt.cContact, (unsigned)pReport->mt.fContact,
    932                  cbCopy));
    933         break;
    9341199    }
    9351200
     
    9401205}
    9411206
     1207DECLINLINE(MTCONTACT *) usbHidFindMTContact(MTCONTACT *paContacts, size_t cContacts,
     1208                                            uint8_t u8Mask, uint8_t u8Value)
     1209{
     1210    size_t i;
     1211    for (i = 0; i < cContacts; i++)
     1212    {
     1213        if ((paContacts[i].status & u8Mask) == u8Value)
     1214        {
     1215            return &paContacts[i];
     1216        }
     1217    }
     1218
     1219    return NULL;
     1220}
     1221
     1222static int usbHidSendMultiTouchReport(PUSBHID pThis, PVUSBURB pUrb)
     1223{
     1224    uint8_t i;
     1225    MTCONTACT *pRepContact;
     1226    MTCONTACT *pCurContact;
     1227
     1228    /* Number of contacts to be reported. In hybrid mode the first report contains
     1229     * total number of contacts and subsequent reports contain 0.
     1230     */
     1231    uint8_t cContacts = 0;
     1232
     1233    Assert(pThis->fHasPendingChanges);
     1234
     1235    if (!pThis->fTouchReporting)
     1236    {
     1237        pThis->fTouchReporting = true;
     1238
     1239        /* Update the reporting state with the new current state.
     1240         * Also mark all active contacts in reporting state as dirty,
     1241         * that is they must be reported to the guest.
     1242         */
     1243        for (i = 0; i < MT_CONTACT_MAX_COUNT; i++)
     1244        {
     1245            pRepContact = &pThis->aReportingContactState[i];
     1246            pCurContact = &pThis->aCurrentContactState[i];
     1247
     1248            if (pCurContact->status & MT_CONTACT_S_ACTIVE)
     1249            {
     1250                if (pCurContact->status & MT_CONTACT_S_REUSED)
     1251                {
     1252                    pCurContact->status &= ~MT_CONTACT_S_REUSED;
     1253
     1254                    /* Keep x,y. Will report lost contact at this point. */
     1255                    pRepContact->id     = pCurContact->oldId;
     1256                    pRepContact->flags  = 0;
     1257                    pRepContact->status = MT_CONTACT_S_REUSED;
     1258                }
     1259                else if (pThis->aCurrentContactState[i].status & MT_CONTACT_S_CANCELLED)
     1260                {
     1261                    pCurContact->status &= ~(MT_CONTACT_S_CANCELLED | MT_CONTACT_S_ACTIVE);
     1262
     1263                    /* Keep x,y. Will report lost contact at this point. */
     1264                    pRepContact->id     = pCurContact->id;
     1265                    pRepContact->flags  = 0;
     1266                    pRepContact->status = 0;
     1267                }
     1268                else
     1269                {
     1270                    if (pCurContact->flags == 0)
     1271                    {
     1272                        pCurContact->status &= ~MT_CONTACT_S_ACTIVE; /* Contact disapeared. */
     1273                    }
     1274
     1275                    pRepContact->x      = pCurContact->x;
     1276                    pRepContact->y      = pCurContact->y;
     1277                    pRepContact->id     = pCurContact->id;
     1278                    pRepContact->flags  = pCurContact->flags;
     1279                    pRepContact->status = 0;
     1280                }
     1281
     1282                cContacts++;
     1283
     1284                pRepContact->status |= MT_CONTACT_S_DIRTY;
     1285            }
     1286            else
     1287            {
     1288                pRepContact->status = 0;
     1289            }
     1290        }
     1291    }
     1292
     1293    /* Report current state. */
     1294    USBHIDMT_REPORT *p = (USBHIDMT_REPORT *)&pUrb->abData[0];
     1295    RT_ZERO(*p);
     1296
     1297    p->idReport = REPORTID_TOUCH_EVENT;
     1298    p->cContacts = cContacts;
     1299
     1300    uint8_t iReportedContact;
     1301    for (iReportedContact = 0; iReportedContact < MT_CONTACTS_PER_REPORT; iReportedContact++)
     1302    {
     1303        /* Find the next not reported contact. */
     1304        pRepContact = usbHidFindMTContact(pThis->aReportingContactState, RT_ELEMENTS(pThis->aReportingContactState),
     1305                                          MT_CONTACT_S_DIRTY, MT_CONTACT_S_DIRTY);
     1306
     1307        if (!pRepContact)
     1308        {
     1309            LogRel3(("usbHid: no more touch contacts to report\n"));
     1310            break;
     1311        }
     1312
     1313        if (pRepContact->status & MT_CONTACT_S_REUSED)
     1314        {
     1315            /* Do not clear DIRTY flag for contacts which were reused.
     1316             * Because two reports must be generated:
     1317             * one for old contact off, and the second for new contact on.
     1318             */
     1319            pRepContact->status &= ~MT_CONTACT_S_REUSED;
     1320        }
     1321        else
     1322        {
     1323            pRepContact->status &= ~MT_CONTACT_S_DIRTY;
     1324        }
     1325
     1326        p->aContacts[iReportedContact].fContact = pRepContact->flags;
     1327        p->aContacts[iReportedContact].cContact = pRepContact->id;
     1328        p->aContacts[iReportedContact].x = pRepContact->x >> pThis->u8CoordShift;
     1329        p->aContacts[iReportedContact].y = pRepContact->y >> pThis->u8CoordShift;
     1330    }
     1331
     1332    p->u32ScanTime = pThis->u32LastTouchScanTime * 10;
     1333
     1334    Assert(iReportedContact > 0);
     1335
     1336    /* Reset TouchReporting if all contacts reported. */
     1337    pRepContact = usbHidFindMTContact(pThis->aReportingContactState, RT_ELEMENTS(pThis->aReportingContactState),
     1338                                      MT_CONTACT_S_DIRTY, MT_CONTACT_S_DIRTY);
     1339
     1340    if (!pRepContact)
     1341    {
     1342        LogRel3(("usbHid: all touch contacts reported\n"));
     1343        pThis->fTouchReporting = false;
     1344        pThis->fHasPendingChanges = false;
     1345    }
     1346    else
     1347    {
     1348        pThis->fHasPendingChanges = true;
     1349    }
     1350
     1351    LogRel3(("usbHid: reporting touch contact:\n%.*Rhxd\n", sizeof(USBHIDMT_REPORT), p));
     1352    return usbHidCompleteOk(pThis, pUrb, sizeof(USBHIDMT_REPORT));
     1353}
     1354
    9421355/**
    9431356 * Sends a state report to the host if there is a pending URB.
     
    9461359{
    9471360    PVUSBURB    pUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue);
     1361
     1362    if (pThis->enmMode == USBHIDMODE_MULTI_TOUCH)
     1363    {
     1364        /* This device uses a different reporting method and fHasPendingChanges maintenance. */
     1365        if (pUrb)
     1366            return usbHidSendMultiTouchReport(pThis, pUrb);
     1367        return VINF_SUCCESS;
     1368    }
    9481369
    9491370    if (pUrb)
     
    10301451
    10311452/**
    1032  * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventMT}
    1033  */
    1034 static DECLCALLBACK(int) usbHidMousePutEventMT(PPDMIMOUSEPORT pInterface,
    1035                                                uint32_t x, uint32_t y,
    1036                                                uint32_t cContact,
    1037                                                uint32_t fContact)
    1038 {
     1453 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventMultiTouch}
     1454 */
     1455static DECLCALLBACK(int) usbHidMousePutEventMultiTouch(PPDMIMOUSEPORT pInterface,
     1456                                                       uint8_t cContacts,
     1457                                                       const uint64_t *pau64Contacts,
     1458                                                       uint32_t u32ScanTime)
     1459{
     1460    uint8_t i;
     1461    uint8_t j;
     1462
     1463    /* Make a copy of new contacts */
     1464    MTCONTACT *paNewContacts = (MTCONTACT *)RTMemTmpAlloc(sizeof(MTCONTACT) * cContacts);
     1465    if (!paNewContacts)
     1466        return VERR_NO_MEMORY;
     1467
     1468    for (i = 0; i < cContacts; i++)
     1469    {
     1470        paNewContacts[i].x      = RT_LO_U16(RT_LO_U32(pau64Contacts[i]));
     1471        paNewContacts[i].y      = RT_HI_U16(RT_LO_U32(pau64Contacts[i]));
     1472        paNewContacts[i].id     = RT_BYTE1(RT_HI_U32(pau64Contacts[i]));
     1473        paNewContacts[i].flags  = RT_BYTE2(RT_HI_U32(pau64Contacts[i])) & (MT_CONTACT_F_IN_CONTACT | MT_CONTACT_F_IN_RANGE);
     1474        paNewContacts[i].status = MT_CONTACT_S_DIRTY;
     1475        paNewContacts[i].oldId  = 0; /* Not used. */
     1476    }
     1477
    10391478    PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
    1040     if (pThis->fHasPendingChanges)
    1041         return VERR_TRY_AGAIN;
     1479    MTCONTACT *pCurContact = NULL;
     1480    MTCONTACT *pNewContact = NULL;
     1481
    10421482    RTCritSectEnter(&pThis->CritSect);
    10431483
    10441484    Assert(pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
    10451485
    1046     /* Accumulate movement - the events from the front end may arrive
    1047      * at a much higher rate than USB can handle. Probably not a real issue
    1048      * when only the Z axis is relative (X/Y movement isn't technically
    1049      * accumulated and only the last value is used).
     1486    /* Maintain a state of all current contacts.
     1487     * Intr URBs will be completed according to the state.
    10501488     */
    1051     pThis->PtrDelta.u.MultiTouch.fContact = fContact;
    1052     pThis->PtrDelta.u.MultiTouch.x        = x >> pThis->u8CoordShift;
    1053     pThis->PtrDelta.u.MultiTouch.y        = y >> pThis->u8CoordShift;
    1054     pThis->PtrDelta.u.MultiTouch.cContact = cContact;
     1489
     1490    /* Mark all existing contacts as dirty. */
     1491    for (i = 0; i < RT_ELEMENTS(pThis->aCurrentContactState); i++)
     1492        pThis->aCurrentContactState[i].status |= MT_CONTACT_S_DIRTY;
     1493
     1494    /* Update existing contacts and mark new contacts. */
     1495    for (i = 0; i < cContacts; i++)
     1496    {
     1497        pNewContact = &paNewContacts[i];
     1498
     1499        /* Find existing contact with the same id. */
     1500        pCurContact = NULL;
     1501        for (j = 0; j < RT_ELEMENTS(pThis->aCurrentContactState); j++)
     1502        {
     1503            if (   (pThis->aCurrentContactState[j].status & MT_CONTACT_S_ACTIVE) != 0
     1504                && pThis->aCurrentContactState[j].id == pNewContact->id)
     1505            {
     1506                pCurContact = &pThis->aCurrentContactState[j];
     1507                break;
     1508            }
     1509        }
     1510
     1511        if (pCurContact)
     1512        {
     1513            pNewContact->status &= ~MT_CONTACT_S_DIRTY;
     1514
     1515            pCurContact->x = pNewContact->x;
     1516            pCurContact->y = pNewContact->y;
     1517            if (pCurContact->flags == 0) /* Contact disappeared already. */
     1518            {
     1519                if ((pCurContact->status & MT_CONTACT_S_REUSED) == 0)
     1520                {
     1521                    pCurContact->status |= MT_CONTACT_S_REUSED; /* Report to the guest that the contact not in touch. */
     1522                    pCurContact->oldId = pCurContact->id;
     1523                }
     1524            }
     1525            pCurContact->flags = pNewContact->flags;
     1526            pCurContact->status &= ~MT_CONTACT_S_DIRTY;
     1527        }
     1528    }
     1529
     1530    /* Append new contacts (the dirty one in the paNewContacts). */
     1531    for (i = 0; i < cContacts; i++)
     1532    {
     1533        pNewContact = &paNewContacts[i];
     1534
     1535        if (pNewContact->status & MT_CONTACT_S_DIRTY)
     1536        {
     1537            /* It is a new contact, copy is to one of not ACTIVE or not updated existing contacts. */
     1538            pCurContact = usbHidFindMTContact(pThis->aCurrentContactState, RT_ELEMENTS(pThis->aCurrentContactState),
     1539                                              MT_CONTACT_S_ACTIVE, 0);
     1540
     1541            if (pCurContact)
     1542            {
     1543                *pCurContact = *pNewContact;
     1544                pCurContact->status = MT_CONTACT_S_ACTIVE; /* Reset status. */
     1545            }
     1546            else
     1547            {
     1548                /* Dirty existing contacts can be reused. */
     1549                pCurContact = usbHidFindMTContact(pThis->aCurrentContactState, RT_ELEMENTS(pThis->aCurrentContactState),
     1550                                                  MT_CONTACT_S_ACTIVE | MT_CONTACT_S_DIRTY,
     1551                                                  MT_CONTACT_S_ACTIVE | MT_CONTACT_S_DIRTY);
     1552
     1553                if (pCurContact)
     1554                {
     1555                    pCurContact->x = pNewContact->x;
     1556                    pCurContact->y = pNewContact->y;
     1557                    if ((pCurContact->status & MT_CONTACT_S_REUSED) == 0)
     1558                    {
     1559                        pCurContact->status |= MT_CONTACT_S_REUSED; /* Report to the guest that the contact not in touch. */
     1560                        pCurContact->oldId = pCurContact->id;
     1561                    }
     1562                    pCurContact->flags = pNewContact->flags;
     1563                    pCurContact->status &= ~MT_CONTACT_S_DIRTY;
     1564                }
     1565                else
     1566                {
     1567                    LogRel3(("usbHid: dropped new contact: %d,%d id %d flags %RX8 status %RX8 oldId %d\n",
     1568                             pNewContact->x,
     1569                             pNewContact->y,
     1570                             pNewContact->id,
     1571                             pNewContact->flags,
     1572                             pNewContact->status,
     1573                             pNewContact->oldId
     1574                           ));
     1575                }
     1576            }
     1577        }
     1578    }
     1579
     1580    /* Mark still dirty existing contacts as cancelled, because a new set of contacts does not include them. */
     1581    for (i = 0; i < RT_ELEMENTS(pThis->aCurrentContactState); i++)
     1582    {
     1583        pCurContact = &pThis->aCurrentContactState[i];
     1584        if (pCurContact->status & MT_CONTACT_S_DIRTY)
     1585        {
     1586            pCurContact->status |= MT_CONTACT_S_CANCELLED;
     1587            pCurContact->status &= ~MT_CONTACT_S_DIRTY;
     1588        }
     1589    }
     1590
     1591    pThis->u32LastTouchScanTime = u32ScanTime;
     1592
     1593    LogRel3(("usbHid: scanTime (ms): %d\n", pThis->u32LastTouchScanTime));
     1594    for (i = 0; i < RT_ELEMENTS(pThis->aCurrentContactState); i++)
     1595    {
     1596        LogRel3(("usbHid: contact state[%d]: %d,%d id %d flags %RX8 status %RX8 oldId %d\n",
     1597                  i,
     1598                  pThis->aCurrentContactState[i].x,
     1599                  pThis->aCurrentContactState[i].y,
     1600                  pThis->aCurrentContactState[i].id,
     1601                  pThis->aCurrentContactState[i].flags,
     1602                  pThis->aCurrentContactState[i].status,
     1603                  pThis->aCurrentContactState[i].oldId
     1604                ));
     1605    }
     1606
     1607    pThis->fHasPendingChanges = true;
    10551608
    10561609    /* Send a report if possible. */
     
    10581611
    10591612    RTCritSectLeave(&pThis->CritSect);
     1613
     1614    RTMemTmpFree(paNewContacts);
    10601615    return VINF_SUCCESS;
    10611616}
     
    10671622{
    10681623    PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
    1069     LogRelFlow(("usbHidUrbReap/#%u: cMillies=%u\n", pUsbIns->iInstance, cMillies));
    10701624
    10711625    RTCritSectEnter(&pThis->CritSect);
     
    11571711        case USBHIDREQSTATE_READY:
    11581712            usbHidQueueAddTail(&pThis->ToHostQueue, pUrb);
     1713            LogRelFlow(("usbHidHandleIntrDevToHost: Added %p:%s to the queue\n",
     1714                        pUrb, pUrb->pszDesc));
    11591715            /* If a report is pending, send it right away. */
    11601716            if (pThis->fHasPendingChanges)
    11611717                usbHidSendReport(pThis);
    1162             LogRelFlow(("usbHidHandleIntrDevToHost: Added %p:%s to the queue\n",
    1163                         pUrb, pUrb->pszDesc));
    11641718            return VINF_SUCCESS;
    11651719
     
    11741728}
    11751729
     1730#define GET_REPORT   0x01
     1731#define GET_IDLE     0x02
     1732#define GET_PROTOCOL 0x03
     1733#define SET_REPORT   0x09
     1734#define SET_IDLE     0x0A
     1735#define SET_PROTOCOL 0x0B
     1736
     1737static uint8_t sau8QASampleBlob[256] =
     1738{
     1739    0xfc, 0x28, 0xfe, 0x84, 0x40, 0xcb, 0x9a, 0x87,
     1740    0x0d, 0xbe, 0x57, 0x3c, 0xb6, 0x70, 0x09, 0x88,
     1741    0x07, 0x97, 0x2d, 0x2b, 0xe3, 0x38, 0x34, 0xb6,
     1742    0x6c, 0xed, 0xb0, 0xf7, 0xe5, 0x9c, 0xf6, 0xc2,
     1743    0x2e, 0x84, 0x1b, 0xe8, 0xb4, 0x51, 0x78, 0x43,
     1744    0x1f, 0x28, 0x4b, 0x7c, 0x2d, 0x53, 0xaf, 0xfc,
     1745    0x47, 0x70, 0x1b, 0x59, 0x6f, 0x74, 0x43, 0xc4,
     1746    0xf3, 0x47, 0x18, 0x53, 0x1a, 0xa2, 0xa1, 0x71,
     1747    0xc7, 0x95, 0x0e, 0x31, 0x55, 0x21, 0xd3, 0xb5,
     1748    0x1e, 0xe9, 0x0c, 0xba, 0xec, 0xb8, 0x89, 0x19,
     1749    0x3e, 0xb3, 0xaf, 0x75, 0x81, 0x9d, 0x53, 0xb9,
     1750    0x41, 0x57, 0xf4, 0x6d, 0x39, 0x25, 0x29, 0x7c,
     1751    0x87, 0xd9, 0xb4, 0x98, 0x45, 0x7d, 0xa7, 0x26,
     1752    0x9c, 0x65, 0x3b, 0x85, 0x68, 0x89, 0xd7, 0x3b,
     1753    0xbd, 0xff, 0x14, 0x67, 0xf2, 0x2b, 0xf0, 0x2a,
     1754    0x41, 0x54, 0xf0, 0xfd, 0x2c, 0x66, 0x7c, 0xf8,
     1755    0xc0, 0x8f, 0x33, 0x13, 0x03, 0xf1, 0xd3, 0xc1,
     1756    0x0b, 0x89, 0xd9, 0x1b, 0x62, 0xcd, 0x51, 0xb7,
     1757    0x80, 0xb8, 0xaf, 0x3a, 0x10, 0xc1, 0x8a, 0x5b,
     1758    0xe8, 0x8a, 0x56, 0xf0, 0x8c, 0xaa, 0xfa, 0x35,
     1759    0xe9, 0x42, 0xc4, 0xd8, 0x55, 0xc3, 0x38, 0xcc,
     1760    0x2b, 0x53, 0x5c, 0x69, 0x52, 0xd5, 0xc8, 0x73,
     1761    0x02, 0x38, 0x7c, 0x73, 0xb6, 0x41, 0xe7, 0xff,
     1762    0x05, 0xd8, 0x2b, 0x79, 0x9a, 0xe2, 0x34, 0x60,
     1763    0x8f, 0xa3, 0x32, 0x1f, 0x09, 0x78, 0x62, 0xbc,
     1764    0x80, 0xe3, 0x0f, 0xbd, 0x65, 0x20, 0x08, 0x13,
     1765    0xc1, 0xe2, 0xee, 0x53, 0x2d, 0x86, 0x7e, 0xa7,
     1766    0x5a, 0xc5, 0xd3, 0x7d, 0x98, 0xbe, 0x31, 0x48,
     1767    0x1f, 0xfb, 0xda, 0xaf, 0xa2, 0xa8, 0x6a, 0x89,
     1768    0xd6, 0xbf, 0xf2, 0xd3, 0x32, 0x2a, 0x9a, 0xe4,
     1769    0xcf, 0x17, 0xb7, 0xb8, 0xf4, 0xe1, 0x33, 0x08,
     1770    0x24, 0x8b, 0xc4, 0x43, 0xa5, 0xe5, 0x24, 0xc2
     1771};
     1772
     1773static int usbHidRequestClass(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
     1774{
     1775    PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
     1776
     1777    if (pThis->enmMode != USBHIDMODE_MULTI_TOUCH)
     1778    {
     1779        LogRelFlow(("usbHid: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
     1780                    pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
     1781                    pSetup->wIndex, pSetup->wLength));
     1782        return usbHidCompleteStall(pThis, pEp, pUrb, "Unsupported class req");
     1783    }
     1784
     1785    int rc = VINF_SUCCESS;
     1786
     1787    switch (pSetup->bRequest)
     1788    {
     1789        case SET_REPORT:
     1790        case GET_REPORT:
     1791        {
     1792            uint8_t u8ReportType = RT_HI_U8(pSetup->wValue);
     1793            uint8_t u8ReportID = RT_LO_U8(pSetup->wValue);
     1794            LogRelFlow(("usbHid: %s: type %d, ID %d, data\n%.*Rhxd\n",
     1795                        pSetup->bRequest == GET_REPORT? "GET_REPORT": "SET_REPORT",
     1796                        u8ReportType, u8ReportID,
     1797                        pUrb->cbData - sizeof(VUSBSETUP), &pUrb->abData[sizeof(VUSBSETUP)]));
     1798            uint32_t cbData = 0;
     1799            if (pSetup->bRequest == GET_REPORT)
     1800            {
     1801                if (u8ReportType == 3 && u8ReportID == REPORTID_TOUCH_MAX_COUNT)
     1802                {
     1803                    pUrb->abData[sizeof(VUSBSETUP) + 0] = REPORTID_TOUCH_MAX_COUNT;
     1804                    pUrb->abData[sizeof(VUSBSETUP) + 1] = MT_CONTACT_MAX_COUNT; /* Contact count maximum. */
     1805                    pUrb->abData[sizeof(VUSBSETUP) + 2] = 0;  /* Device identifier */
     1806                    cbData = 3;
     1807                }
     1808                else if (u8ReportType == 3 && u8ReportID == REPORTID_TOUCH_QABLOB)
     1809                {
     1810                    uint32_t cbLeft = pUrb->cbData;
     1811                    pUrb->abData[sizeof(VUSBSETUP) + 0] = REPORTID_TOUCH_QABLOB;  /* Report Id. */
     1812                    memcpy(&pUrb->abData[sizeof(VUSBSETUP) + 1],
     1813                           sau8QASampleBlob, sizeof(sau8QASampleBlob));
     1814                    cbData = sizeof(sau8QASampleBlob) + 1;
     1815                }
     1816            }
     1817
     1818            rc = usbHidCompleteOk(pThis, pUrb, sizeof(VUSBSETUP) + cbData);
     1819        } break;
     1820        default:
     1821        {
     1822            LogRelFlow(("usbHid: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
     1823                        pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
     1824                        pSetup->wIndex, pSetup->wLength));
     1825            rc = usbHidCompleteStall(pThis, pEp, pUrb, "Unsupported class req MT");
     1826        }
     1827    }
     1828
     1829    return rc;
     1830}
    11761831
    11771832/**
     
    13632018        usbHidCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
    13642019    }
     2020    else if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_CLASS)
     2021    {
     2022        /* Only VUSB_TO_INTERFACE is allowed. */
     2023        if ((pSetup->bmRequestType & VUSB_RECIP_MASK) == VUSB_TO_INTERFACE)
     2024        {
     2025            return usbHidRequestClass(pThis, pEp, pUrb);
     2026        }
     2027
     2028        LogRelFlow(("usbHid: invalid recipient of class req: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
     2029                    pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
     2030                    pSetup->wIndex, pSetup->wLength));
     2031        return usbHidCompleteStall(pThis, pEp, pUrb, "Invalid recip");
     2032    }
    13652033    else
    13662034    {
     
    15822250    pThis->Lun0.IPort.pfnPutEvent       = usbHidMousePutEvent;
    15832251    pThis->Lun0.IPort.pfnPutEventAbs    = usbHidMousePutEventAbs;
    1584     pThis->Lun0.IPort.pfnPutEventMT     = usbHidMousePutEventMT;
     2252    pThis->Lun0.IPort.pfnPutEventMultiTouch = usbHidMousePutEventMultiTouch;
    15852253
    15862254    /*
  • trunk/src/VBox/Devices/Input/testcase/tstUsbMouse.cpp

    r47422 r47571  
    247247}
    248248
    249 
     249#if 0
     250/** @todo PDM interface was updated. This is not working anymore. */
    250251static void testSendPositionMT(RTTEST hTest)
    251252{
     
    296297        g_UsbHidMou.pfnDestruct(pThis);
    297298}
    298 
     299#endif
    299300
    300301int main()
     
    322323    testSendPositionRel(hTest);
    323324    testSendPositionAbs(hTest);
    324     testSendPositionMT(hTest);
     325    /* testSendPositionMT(hTest); */
    325326    return RTTestSummaryAndDestroy(hTest);
    326327}
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMouseHandler.cpp

    r47511 r47571  
    6262#include "CFramebuffer.h"
    6363#include "CDisplay.h"
     64
     65#include <iprt/time.h>
    6466
    6567/* Factory function to create mouse-handler: */
     
    907909    CMouse mouse = session().GetConsole().GetMouse();
    908910
     911    QVector<LONG64> contacts(pTouchEvent->touchPoints().size());
     912
    909913    /* Pass all multi-touch events into guest: */
     914    int i = 0;
    910915    foreach (const QTouchEvent::TouchPoint &touchPoint, pTouchEvent->touchPoints())
    911916    {
     
    929934        LogRelFlow(("UIMouseHandler::multiTouchEvent: Origin: %dx%d, State: %d\n",
    930935                    currentTouchPoint.x(), currentTouchPoint.y(), iTouchPointState));
    931         mouse.PutMouseEventMultiTouch((LONG)currentTouchPoint.x(), (LONG)currentTouchPoint.y(),
    932                                       (LONG)touchPoint.id(), iTouchPointState);
    933     }
     936
     937        contacts[i++] = RT_MAKE_U64_FROM_U16((uint16_t)currentTouchPoint.x(),
     938                                             (uint16_t)currentTouchPoint.y(),
     939                                             RT_MAKE_U16(touchPoint.id(), iTouchPointState),
     940                                             0);
     941    }
     942
     943    mouse.PutEventMultiTouch(pTouchEvent->touchPoints().size(),
     944                             contacts,
     945                             (ULONG)RTTimeMilliTS());
    934946
    935947    /* Eat by default? */
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r47561 r47571  
    1449414494  <interface
    1449514495    name="IMouse" extends="$unknown"
    14496     uuid="b84498e5-c8ad-4ae0-adbe-7928c7a546df"
     14496    uuid="ee770393-415f-4421-b2d5-28b73cacf86a"
    1449714497    wsmap="managed"
    1449814498    >
     
    1467214672    </method>
    1467314673
    14674     <method name="putMouseEventMultiTouch">
    14675       <desc>
    14676         Sends a multi-touch pointer event.  The coordinates are expressed in
     14674    <method name="putEventMultiTouch">
     14675      <desc>
     14676        Sends a multi-touch pointer event. The coordinates are expressed in
    1467714677        pixels and start from <tt>[1,1]</tt> which corresponds to the top left
    1467814678        corner of the virtual display.
     
    1468214682        </result>
    1468314683        <result name="VBOX_E_IPRT_ERROR">
    14684           Could not send mouse event to virtual mouse.
     14684          Could not send event to virtual device.
    1468514685        </result>
    1468614686
     
    1469214692      </desc>
    1469314693
    14694       <param name="x" type="long" dir="in">
    14695         <desc>
    14696           X coordinate of the touch in pixels, starting from @c 1.
    14697         </desc>
    14698       </param>
    14699       <param name="y" type="long" dir="in">
    14700         <desc>
    14701           Y coordinate of the touch in pixels, starting from @c 1.
    14702         </desc>
    14703       </param>
    14704       <param name="contactID" type="long" dir="in">
    14705         <desc>
    14706           Identifier for the touch number.  When a touch starts (i.e. a finger
    14707           first touches the device) it is given a currently unused identifier,
    14708           but if the touch moves without interruption (i.e. the finger is
    14709           touching the device the whole time) the identifier will be the same
    14710           for all following events.
    14711         </desc>
    14712       </param>
    14713       <param name="contactState" type="long" dir="in">
    14714         <desc>
    14715           State information for the touch identified by @a contactID.  See the
    14716           <link to="TouchContactState"/> enumeration value.  If this is not
    14717           zero, expect more events with the same @a contactID, and this will
    14718           usually be zero when the last event is received before the contact is
    14719           stopped (i.e. the finger is removed from the device).
     14694      <param name="count" type="long" dir="in">
     14695        <desc>
     14696          Number of contacts in the event.
     14697        </desc>
     14698      </param>
     14699
     14700      <param name="contacts" type="long long" dir="in" safearray="yes">
     14701        <desc>
     14702          Each array element contains packed information about one contact.
     14703          Bits 0..15: X coordinate in pixels.
     14704          Bits 16..31: Y coordinate in pixels.
     14705          Bits 32..39: contact identifier.
     14706          Bit 40: "in contact" flag, which indicates that there is a contact with the touch surface.
     14707          Bit 41: "in range" flag, the contact is close enough to the touch surface.
     14708          All other bits are reserved for future use and must be set to 0.
     14709        </desc>
     14710      </param>
     14711
     14712      <param name="scanTime" type="unsigned long" dir="in">
     14713        <desc>
     14714          Timestamp of the event in milliseconds. Only relative time between events is important.
     14715        </desc>
     14716      </param>
     14717    </method>
     14718
     14719    <method name="putEventMultiTouchString">
     14720      <desc>
     14721        <see><link to="#putEventMultiTouch"/></see>
     14722      </desc>
     14723
     14724      <param name="count" type="long" dir="in">
     14725        <desc>
     14726          <see><link to="#putEventMultiTouch"/></see>
     14727        </desc>
     14728      </param>
     14729
     14730      <param name="contacts" type="wstring" dir="in">
     14731        <desc>
     14732          Contains information about all contacts:
     14733          "id1,x1,y1,inContact1,inRange1;...;idN,xN,yN,inContactN,inRangeN".
     14734          For example for two contacts: "0,10,20,1,1;1,30,40,1,1"
     14735        </desc>
     14736      </param>
     14737
     14738      <param name="scanTime" type="unsigned long" dir="in">
     14739        <desc>
     14740          <see><link to="#putEventMultiTouch"/></see>
    1472014741        </desc>
    1472114742      </param>
  • trunk/src/VBox/Main/include/ConsoleVRDPServer.h

    r47464 r47571  
    356356                                                     const void *pvEvent,
    357357                                                     uint32_t cbEvent);
     358    uint64_t mu64TouchInputTimestampMCS;
    358359};
    359360
  • trunk/src/VBox/Main/include/MouseImpl.h

    r47245 r47571  
    6666    STDMETHOD(PutMouseEventAbsolute)(LONG x, LONG y, LONG dz, LONG dw,
    6767                                     LONG buttonState);
    68     STDMETHOD(PutMouseEventMultiTouch)(LONG x, LONG y, LONG contactID,
    69                                        LONG contactState);
     68    STDMETHOD(PutEventMultiTouch)(LONG aCount, ComSafeArrayIn(LONG64, aContacts), ULONG aScanTime);
     69    STDMETHOD(PutEventMultiTouchString)(LONG aCount, IN_BSTR aContacts, ULONG aScanTime);
    7070    STDMETHOD(COMGETTER(EventSource)) (IEventSource ** aEventSource);
    7171
     
    9898    HRESULT reportMTEventToMouseDev(int32_t x, int32_t z, uint32_t cContact,
    9999                                    uint32_t fContact);
     100    HRESULT reportMultiTouchEventToDevice(uint8_t cContacts, const uint64_t *pau64Contacts, uint32_t u32ScanTime);
    100101    HRESULT reportAbsEventToVMMDev(int32_t x, int32_t y);
    101102    HRESULT reportAbsEvent(int32_t x, int32_t y, int32_t dz, int32_t dw,
     
    103104    HRESULT convertDisplayRes(LONG x, LONG y, int32_t *pxAdj, int32_t *pyAdj,
    104105                              bool *pfValid);
     106    HRESULT putEventMultiTouch(LONG aCount, LONG64 *paContacts, ULONG aScanTime);
    105107
    106108    void getDeviceCaps(bool *pfAbs, bool *pfRel, bool *fMT);
  • trunk/src/VBox/Main/src-client/ConsoleVRDPServer.cpp

    r47464 r47571  
    28152815            if (pHeader->u16EventId == VRDEINPUT_EVENTID_TOUCH)
    28162816            {
     2817                IMouse *pMouse = pThis->mConsole->getMouse();
     2818
    28172819                VRDEINPUT_TOUCH_EVENT_PDU *p = (VRDEINPUT_TOUCH_EVENT_PDU *)pHeader;
    28182820
     
    28222824                    VRDEINPUT_TOUCH_FRAME *pFrame = &p->aFrames[iFrame];
    28232825
     2826                    com::SafeArray<LONG64> aContacts(pFrame->u16ContactCount);
     2827
    28242828                    uint16_t iContact;
    28252829                    for (iContact = 0; iContact < pFrame->u16ContactCount; iContact++)
     
    28272831                        VRDEINPUT_CONTACT_DATA *pContact = &pFrame->aContacts[iContact];
    28282832
    2829                         LONG x = pContact->i32X;
    2830                         LONG y = pContact->i32Y;
    2831                         LONG cContact = pContact->u8ContactId;
    2832                         LONG contactState = TouchContactState_None;
    2833 
    2834                         /* @todo */
     2833                        int16_t x = (int16_t)(pContact->i32X + 1);
     2834                        int16_t y = (int16_t)(pContact->i32Y + 1);
     2835                        uint8_t contactId = pContact->u8ContactId;
     2836                        uint8_t contactState = TouchContactState_None;
     2837
    28352838                        if (pContact->u32ContactFlags & VRDEINPUT_CONTACT_FLAG_INRANGE)
    28362839                        {
     
    28412844                            contactState |= TouchContactState_InContact;
    28422845                        }
    2843        
    2844                         HRESULT hrc = pThis->mConsole->getMouse()->PutMouseEventMultiTouch(x, y, cContact, contactState);
     2846
     2847                        aContacts[iContact] = RT_MAKE_U64_FROM_U16((uint16_t)x,
     2848                                                                   (uint16_t)y,
     2849                                                                   RT_MAKE_U16(contactId, contactState),
     2850                                                                   0);
    28452851                    }
     2852
     2853                    if (pFrame->u64FrameOffset == 0)
     2854                    {
     2855                        pThis->mu64TouchInputTimestampMCS = 0;
     2856                    }
     2857                    else
     2858                    {
     2859                        pThis->mu64TouchInputTimestampMCS += pFrame->u64FrameOffset;
     2860                    }
     2861
     2862                    pMouse->PutEventMultiTouch(pFrame->u16ContactCount,
     2863                                               ComSafeArrayAsInParam(aContacts),
     2864                                               (ULONG)(pThis->mu64TouchInputTimestampMCS / 1000)); /* Micro->milliseconds. */
    28462865                }
    28472866            }
  • trunk/src/VBox/Main/src-client/MouseImpl.cpp

    r47358 r47571  
    362362}
    363363
    364 
    365 /**
    366  * Send a multi-touch event to the first enabled emulated multi-touch device.
    367  *
    368  * @returns   COM status code
    369  */
    370 HRESULT Mouse::reportMTEventToMouseDev(int32_t x, int32_t y,
    371                                        uint32_t cContact, uint32_t fContact)
    372 {
    373     if (   x < VMMDEV_MOUSE_RANGE_MIN
    374         || x > VMMDEV_MOUSE_RANGE_MAX)
    375         return S_OK;
    376     if (   y < VMMDEV_MOUSE_RANGE_MIN
    377         || y > VMMDEV_MOUSE_RANGE_MAX)
    378         return S_OK;
     364HRESULT Mouse::reportMultiTouchEventToDevice(uint8_t cContacts,
     365                                             const uint64_t *pau64Contacts,
     366                                             uint32_t u32ScanTime)
     367{
     368    HRESULT hrc = S_OK;
     369
    379370    PPDMIMOUSEPORT pUpPort = NULL;
    380371    {
    381372        AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
    382373
    383         for (unsigned i = 0; !pUpPort && i < MOUSE_MAX_DEVICES; ++i)
     374        unsigned i;
     375        for (i = 0; i < MOUSE_MAX_DEVICES; ++i)
    384376        {
    385377            if (   mpDrv[i]
    386378                && (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_MULTI_TOUCH))
     379            {
    387380                pUpPort = mpDrv[i]->pUpPort;
     381                break;
     382            }
    388383        }
    389384    }
    390     if (!pUpPort)
    391         return S_OK;
    392 
    393     int vrc = pUpPort->pfnPutEventMT(pUpPort, x, y,
    394                                      cContact, fContact);
    395     if (RT_FAILURE(vrc))
    396         return setError(VBOX_E_IPRT_ERROR,
    397                         tr("Could not send the touch event to the virtual device (%Rrc)"),
    398                         vrc);
    399     return S_OK;
     385
     386    if (pUpPort)
     387    {
     388        int vrc = pUpPort->pfnPutEventMultiTouch(pUpPort, cContacts, pau64Contacts, u32ScanTime);
     389        if (RT_FAILURE(vrc))
     390            hrc = setError(VBOX_E_IPRT_ERROR,
     391                           tr("Could not send the multi-touch event to the virtual device (%Rrc)"),
     392                           vrc);
     393    }
     394    else
     395    {
     396        hrc = E_UNEXPECTED;
     397    }
     398
     399    return hrc;
    400400}
    401401
     
    638638
    639639/**
    640  * @interface_method_impl{IMouse,putMouseEventMultiTouch}
    641  */
    642 STDMETHODIMP Mouse::PutMouseEventMultiTouch(LONG x, LONG y, LONG cContact,
    643                                             LONG contactState)
     640 * Send a multi-touch event. This requires multi-touch pointing device emulation.
     641 * @note all calls out of this object are made with no locks held!
     642 *
     643 * @returns COM status code.
     644 * @param aCount     Number of contacts.
     645 * @param aContacts  Information about each contact.
     646 * @param aScanTime  Timestamp.
     647 */
     648STDMETHODIMP Mouse::PutEventMultiTouch(LONG aCount,
     649                                       ComSafeArrayIn(LONG64, aContacts),
     650                                       ULONG aScanTime)
    644651{
    645652    AutoCaller autoCaller(this);
    646653    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    647654
    648     LogRel3(("%s: x=%d, y=%d, cContact=%d, contactState=%d\n",
    649              __PRETTY_FUNCTION__, x, y, cContact, contactState));
    650 
    651     int32_t xAdj, yAdj;
    652     bool fValid;
    653 
    654     /** @todo the front end should do this conversion to avoid races */
    655     /** @note Or maybe not... races are pretty inherent in everything done in
    656      *        this object and not really bad as far as I can see. */
    657     HRESULT rc = convertDisplayRes(x, y, &xAdj, &yAdj, &fValid);
    658     if (FAILED(rc)) return rc;
    659 
    660     if (fValid)
    661     {
    662         rc = reportMTEventToMouseDev(xAdj, yAdj, cContact, contactState);
    663 
    664         fireMouseEvent(true, x, y, 0, 0, cContact, contactState);
     655    com::SafeArray <LONG64> arrayContacts(ComSafeArrayInArg(aContacts));
     656
     657    LogRel3(("%s: aCount %d(actual %d), aScanTime %u\n",
     658             __FUNCTION__, aCount, arrayContacts.size(), aScanTime));
     659
     660    HRESULT rc = S_OK;
     661
     662    if ((LONG)arrayContacts.size() >= aCount)
     663    {
     664        LONG64* paContacts = arrayContacts.raw();
     665
     666        rc = putEventMultiTouch(aCount, paContacts, aScanTime);
     667    }
     668    else
     669    {
     670        rc = E_INVALIDARG;
    665671    }
    666672
    667673    return rc;
    668674}
     675
     676/**
     677 * Send a multi-touch event. Version for scripting languages.
     678 *
     679 * @returns COM status code.
     680 * @param aCount     Number of contacts.
     681 * @param aContacts  Information about each contact.
     682 * @param aScanTime  Timestamp.
     683 */
     684STDMETHODIMP Mouse::PutEventMultiTouchString(LONG aCount,
     685                                             IN_BSTR aContacts,
     686                                             ULONG aScanTime)
     687{
     688    /** @todo implement: convert the string to LONG64 array and call putEventMultiTouch. */
     689    NOREF(aCount);
     690    NOREF(aContacts);
     691    NOREF(aScanTime);
     692    return E_NOTIMPL;
     693}
     694
    669695
    670696// private methods
    671697/////////////////////////////////////////////////////////////////////////////
     698
     699/* Used by PutEventMultiTouch and PutEventMultiTouchString. */
     700HRESULT Mouse::putEventMultiTouch(LONG aCount,
     701                                  LONG64 *paContacts,
     702                                  ULONG aScanTime)
     703{
     704    if (aCount >= 256)
     705    {
     706         return E_INVALIDARG;
     707    }
     708
     709    DisplayMouseInterface *pDisplay = mParent->getDisplayMouseInterface();
     710    ComAssertRet(pDisplay, E_FAIL);
     711
     712    HRESULT rc = S_OK;
     713
     714    uint64_t* pau64Contacts = NULL;
     715    uint8_t cContacts = 0;
     716
     717    /* Deliver 0 contacts too, touch device may use this to reset the state. */
     718    if (aCount > 0)
     719    {
     720        /* Create a copy with converted coords. */
     721        pau64Contacts = (uint64_t *)RTMemTmpAlloc(aCount * sizeof(uint64_t));
     722        if (pau64Contacts)
     723        {
     724            int32_t x1, y1, x2, y2;
     725            /* Takes the display lock */
     726            pDisplay->getFramebufferDimensions(&x1, &y1, &x2, &y2);
     727
     728            LONG i;
     729            for (i = 0; i < aCount; i++)
     730            {
     731                int32_t x = (int16_t)RT_LO_U16(RT_LO_U32(paContacts[i]));
     732                int32_t y = (int16_t)RT_HI_U16(RT_LO_U32(paContacts[i]));
     733                uint8_t contactId =  RT_BYTE1(RT_HI_U32(paContacts[i]));
     734                bool fInContact   = (RT_BYTE2(RT_HI_U32(paContacts[i])) & 0x1) != 0;
     735                bool fInRange     = (RT_BYTE2(RT_HI_U32(paContacts[i])) & 0x2) != 0;
     736
     737                LogRel3(("%s: [%d] %d,%d id %d, inContact %d, inRange %d\n",
     738                         __FUNCTION__, i, x, y, fInContact, fInRange));
     739
     740                /* Framebuffer dimensions are 0,0 width, height, that is x2,y2 are exclusive,
     741                 * while coords are inclusive.
     742                 */
     743                int32_t xAdj = x1 < x2 ?   ((x - 1 - x1) * VMMDEV_MOUSE_RANGE)
     744                                         / (x2 - x1) : 0;
     745                int32_t yAdj = y1 < y2 ?   ((y - 1 - y1) * VMMDEV_MOUSE_RANGE)
     746                                         / (y2 - y1) : 0;
     747
     748                bool fValid = (   xAdj >= VMMDEV_MOUSE_RANGE_MIN
     749                               && xAdj <= VMMDEV_MOUSE_RANGE_MAX
     750                               && yAdj >= VMMDEV_MOUSE_RANGE_MIN
     751                               && yAdj <= VMMDEV_MOUSE_RANGE_MAX);
     752
     753                if (fValid)
     754                {
     755                    uint8_t fu8 =   (fInContact? 0x01: 0x00)
     756                                  | (fInRange?   0x02: 0x00);
     757                    pau64Contacts[cContacts] = RT_MAKE_U64_FROM_U16((uint16_t)xAdj,
     758                                                                    (uint16_t)yAdj,
     759                                                                    RT_MAKE_U16(contactId, fu8),
     760                                                                    0);
     761                    cContacts++;
     762                }
     763            }
     764        }
     765        else
     766        {
     767            rc = E_OUTOFMEMORY;
     768        }
     769    }
     770
     771    if (SUCCEEDED(rc))
     772    {
     773        rc = reportMultiTouchEventToDevice(cContacts, cContacts? pau64Contacts: NULL, (uint32_t)aScanTime);
     774
     775        // @todo Implement. Maybe using a new TouchEvent rather than extending the mouse event.
     776        // fireMouseEvent(true, x, y, 0, 0, cContact, contactState);
     777    }
     778
     779    RTMemTmpFree(pau64Contacts);
     780
     781    return rc;
     782}
    672783
    673784
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette