VirtualBox

Changeset 95275 in vbox for trunk/src


Ignore:
Timestamp:
Jun 14, 2022 11:14:07 AM (3 years ago)
Author:
vboxsync
Message:

UsbMouse: Merged touchpad and touchscreen logic (see bugref:9891).

File:
1 edited

Legend:

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

    r95272 r95275  
    242242    bool fTouchReporting;
    243243    bool fTouchStateUpdated;
    244 
    245     struct
    246     {
    247         MTCONTACT aCurrentContactState[TPAD_CONTACT_MAX_COUNT];
    248         MTCONTACT aReportingContactState[TPAD_CONTACT_MAX_COUNT];
    249         uint32_t u32LastTouchScanTime;
    250         bool fTouchReporting;
    251         bool fTouchStateUpdated;
    252     } tpad;
    253244} USBHID;
    254245/** Pointer to the USB HID instance data. */
     
    318309/**
    319310 * The USB HID report structure for the touchpad device.
     311 * It is a superset of the multi-touch report.
    320312 */
    321313typedef struct USBHIDTP_REPORT
    322314{
    323     uint8_t     idReport;
    324     uint8_t     cContacts;
    325     struct
    326     {
    327         uint8_t     fContact;
    328         uint8_t     cContact;
    329         uint16_t    x;
    330         uint16_t    y;
    331     } aContacts[MT_CONTACTS_PER_REPORT];
    332     uint32_t    u32ScanTime;
    333     uint8_t     buttons;
     315    USBHIDMT_REPORT mt;
     316    uint8_t         buttons;    /* Required by Win10, not used. */
    334317} USBHIDTP_REPORT, *PUSBHIDTP_REPORT;
    335318
     
    15191502    pThis->fHasPendingChanges = false;
    15201503    pThis->fTouchStateUpdated = false;
    1521     pThis->tpad.fTouchStateUpdated = false;
    15221504
    15231505    for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
     
    16241606    uint8_t cContacts = 0;
    16251607
     1608    uint8_t cMaxContacts = pThis->enmMode == USBHIDMODE_MT_RELATIVE ? TPAD_CONTACT_MAX_COUNT  : MT_CONTACT_MAX_COUNT;
     1609    size_t  cbReport     = pThis->enmMode == USBHIDMODE_MT_RELATIVE ? sizeof(USBHIDTP_REPORT) : sizeof(USBHIDMT_REPORT);
     1610
    16261611    Assert(pThis->fHasPendingChanges);
    16271612
     
    16351620         * that is they must be reported to the guest.
    16361621         */
    1637         for (i = 0; i < MT_CONTACT_MAX_COUNT; i++)
     1622        for (i = 0; i < cMaxContacts; i++)
    16381623        {
    16391624            pRepContact = &pThis->aReportingContactState[i];
     
    16861671
    16871672    /* Report current state. */
    1688     USBHIDMT_REPORT r;
    1689     USBHIDMT_REPORT *p = &r;
     1673    USBHIDTP_REPORT r;
     1674    USBHIDTP_REPORT *p = &r;
    16901675    RT_ZERO(*p);
    16911676
    1692     p->idReport = REPORTID_TOUCH_EVENT;
    1693     p->cContacts = cContacts;
     1677    p->mt.idReport = REPORTID_TOUCH_EVENT;
     1678    p->mt.cContacts = cContacts;
     1679    p->buttons = 0; /* Not currently used. */
    16941680
    16951681    uint8_t iReportedContact;
     
    17191705        }
    17201706
    1721         p->aContacts[iReportedContact].fContact = pRepContact->flags;
    1722         p->aContacts[iReportedContact].cContact = pRepContact->id;
    1723         p->aContacts[iReportedContact].x = pRepContact->x >> pThis->u8CoordShift;
    1724         p->aContacts[iReportedContact].y = pRepContact->y >> pThis->u8CoordShift;
    1725     }
    1726 
    1727     p->u32ScanTime = pThis->u32LastTouchScanTime * 10;
     1707        p->mt.aContacts[iReportedContact].fContact = pRepContact->flags;
     1708        p->mt.aContacts[iReportedContact].cContact = pRepContact->id;
     1709        p->mt.aContacts[iReportedContact].x = pRepContact->x >> pThis->u8CoordShift;
     1710        p->mt.aContacts[iReportedContact].y = pRepContact->y >> pThis->u8CoordShift;
     1711
     1712        if (pThis->enmMode == USBHIDMODE_MT_RELATIVE) {
     1713            /** @todo Parse touch confidence in Qt frontend */
     1714            p->mt.aContacts[iReportedContact].fContact |= MT_CONTACT_F_CONFIDENCE;
     1715        }
     1716    }
     1717
     1718    p->mt.u32ScanTime = pThis->u32LastTouchScanTime * 10;
    17281719
    17291720    Assert(iReportedContact > 0);
     
    17441735    }
    17451736
    1746     LogRel3(("usbHid: reporting touch contact:\n%.*Rhxd\n", sizeof(USBHIDMT_REPORT), p));
    1747     return usbHidCompleteOk(pThis, pUrb, p, sizeof(USBHIDMT_REPORT));
    1748 }
    1749 
    1750 
    1751 static int usbHidSendTouchPadReport(PUSBHID pThis, PVUSBURB pUrb)
    1752 {
    1753     uint8_t i;
    1754     MTCONTACT *pRepContact;
    1755     MTCONTACT *pCurContact;
    1756 
    1757     /* Number of contacts to be reported. In hybrid mode the first report contains
    1758      * total number of contacts and subsequent reports contain 0.
    1759      */
    1760     uint8_t cContacts = 0;
    1761 
    1762     Assert(pThis->fHasPendingChanges);
    1763 
    1764     if (!pThis->tpad.fTouchReporting)
    1765     {
    1766         pThis->tpad.fTouchReporting = true;
    1767         pThis->tpad.fTouchStateUpdated = false;
    1768 
    1769         /* Update the reporting state with the new current state.
    1770          * Also mark all active contacts in reporting state as dirty,
    1771          * that is they must be reported to the guest.
    1772          */
    1773         for (i = 0; i < TPAD_CONTACT_MAX_COUNT; i++)
    1774         {
    1775             pRepContact = &pThis->tpad.aReportingContactState[i];
    1776             pCurContact = &pThis->tpad.aCurrentContactState[i];
    1777 
    1778             if (pCurContact->status & MT_CONTACT_S_ACTIVE)
    1779             {
    1780                 if (pCurContact->status & MT_CONTACT_S_REUSED)
    1781                 {
    1782                     pCurContact->status &= ~MT_CONTACT_S_REUSED;
    1783 
    1784                     /* Keep x,y. Will report lost contact at this point. */
    1785                     pRepContact->id     = pCurContact->oldId;
    1786                     pRepContact->flags  = 0;
    1787                     pRepContact->status = MT_CONTACT_S_REUSED;
    1788                 }
    1789                 else if (pThis->tpad.aCurrentContactState[i].status & MT_CONTACT_S_CANCELLED)
    1790                 {
    1791                     pCurContact->status &= ~(MT_CONTACT_S_CANCELLED | MT_CONTACT_S_ACTIVE);
    1792 
    1793                     /* Keep x,y. Will report lost contact at this point. */
    1794                     pRepContact->id     = pCurContact->id;
    1795                     pRepContact->flags  = 0;
    1796                     pRepContact->status = 0;
    1797                 }
    1798                 else
    1799                 {
    1800                     if (pCurContact->flags == 0)
    1801                     {
    1802                         pCurContact->status &= ~MT_CONTACT_S_ACTIVE; /* Contact disapeared. */
    1803                     }
    1804 
    1805                     pRepContact->x      = pCurContact->x;
    1806                     pRepContact->y      = pCurContact->y;
    1807                     pRepContact->id     = pCurContact->id;
    1808                     pRepContact->flags  = pCurContact->flags;
    1809                     pRepContact->status = 0;
    1810                 }
    1811 
    1812                 cContacts++;
    1813 
    1814                 pRepContact->status |= MT_CONTACT_S_DIRTY;
    1815             }
    1816             else
    1817             {
    1818                 pRepContact->status = 0;
    1819             }
    1820         }
    1821     }
    1822 
    1823     /* Report current state. */
    1824     USBHIDTP_REPORT r;
    1825     USBHIDTP_REPORT *p = &r;
    1826     RT_ZERO(*p);
    1827 
    1828     p->idReport = REPORTID_TOUCH_EVENT;
    1829     p->cContacts = cContacts;
    1830     p->buttons = 0;
    1831 
    1832     uint8_t iReportedContact;
    1833     for (iReportedContact = 0; iReportedContact < MT_CONTACTS_PER_REPORT; iReportedContact++)
    1834     {
    1835         /* Find the next not reported contact. */
    1836         pRepContact = usbHidFindMTContact(pThis->tpad.aReportingContactState, RT_ELEMENTS(pThis->tpad.aReportingContactState),
    1837                                           MT_CONTACT_S_DIRTY, MT_CONTACT_S_DIRTY);
    1838 
    1839         if (!pRepContact)
    1840         {
    1841             LogRel3(("usbHid: no more touch contacts to report\n"));
    1842             break;
    1843         }
    1844 
    1845         if (pRepContact->status & MT_CONTACT_S_REUSED)
    1846         {
    1847             /* Do not clear DIRTY flag for contacts which were reused.
    1848              * Because two reports must be generated:
    1849              * one for old contact off, and the second for new contact on.
    1850              */
    1851             pRepContact->status &= ~MT_CONTACT_S_REUSED;
    1852         }
    1853         else
    1854         {
    1855             pRepContact->status &= ~MT_CONTACT_S_DIRTY;
    1856         }
    1857 
    1858         /** @todo Parse touch confidence in Qt frontend */
    1859         p->aContacts[iReportedContact].fContact = pRepContact->flags | MT_CONTACT_F_CONFIDENCE;
    1860         p->aContacts[iReportedContact].cContact = pRepContact->id;
    1861         p->aContacts[iReportedContact].x = pRepContact->x >> pThis->u8CoordShift;
    1862         p->aContacts[iReportedContact].y = pRepContact->y >> pThis->u8CoordShift;
    1863     }
    1864 
    1865     p->u32ScanTime = pThis->tpad.u32LastTouchScanTime * 10;
    1866 
    1867     Assert(iReportedContact > 0);
    1868 
    1869     /* Reset TouchReporting if all contacts reported. */
    1870     pRepContact = usbHidFindMTContact(pThis->tpad.aReportingContactState, RT_ELEMENTS(pThis->tpad.aReportingContactState),
    1871                                       MT_CONTACT_S_DIRTY, MT_CONTACT_S_DIRTY);
    1872 
    1873     if (!pRepContact)
    1874     {
    1875         LogRel3(("usbHid: all touch contacts reported\n"));
    1876         pThis->tpad.fTouchReporting = false;
    1877         pThis->fHasPendingChanges = pThis->tpad.fTouchStateUpdated;
    1878     }
    1879     else
    1880     {
    1881         pThis->fHasPendingChanges = true;
    1882     }
    1883 
    1884     LogRel3(("usbHid: reporting touch contact:\n%.*Rhxd\n", sizeof(USBHIDTP_REPORT), p));
    1885     return usbHidCompleteOk(pThis, pUrb, p, sizeof(USBHIDTP_REPORT));
    1886 }
     1737    LogRel3(("usbHid: reporting touch contact:\n%.*Rhxd\n", cbReport, p));
     1738    return usbHidCompleteOk(pThis, pUrb, p, cbReport);
     1739}
     1740
    18871741
    18881742/**
     
    18931747    PVUSBURB    pUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue);
    18941748
    1895     if (pThis->enmMode == USBHIDMODE_MT_ABSOLUTE)
    1896     {
    1897         /* This device uses a different reporting method and fHasPendingChanges maintenance. */
     1749    if (pThis->enmMode == USBHIDMODE_MT_ABSOLUTE || pThis->enmMode == USBHIDMODE_MT_RELATIVE)
     1750    {
     1751        /* These modes use a different reporting method and maintain fHasPendingChanges. */
    18981752        if (pUrb)
    18991753            return usbHidSendMultiTouchReport(pThis, pUrb);
    1900         return VINF_SUCCESS;
    1901     }
    1902     if (pThis->enmMode == USBHIDMODE_MT_RELATIVE)
    1903     {
    1904         /* This device uses a different reporting method and fHasPendingChanges maintenance. */
    1905         if (pUrb)
    1906             return usbHidSendTouchPadReport(pThis, pUrb);
    19071754        return VINF_SUCCESS;
    19081755    }
     
    19961843 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventTouchScreen}
    19971844 */
    1998 static DECLCALLBACK(int) usbHidMousePutEventTouchScreen(PPDMIMOUSEPORT pInterface,
     1845static DECLCALLBACK(int) usbHidMousePutEventMultiTouch(PUSBHID pThis,
    19991846                                                       uint8_t cContacts,
    20001847                                                       const uint64_t *pau64Contacts,
     
    20161863        paNewContacts[i].y      = (uint16_t)(u32Lo >> 16);
    20171864        paNewContacts[i].id     = RT_BYTE1(u32Hi);
    2018         paNewContacts[i].flags  = RT_BYTE2(u32Hi) & (MT_CONTACT_F_IN_CONTACT | MT_CONTACT_F_IN_RANGE);
     1865        paNewContacts[i].flags  = RT_BYTE2(u32Hi);
    20191866        paNewContacts[i].status = MT_CONTACT_S_DIRTY;
    20201867        paNewContacts[i].oldId  = 0; /* Not used. */
    2021         if (paNewContacts[i].flags & MT_CONTACT_F_IN_CONTACT)
     1868
     1869        if (pThis->enmMode == USBHIDMODE_MT_ABSOLUTE)
    20221870        {
    2023             paNewContacts[i].flags |= MT_CONTACT_F_IN_RANGE;
     1871            paNewContacts[i].flags &= MT_CONTACT_F_IN_CONTACT | MT_CONTACT_F_IN_RANGE;
     1872            if (paNewContacts[i].flags & MT_CONTACT_F_IN_CONTACT)
     1873            {
     1874                paNewContacts[i].flags |= MT_CONTACT_F_IN_RANGE;
     1875            }
    20241876        }
    2025     }
    2026 
    2027     PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
     1877        else
     1878        {
     1879            Assert(pThis->enmMode == USBHIDMODE_MT_RELATIVE);
     1880            paNewContacts[i].flags &= MT_CONTACT_F_IN_CONTACT;
     1881        }
     1882    }
     1883
    20281884    MTCONTACT *pCurContact = NULL;
    20291885    MTCONTACT *pNewContact = NULL;
    20301886
    20311887    RTCritSectEnter(&pThis->CritSect);
    2032 
    2033     Assert(pThis->enmMode == USBHIDMODE_MT_ABSOLUTE);
    20341888
    20351889    /* Maintain a state of all current contacts.
     
    21672021
    21682022/**
     2023 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventTouchScreen}
     2024 */
     2025static DECLCALLBACK(int) usbHidMousePutEventTouchScreen(PPDMIMOUSEPORT pInterface,
     2026                                                       uint8_t cContacts,
     2027                                                       const uint64_t *pau64Contacts,
     2028                                                       uint32_t u32ScanTime)
     2029{
     2030    PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
     2031
     2032    Assert(pThis->enmMode == USBHIDMODE_MT_ABSOLUTE);
     2033
     2034    return usbHidMousePutEventMultiTouch(pThis, cContacts, pau64Contacts, u32ScanTime);
     2035}
     2036
     2037/**
    21692038 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventTouchPad}
    21702039 */
     
    21742043                                                       uint32_t u32ScanTime)
    21752044{
    2176     uint8_t i;
    2177     uint8_t j;
    2178 
    2179     /* Make a copy of new contacts */
    2180     MTCONTACT *paNewContacts = (MTCONTACT *)RTMemTmpAlloc(sizeof(MTCONTACT) * cContacts);
    2181     if (!paNewContacts)
    2182         return VERR_NO_MEMORY;
    2183 
    2184     for (i = 0; i < cContacts; i++)
    2185     {
    2186         uint32_t u32Lo = RT_LO_U32(pau64Contacts[i]);
    2187         uint32_t u32Hi = RT_HI_U32(pau64Contacts[i]);
    2188         paNewContacts[i].x      = (uint16_t)u32Lo;
    2189         paNewContacts[i].y      = (uint16_t)(u32Lo >> 16);
    2190         paNewContacts[i].id     = RT_BYTE1(u32Hi);
    2191         paNewContacts[i].flags  = RT_BYTE2(u32Hi) & MT_CONTACT_F_IN_CONTACT;
    2192         paNewContacts[i].status = MT_CONTACT_S_DIRTY;
    2193         paNewContacts[i].oldId  = 0; /* Not used. */
    2194     }
    2195 
    21962045    PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
    2197     MTCONTACT *pCurContact = NULL;
    2198     MTCONTACT *pNewContact = NULL;
    2199 
    2200     RTCritSectEnter(&pThis->CritSect);
    22012046
    22022047    Assert(pThis->enmMode == USBHIDMODE_MT_RELATIVE);
    22032048
    2204     /* Maintain a state of all current contacts.
    2205      * Intr URBs will be completed according to the state.
    2206      */
    2207 
    2208     /* Mark all existing contacts as dirty. */
    2209     for (i = 0; i < RT_ELEMENTS(pThis->tpad.aCurrentContactState); i++)
    2210         pThis->tpad.aCurrentContactState[i].status |= MT_CONTACT_S_DIRTY;
    2211 
    2212     /* Update existing contacts and mark new contacts. */
    2213     for (i = 0; i < cContacts; i++)
    2214     {
    2215         pNewContact = &paNewContacts[i];
    2216 
    2217         /* Find existing contact with the same id. */
    2218         pCurContact = NULL;
    2219         for (j = 0; j < RT_ELEMENTS(pThis->tpad.aCurrentContactState); j++)
    2220         {
    2221             if (   (pThis->tpad.aCurrentContactState[j].status & MT_CONTACT_S_ACTIVE) != 0
    2222                 && pThis->tpad.aCurrentContactState[j].id == pNewContact->id)
    2223             {
    2224                 pCurContact = &pThis->tpad.aCurrentContactState[j];
    2225                 break;
    2226             }
    2227         }
    2228 
    2229         if (pCurContact)
    2230         {
    2231             pNewContact->status &= ~MT_CONTACT_S_DIRTY;
    2232 
    2233             pCurContact->x = pNewContact->x;
    2234             pCurContact->y = pNewContact->y;
    2235             if (pCurContact->flags == 0) /* Contact disappeared already. */
    2236             {
    2237                 if ((pCurContact->status & MT_CONTACT_S_REUSED) == 0)
    2238                 {
    2239                     pCurContact->status |= MT_CONTACT_S_REUSED; /* Report to the guest that the contact not in touch. */
    2240                     pCurContact->oldId = pCurContact->id;
    2241                 }
    2242             }
    2243             pCurContact->flags = pNewContact->flags;
    2244             pCurContact->status &= ~MT_CONTACT_S_DIRTY;
    2245         }
    2246     }
    2247 
    2248     /* Append new contacts (the dirty one in the paNewContacts). */
    2249     for (i = 0; i < cContacts; i++)
    2250     {
    2251         pNewContact = &paNewContacts[i];
    2252 
    2253         if (pNewContact->status & MT_CONTACT_S_DIRTY)
    2254         {
    2255             /* It is a new contact, copy is to one of not ACTIVE or not updated existing contacts. */
    2256             pCurContact = usbHidFindMTContact(pThis->tpad.aCurrentContactState, RT_ELEMENTS(pThis->tpad.aCurrentContactState),
    2257                                               MT_CONTACT_S_ACTIVE, 0);
    2258 
    2259             if (pCurContact)
    2260             {
    2261                 *pCurContact = *pNewContact;
    2262                 pCurContact->status = MT_CONTACT_S_ACTIVE; /* Reset status. */
    2263             }
    2264             else
    2265             {
    2266                 /* Dirty existing contacts can be reused. */
    2267                 pCurContact = usbHidFindMTContact(pThis->tpad.aCurrentContactState, RT_ELEMENTS(pThis->tpad.aCurrentContactState),
    2268                                                   MT_CONTACT_S_ACTIVE | MT_CONTACT_S_DIRTY,
    2269                                                   MT_CONTACT_S_ACTIVE | MT_CONTACT_S_DIRTY);
    2270 
    2271                 if (pCurContact)
    2272                 {
    2273                     pCurContact->x = pNewContact->x;
    2274                     pCurContact->y = pNewContact->y;
    2275                     if ((pCurContact->status & MT_CONTACT_S_REUSED) == 0)
    2276                     {
    2277                         pCurContact->status |= MT_CONTACT_S_REUSED; /* Report to the guest that the contact not in touch. */
    2278                         pCurContact->oldId = pCurContact->id;
    2279                     }
    2280                     pCurContact->flags = pNewContact->flags;
    2281                     pCurContact->status &= ~MT_CONTACT_S_DIRTY;
    2282                 }
    2283                 else
    2284                 {
    2285                     LogRel3(("usbHid: dropped new contact: %d,%d id %d flags %RX8 status %RX8 oldId %d\n",
    2286                              pNewContact->x,
    2287                              pNewContact->y,
    2288                              pNewContact->id,
    2289                              pNewContact->flags,
    2290                              pNewContact->status,
    2291                              pNewContact->oldId
    2292                            ));
    2293                 }
    2294             }
    2295         }
    2296     }
    2297 
    2298     /* Mark still dirty existing contacts as cancelled, because a new set of contacts does not include them. */
    2299     for (i = 0; i < RT_ELEMENTS(pThis->tpad.aCurrentContactState); i++)
    2300     {
    2301         pCurContact = &pThis->tpad.aCurrentContactState[i];
    2302         if (pCurContact->status & MT_CONTACT_S_DIRTY)
    2303         {
    2304             pCurContact->status |= MT_CONTACT_S_CANCELLED;
    2305             pCurContact->status &= ~MT_CONTACT_S_DIRTY;
    2306         }
    2307     }
    2308 
    2309     pThis->tpad.u32LastTouchScanTime = u32ScanTime;
    2310 
    2311     LogRel3(("usbHid: scanTime (ms): %d\n", pThis->tpad.u32LastTouchScanTime));
    2312     for (i = 0; i < RT_ELEMENTS(pThis->tpad.aCurrentContactState); i++)
    2313     {
    2314         LogRel3(("usbHid: contact state[%d]: %d,%d id %d flags %RX8 status %RX8 oldId %d\n",
    2315                   i,
    2316                   pThis->tpad.aCurrentContactState[i].x,
    2317                   pThis->tpad.aCurrentContactState[i].y,
    2318                   pThis->tpad.aCurrentContactState[i].id,
    2319                   pThis->tpad.aCurrentContactState[i].flags,
    2320                   pThis->tpad.aCurrentContactState[i].status,
    2321                   pThis->tpad.aCurrentContactState[i].oldId
    2322                 ));
    2323     }
    2324 
    2325     pThis->tpad.fTouchStateUpdated = true;
    2326     pThis->fHasPendingChanges = true;
    2327 
    2328     /* Send a report if possible. */
    2329     usbHidSendReport(pThis);
    2330 
    2331     RTCritSectLeave(&pThis->CritSect);
    2332 
    2333     RTMemTmpFree(paNewContacts);
    2334     return VINF_SUCCESS;
     2049    return usbHidMousePutEventMultiTouch(pThis, cContacts, pau64Contacts, u32ScanTime);
    23352050}
    23362051
     
    25612276                            /* The actual state should be reported here. */
    25622277                            RT_ZERO(*p);
    2563                             p->idReport = REPORTID_TOUCH_EVENT;
     2278                            p->mt.idReport = REPORTID_TOUCH_EVENT;
    25642279                            cbData = sizeof(USBHIDTP_REPORT);
    25652280                            break;
Note: See TracChangeset for help on using the changeset viewer.

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