modules/graphics/src/main/native-glass/win/ViewContainer.cpp

Print this page

        

@@ -90,10 +90,11 @@
     m_deadKeyWParam(0)
 {
     m_kbLayout = ::GetKeyboardLayout(0);
     m_idLang = LOWORD(m_kbLayout);
     m_codePage = LangToCodePage(m_idLang);
+    m_lastTouchInputCount = 0;
 }
 
 jobject ViewContainer::GetView()
 {
     return GetGlassView() != NULL ? GetGlassView()->GetView() : NULL;

@@ -1214,10 +1215,25 @@
     operator HTOUCHINPUT() const {
         return m_h;
     }
 };
 
+static BOOL debugTouch = false;
+
+static char * touchEventName(unsigned int dwFlags) {
+        if (dwFlags & TOUCHEVENTF_MOVE) {
+            return "MOVE";
+        }
+        if (dwFlags & TOUCHEVENTF_DOWN) {
+            return "PRESS";
+        }
+        if (dwFlags & TOUCHEVENTF_UP) {
+            return "RELEASE";
+        }
+        return "UNKOWN";
+}
+
 void NotifyTouchInput(
         HWND hWnd, jobject view, jclass gestureSupportCls, 
         const TOUCHINPUT* ti, unsigned count) 
 {
 

@@ -1293,40 +1309,151 @@
     }
 }
 
 } // namespace
 
