Touch input support for Windows

Had to add some logic to avoid touch and mouse cross-talk, because
(at least on my laptop), the touch screen generates both kinds of
events.

This seems really useful [1] for the many [2] Skia developers with
touch-enabled Windows devices.

----------
1: No, not really.
2: N = 1?

Bug: skia:
Change-Id: Ib888bf4198f2cc0a29a31581ec4b64d3d9008c33
Reviewed-on: https://skia-review.googlesource.com/18920
Reviewed-by: Yuqian Li <liyuqian@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2017-06-07 10:00:30 -04:00 committed by Skia Commit-Bot
parent 2e425ebd95
commit b53f48cfec
5 changed files with 50 additions and 5 deletions

View File

@ -39,6 +39,7 @@ public:
bool isActive() { return fFlinger.isActive(); } bool isActive() { return fFlinger.isActive(); }
void stop() { fFlinger.stop(); } void stop() { fFlinger.stop(); }
bool isBeingTouched() { return kEmpty_State != fState; }
const SkMatrix& localM(); const SkMatrix& localM();
const SkMatrix& globalM() const { return fGlobalM; } const SkMatrix& globalM() const { return fGlobalM; }

View File

@ -209,10 +209,8 @@ void SkTouchGesture::touchMoved(void* owner, float x, float y) {
int index = this->findRec(owner); int index = this->findRec(owner);
if (index < 0) { if (index < 0) {
// not found, so I guess we should add it... SkDebugf("---- ignoring move without begin\n");
SkDebugf("---- add missing begin\n"); return;
this->appendNewRec(owner, x, y);
index = fTouches.count() - 1;
} }
Rec& rec = fTouches[index]; Rec& rec = fTouches[index];
@ -220,7 +218,7 @@ void SkTouchGesture::touchMoved(void* owner, float x, float y) {
// not sure how valuable this is // not sure how valuable this is
if (fTouches.count() == 2) { if (fTouches.count() == 2) {
if (close_enough_for_jitter(rec.fLastX, rec.fLastY, x, y)) { if (close_enough_for_jitter(rec.fLastX, rec.fLastY, x, y)) {
// SkDebugf("--- drop touchMove, withing jitter tolerance %g %g\n", rec.fLastX - x, rec.fLastY - y); // SkDebugf("--- drop touchMove, within jitter tolerance %g %g\n", rec.fLastX - x, rec.fLastY - y);
return; return;
} }
} }

View File

@ -251,6 +251,7 @@ Viewer::Viewer(int argc, char** argv, void* platformData)
, fColorMode(ColorMode::kLegacy) , fColorMode(ColorMode::kLegacy)
, fColorSpacePrimaries(gSrgbPrimaries) , fColorSpacePrimaries(gSrgbPrimaries)
, fZoomLevel(0.0f) , fZoomLevel(0.0f)
, fGestureDevice(GestureDevice::kNone)
{ {
static SkTaskGroup::Enabler kTaskGroupEnabler; static SkTaskGroup::Enabler kTaskGroupEnabler;
SkGraphics::Init(); SkGraphics::Init();
@ -819,6 +820,9 @@ void Viewer::onPaint(SkCanvas* canvas) {
} }
bool Viewer::onTouch(intptr_t owner, Window::InputState state, float x, float y) { bool Viewer::onTouch(intptr_t owner, Window::InputState state, float x, float y) {
if (GestureDevice::kMouse == fGestureDevice) {
return false;
}
void* castedOwner = reinterpret_cast<void*>(owner); void* castedOwner = reinterpret_cast<void*>(owner);
switch (state) { switch (state) {
case Window::kUp_InputState: { case Window::kUp_InputState: {
@ -834,11 +838,15 @@ bool Viewer::onTouch(intptr_t owner, Window::InputState state, float x, float y)
break; break;
} }
} }
fGestureDevice = fGesture.isBeingTouched() ? GestureDevice::kTouch : GestureDevice::kNone;
fWindow->inval(); fWindow->inval();
return true; return true;
} }
bool Viewer::onMouse(float x, float y, Window::InputState state, uint32_t modifiers) { bool Viewer::onMouse(float x, float y, Window::InputState state, uint32_t modifiers) {
if (GestureDevice::kTouch == fGestureDevice) {
return false;
}
switch (state) { switch (state) {
case Window::kUp_InputState: { case Window::kUp_InputState: {
fGesture.touchEnd(nullptr); fGesture.touchEnd(nullptr);
@ -853,6 +861,7 @@ bool Viewer::onMouse(float x, float y, Window::InputState state, uint32_t modifi
break; break;
} }
} }
fGestureDevice = fGesture.isBeingTouched() ? GestureDevice::kMouse : GestureDevice::kNone;
fWindow->inval(); fWindow->inval();
return true; return true;
} }

View File

@ -91,7 +91,14 @@ private:
sk_app::CommandSet fCommands; sk_app::CommandSet fCommands;
enum class GestureDevice {
kNone,
kTouch,
kMouse,
};
SkTouchGesture fGesture; SkTouchGesture fGesture;
GestureDevice fGestureDevice;
// identity unless the window initially scales the content to fit the screen. // identity unless the window initially scales the content to fit the screen.
SkMatrix fDefaultMatrix; SkMatrix fDefaultMatrix;

View File

@ -114,6 +114,7 @@ bool Window_win::init(HINSTANCE hInstance) {
} }
SetWindowLongPtr(fHWnd, GWLP_USERDATA, (LONG_PTR)this); SetWindowLongPtr(fHWnd, GWLP_USERDATA, (LONG_PTR)this);
RegisterTouchWindow(fHWnd, 0);
return true; return true;
} }
@ -196,6 +197,7 @@ static uint32_t get_modifiers(UINT message, WPARAM wParam, LPARAM lParam) {
if (wParam & MK_SHIFT) { if (wParam & MK_SHIFT) {
modifiers |= Window::kShift_ModifierKey; modifiers |= Window::kShift_ModifierKey;
} }
break;
} }
return modifiers; return modifiers;
@ -296,6 +298,34 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
get_modifiers(message, wParam, lParam)); get_modifiers(message, wParam, lParam));
break; break;
case WM_TOUCH: {
uint16_t numInputs = LOWORD(wParam);
std::unique_ptr<TOUCHINPUT[]> inputs(new TOUCHINPUT[numInputs]);
if (GetTouchInputInfo((HTOUCHINPUT)lParam, numInputs, inputs.get(),
sizeof(TOUCHINPUT))) {
RECT rect;
GetClientRect(hWnd, &rect);
for (uint16_t i = 0; i < numInputs; ++i) {
TOUCHINPUT ti = inputs[i];
Window::InputState state;
if (ti.dwFlags & TOUCHEVENTF_DOWN) {
state = Window::kDown_InputState;
} else if (ti.dwFlags & TOUCHEVENTF_MOVE) {
state = Window::kMove_InputState;
} else if (ti.dwFlags & TOUCHEVENTF_UP) {
state = Window::kUp_InputState;
} else {
continue;
}
// TOUCHINPUT coordinates are in 100ths of pixels
// Adjust for that, and make them window relative
LONG tx = (ti.x / 100) - rect.left;
LONG ty = (ti.y / 100) - rect.top;
eventHandled = window->onTouch(ti.dwID, state, tx, ty) || eventHandled;
}
}
} break;
default: default:
return DefWindowProc(hWnd, message, wParam, lParam); return DefWindowProc(hWnd, message, wParam, lParam);
} }