-void ViewContainer::HandleViewTouchEvent(
+unsigned int ViewContainer::HandleViewTouchEvent(
         HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
-    // Preallocated arrays. One element per finger. Though so far
-    // Win 7 can handle at most four touch points simultaneously, 
-    // so the buffer is excessive.
-    TOUCHINPUT staticTouchInputBuf[10];
-
-    std::vector<TOUCHINPUT> dynamicTouchInputBuf;
-    PTOUCHINPUT pInputs = staticTouchInputBuf;
-
-    const UINT cInputs = static_cast<UINT>(LOWORD(wParam));
-    if (ARRAYSIZE(staticTouchInputBuf) < cInputs) {
-        dynamicTouchInputBuf.resize(cInputs);
-        pInputs = &*dynamicTouchInputBuf.begin();
+    const UINT newCount = static_cast<UINT>(LOWORD(wParam));
+    TOUCHINPUT * tempTouchInputBuf;
+
+    unsigned int bufsz = newCount >  10 ? newCount : 10;
+    if (m_thisTouchInputBuf.size() < bufsz) {
+        m_thisTouchInputBuf.resize(bufsz);
     }
 
+    if (newCount > 0) {
+        tempTouchInputBuf = new TOUCHINPUT[newCount];
     do {
         AutoTouchInputHandle inputInfo(lParam);
-        if (!::GetTouchInputInfo(inputInfo, cInputs, 
-                                 pInputs, sizeof(TOUCHINPUT))) {
-            return;
+            if (!::GetTouchInputInfo(inputInfo, newCount,
+                                     tempTouchInputBuf, sizeof(TOUCHINPUT))) {
+                return 0;
         }
     } while(0); // scope for 'inputInfo'
+    }
+
+    // Fix up the touch point stream. Some drivers seem to lose touch events,
+    // dropping PRESS, MOVE, UP, so we need to add them back in.
+
+    unsigned int activeCount = 0;
+    unsigned int pointsCount = 0;
 
-    NotifyTouchInput(hWnd, GetView(), m_gestureSupportCls, pInputs, cInputs);
+    // check first for any "lost" touches
+    // these need to get added to the send list of points
+    for (unsigned int i = 0 ; i < m_lastTouchInputCount; i++) {
+        if (!(m_lastTouchInputBuf[i].dwFlags & TOUCHEVENTF_UP)) {
+            // looking for a dwID that is
+            //   not present in the new batch
+            //   was not UP in the old batch
+            bool found = false;
+            for (unsigned int j = 0; j < newCount; j++) {
+                if (m_lastTouchInputBuf[i].dwID == tempTouchInputBuf[j].dwID) {
+                    found = true;
+                    //break;
+                }
+            }
+            if (!found) {
+                // We have a old event but not a new one, so release it
+                m_thisTouchInputBuf[pointsCount].dwFlags = TOUCHEVENTF_UP;
+                m_thisTouchInputBuf[pointsCount].dwID = m_lastTouchInputBuf[i].dwID;
+                m_thisTouchInputBuf[pointsCount].x = m_lastTouchInputBuf[i].x;
+                m_thisTouchInputBuf[pointsCount].y = m_lastTouchInputBuf[i].y;
+                if (newCount > 0) {
+                    //use the time of the first new element for our inserted event
+                    m_thisTouchInputBuf[pointsCount].dwTime = tempTouchInputBuf[0].dwTime;
+                } else {
+                    m_thisTouchInputBuf[pointsCount].dwTime = m_lastTouchInputBuf[i].dwTime;
+                }
+                m_thisTouchInputBuf[pointsCount].dwMask = m_lastTouchInputBuf[i].dwMask;
+
+                if (debugTouch) {
+                        printf("TOUCH FIX UP  %d, %s\n", m_lastTouchInputBuf[i].dwID, touchEventName(m_lastTouchInputBuf[i].dwFlags));
+                }
+
+                pointsCount++;
+            }
+         }
+    }
+
+    if (pointsCount + newCount > m_thisTouchInputBuf.size()) {
+        bufsz = pointsCount + newCount;
+        m_thisTouchInputBuf.resize(bufsz);
+    }
+
+    // now fold in the current touch points
+    for (unsigned int i = 0 ; i < newCount; i++) {
+        bool found = false;
+        for (unsigned int j = 0 ; j < m_lastTouchInputCount; j++) {
+            if (m_lastTouchInputBuf[j].dwID == tempTouchInputBuf[i].dwID) {
+                found = true;
+                break;
+            }
+        }
+
+        m_thisTouchInputBuf[pointsCount].dwFlags = tempTouchInputBuf[i].dwFlags;
+        m_thisTouchInputBuf[pointsCount].dwID = tempTouchInputBuf[i].dwID;
+        m_thisTouchInputBuf[pointsCount].dwTime = tempTouchInputBuf[i].dwTime;
+        m_thisTouchInputBuf[pointsCount].dwMask = tempTouchInputBuf[i].dwMask;
+        m_thisTouchInputBuf[pointsCount].x = tempTouchInputBuf[i].x;
+        m_thisTouchInputBuf[pointsCount].y = tempTouchInputBuf[i].y;
+
+        if (m_thisTouchInputBuf[pointsCount].dwFlags & TOUCHEVENTF_DOWN) {
+            pointsCount++;
+            activeCount ++;
+        } else if (m_thisTouchInputBuf[pointsCount].dwFlags & TOUCHEVENTF_MOVE) {
+                if (!found) {
+                    if (debugTouch) {
+                        printf("TOUCH FIX MV->DOWN  %d, %s\n", m_thisTouchInputBuf[pointsCount].dwID, touchEventName(m_thisTouchInputBuf[pointsCount].dwFlags));
+            }
+                        m_thisTouchInputBuf[pointsCount].dwFlags = TOUCHEVENTF_DOWN;
+                    }
+                pointsCount++;
+                activeCount ++;
+        } else if (m_thisTouchInputBuf[pointsCount].dwFlags & TOUCHEVENTF_UP) {
+               if (found) {
+                    pointsCount++;
+               } else {
+                   // UP without a previous DOWN, ignore it
+               }
+        }
+     }
+
+     if (debugTouch) {
+        printf("Touch Sequence %d/%d win=%d view=%d %d,%d,%d\n",pointsCount,activeCount,
+            hWnd, GetView(),
+            m_lastTouchInputCount, newCount, pointsCount);
+        for (unsigned int i = 0 ; i < m_lastTouchInputCount; i++) {
+            printf("  old  %d, %s\n", m_lastTouchInputBuf[i].dwID, touchEventName(m_lastTouchInputBuf[i].dwFlags));
+        }
+        for (unsigned int i = 0 ; i < newCount; i++) {
+            printf("  in   %d, %s\n", tempTouchInputBuf[i].dwID, touchEventName(tempTouchInputBuf[i].dwFlags));
+        }
+        for (unsigned int i = 0 ; i < pointsCount; i++) {
+            printf("  this %d, %d\n", m_thisTouchInputBuf[i].dwID, m_thisTouchInputBuf[i].dwFlags & 0x07);
+        }
+        printf("  ---\n");
+        fflush(stdout);
+     }
+
+    if (pointsCount > 0) {
+        NotifyTouchInput(hWnd, GetView(), m_gestureSupportCls, &m_thisTouchInputBuf[0], pointsCount);
 
     if (m_manipProc) {
-        NotifyManipulationProcessor(*m_manipProc, pInputs, cInputs);
+            NotifyManipulationProcessor(*m_manipProc, &m_thisTouchInputBuf[0], pointsCount);
     }
+
+        std::swap(m_lastTouchInputBuf, m_thisTouchInputBuf);
+        m_lastTouchInputCount = pointsCount;
+    }
+
+    if ( newCount > 0) {
+        delete [] tempTouchInputBuf;
+    }
+
+    return activeCount;
 }
 
 void ViewContainer::HandleViewTimerEvent(HWND hwnd, UINT_PTR timerID)
 {
     if (IDT_GLASS_INERTIAPROCESSOR == timerID) {