widget/windows/nsWinGesture.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /*
michael@0 7 * nsWinGesture - Touch input handling for tablet displays.
michael@0 8 */
michael@0 9
michael@0 10 #include "nscore.h"
michael@0 11 #include "nsWinGesture.h"
michael@0 12 #include "nsUXThemeData.h"
michael@0 13 #include "nsIDOMSimpleGestureEvent.h"
michael@0 14 #include "nsIDOMWheelEvent.h"
michael@0 15 #include "mozilla/Constants.h"
michael@0 16 #include "mozilla/MouseEvents.h"
michael@0 17 #include "mozilla/Preferences.h"
michael@0 18 #include "mozilla/TouchEvents.h"
michael@0 19
michael@0 20 using namespace mozilla;
michael@0 21 using namespace mozilla::widget;
michael@0 22
michael@0 23 #ifdef PR_LOGGING
michael@0 24 extern PRLogModuleInfo* gWindowsLog;
michael@0 25 #endif
michael@0 26
michael@0 27 const wchar_t nsWinGesture::kGestureLibraryName[] = L"user32.dll";
michael@0 28 HMODULE nsWinGesture::sLibraryHandle = nullptr;
michael@0 29 nsWinGesture::GetGestureInfoPtr nsWinGesture::getGestureInfo = nullptr;
michael@0 30 nsWinGesture::CloseGestureInfoHandlePtr nsWinGesture::closeGestureInfoHandle = nullptr;
michael@0 31 nsWinGesture::GetGestureExtraArgsPtr nsWinGesture::getGestureExtraArgs = nullptr;
michael@0 32 nsWinGesture::SetGestureConfigPtr nsWinGesture::setGestureConfig = nullptr;
michael@0 33 nsWinGesture::GetGestureConfigPtr nsWinGesture::getGestureConfig = nullptr;
michael@0 34 nsWinGesture::BeginPanningFeedbackPtr nsWinGesture::beginPanningFeedback = nullptr;
michael@0 35 nsWinGesture::EndPanningFeedbackPtr nsWinGesture::endPanningFeedback = nullptr;
michael@0 36 nsWinGesture::UpdatePanningFeedbackPtr nsWinGesture::updatePanningFeedback = nullptr;
michael@0 37
michael@0 38 nsWinGesture::RegisterTouchWindowPtr nsWinGesture::registerTouchWindow = nullptr;
michael@0 39 nsWinGesture::UnregisterTouchWindowPtr nsWinGesture::unregisterTouchWindow = nullptr;
michael@0 40 nsWinGesture::GetTouchInputInfoPtr nsWinGesture::getTouchInputInfo = nullptr;
michael@0 41 nsWinGesture::CloseTouchInputHandlePtr nsWinGesture::closeTouchInputHandle = nullptr;
michael@0 42
michael@0 43 static bool gEnableSingleFingerPanEvents = false;
michael@0 44
michael@0 45 nsWinGesture::nsWinGesture() :
michael@0 46 mPanActive(false),
michael@0 47 mFeedbackActive(false),
michael@0 48 mXAxisFeedback(false),
michael@0 49 mYAxisFeedback(false),
michael@0 50 mPanInertiaActive(false)
michael@0 51 {
michael@0 52 (void)InitLibrary();
michael@0 53 mPixelScrollOverflow = 0;
michael@0 54 }
michael@0 55
michael@0 56 /* Load and shutdown */
michael@0 57
michael@0 58 bool nsWinGesture::InitLibrary()
michael@0 59 {
michael@0 60 if (getGestureInfo) {
michael@0 61 return true;
michael@0 62 } else if (sLibraryHandle) {
michael@0 63 return false;
michael@0 64 }
michael@0 65
michael@0 66 sLibraryHandle = ::LoadLibraryW(kGestureLibraryName);
michael@0 67 HMODULE hTheme = nsUXThemeData::GetThemeDLL();
michael@0 68
michael@0 69 // gesture interfaces
michael@0 70 if (sLibraryHandle) {
michael@0 71 getGestureInfo = (GetGestureInfoPtr)GetProcAddress(sLibraryHandle, "GetGestureInfo");
michael@0 72 closeGestureInfoHandle = (CloseGestureInfoHandlePtr)GetProcAddress(sLibraryHandle, "CloseGestureInfoHandle");
michael@0 73 getGestureExtraArgs = (GetGestureExtraArgsPtr)GetProcAddress(sLibraryHandle, "GetGestureExtraArgs");
michael@0 74 setGestureConfig = (SetGestureConfigPtr)GetProcAddress(sLibraryHandle, "SetGestureConfig");
michael@0 75 getGestureConfig = (GetGestureConfigPtr)GetProcAddress(sLibraryHandle, "GetGestureConfig");
michael@0 76 registerTouchWindow = (RegisterTouchWindowPtr)GetProcAddress(sLibraryHandle, "RegisterTouchWindow");
michael@0 77 unregisterTouchWindow = (UnregisterTouchWindowPtr)GetProcAddress(sLibraryHandle, "UnregisterTouchWindow");
michael@0 78 getTouchInputInfo = (GetTouchInputInfoPtr)GetProcAddress(sLibraryHandle, "GetTouchInputInfo");
michael@0 79 closeTouchInputHandle = (CloseTouchInputHandlePtr)GetProcAddress(sLibraryHandle, "CloseTouchInputHandle");
michael@0 80 }
michael@0 81
michael@0 82 if (!getGestureInfo || !closeGestureInfoHandle || !getGestureExtraArgs ||
michael@0 83 !setGestureConfig || !getGestureConfig) {
michael@0 84 getGestureInfo = nullptr;
michael@0 85 closeGestureInfoHandle = nullptr;
michael@0 86 getGestureExtraArgs = nullptr;
michael@0 87 setGestureConfig = nullptr;
michael@0 88 getGestureConfig = nullptr;
michael@0 89 return false;
michael@0 90 }
michael@0 91
michael@0 92 if (!registerTouchWindow || !unregisterTouchWindow || !getTouchInputInfo || !closeTouchInputHandle) {
michael@0 93 registerTouchWindow = nullptr;
michael@0 94 unregisterTouchWindow = nullptr;
michael@0 95 getTouchInputInfo = nullptr;
michael@0 96 closeTouchInputHandle = nullptr;
michael@0 97 }
michael@0 98
michael@0 99 // panning feedback interfaces
michael@0 100 if (hTheme) {
michael@0 101 beginPanningFeedback = (BeginPanningFeedbackPtr)GetProcAddress(hTheme, "BeginPanningFeedback");
michael@0 102 endPanningFeedback = (EndPanningFeedbackPtr)GetProcAddress(hTheme, "EndPanningFeedback");
michael@0 103 updatePanningFeedback = (UpdatePanningFeedbackPtr)GetProcAddress(hTheme, "UpdatePanningFeedback");
michael@0 104 }
michael@0 105
michael@0 106 if (!beginPanningFeedback || !endPanningFeedback || !updatePanningFeedback) {
michael@0 107 beginPanningFeedback = nullptr;
michael@0 108 endPanningFeedback = nullptr;
michael@0 109 updatePanningFeedback = nullptr;
michael@0 110 }
michael@0 111
michael@0 112 // Check to see if we want single finger gesture input. Only do this once
michael@0 113 // for the app so we don't have to look it up on every window create.
michael@0 114 gEnableSingleFingerPanEvents =
michael@0 115 Preferences::GetBool("gestures.enable_single_finger_input", false);
michael@0 116
michael@0 117 return true;
michael@0 118 }
michael@0 119
michael@0 120 #define GCOUNT 5
michael@0 121
michael@0 122 bool nsWinGesture::SetWinGestureSupport(HWND hWnd,
michael@0 123 WidgetGestureNotifyEvent::ePanDirection aDirection)
michael@0 124 {
michael@0 125 if (!getGestureInfo)
michael@0 126 return false;
michael@0 127
michael@0 128 GESTURECONFIG config[GCOUNT];
michael@0 129
michael@0 130 memset(&config, 0, sizeof(config));
michael@0 131
michael@0 132 config[0].dwID = GID_ZOOM;
michael@0 133 config[0].dwWant = GC_ZOOM;
michael@0 134 config[0].dwBlock = 0;
michael@0 135
michael@0 136 config[1].dwID = GID_ROTATE;
michael@0 137 config[1].dwWant = GC_ROTATE;
michael@0 138 config[1].dwBlock = 0;
michael@0 139
michael@0 140 config[2].dwID = GID_PAN;
michael@0 141 config[2].dwWant = GC_PAN|GC_PAN_WITH_INERTIA|
michael@0 142 GC_PAN_WITH_GUTTER;
michael@0 143 config[2].dwBlock = GC_PAN_WITH_SINGLE_FINGER_VERTICALLY|
michael@0 144 GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
michael@0 145
michael@0 146 if (gEnableSingleFingerPanEvents) {
michael@0 147
michael@0 148 if (aDirection == WidgetGestureNotifyEvent::ePanVertical ||
michael@0 149 aDirection == WidgetGestureNotifyEvent::ePanBoth)
michael@0 150 {
michael@0 151 config[2].dwWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
michael@0 152 config[2].dwBlock -= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
michael@0 153 }
michael@0 154
michael@0 155 if (aDirection == WidgetGestureNotifyEvent::ePanHorizontal ||
michael@0 156 aDirection == WidgetGestureNotifyEvent::ePanBoth)
michael@0 157 {
michael@0 158 config[2].dwWant |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
michael@0 159 config[2].dwBlock -= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
michael@0 160 }
michael@0 161
michael@0 162 }
michael@0 163
michael@0 164 config[3].dwWant = GC_TWOFINGERTAP;
michael@0 165 config[3].dwID = GID_TWOFINGERTAP;
michael@0 166 config[3].dwBlock = 0;
michael@0 167
michael@0 168 config[4].dwWant = GC_PRESSANDTAP;
michael@0 169 config[4].dwID = GID_PRESSANDTAP;
michael@0 170 config[4].dwBlock = 0;
michael@0 171
michael@0 172 return SetGestureConfig(hWnd, GCOUNT, (PGESTURECONFIG)&config);
michael@0 173 }
michael@0 174
michael@0 175 /* Helpers */
michael@0 176
michael@0 177 bool nsWinGesture::IsAvailable()
michael@0 178 {
michael@0 179 return getGestureInfo != nullptr;
michael@0 180 }
michael@0 181
michael@0 182 bool nsWinGesture::RegisterTouchWindow(HWND hWnd)
michael@0 183 {
michael@0 184 if (!registerTouchWindow)
michael@0 185 return false;
michael@0 186
michael@0 187 return registerTouchWindow(hWnd, TWF_WANTPALM);
michael@0 188 }
michael@0 189
michael@0 190 bool nsWinGesture::UnregisterTouchWindow(HWND hWnd)
michael@0 191 {
michael@0 192 if (!unregisterTouchWindow)
michael@0 193 return false;
michael@0 194
michael@0 195 return unregisterTouchWindow(hWnd);
michael@0 196 }
michael@0 197
michael@0 198 bool nsWinGesture::GetTouchInputInfo(HTOUCHINPUT hTouchInput, uint32_t cInputs, PTOUCHINPUT pInputs)
michael@0 199 {
michael@0 200 if (!getTouchInputInfo)
michael@0 201 return false;
michael@0 202
michael@0 203 return getTouchInputInfo(hTouchInput, cInputs, pInputs, sizeof(TOUCHINPUT));
michael@0 204 }
michael@0 205
michael@0 206 bool nsWinGesture::CloseTouchInputHandle(HTOUCHINPUT hTouchInput)
michael@0 207 {
michael@0 208 if (!closeTouchInputHandle)
michael@0 209 return false;
michael@0 210
michael@0 211 return closeTouchInputHandle(hTouchInput);
michael@0 212 }
michael@0 213
michael@0 214 bool nsWinGesture::GetGestureInfo(HGESTUREINFO hGestureInfo, PGESTUREINFO pGestureInfo)
michael@0 215 {
michael@0 216 if (!getGestureInfo || !hGestureInfo || !pGestureInfo)
michael@0 217 return false;
michael@0 218
michael@0 219 ZeroMemory(pGestureInfo, sizeof(GESTUREINFO));
michael@0 220 pGestureInfo->cbSize = sizeof(GESTUREINFO);
michael@0 221
michael@0 222 return getGestureInfo(hGestureInfo, pGestureInfo);
michael@0 223 }
michael@0 224
michael@0 225 bool nsWinGesture::CloseGestureInfoHandle(HGESTUREINFO hGestureInfo)
michael@0 226 {
michael@0 227 if (!getGestureInfo || !hGestureInfo)
michael@0 228 return false;
michael@0 229
michael@0 230 return closeGestureInfoHandle(hGestureInfo);
michael@0 231 }
michael@0 232
michael@0 233 bool nsWinGesture::GetGestureExtraArgs(HGESTUREINFO hGestureInfo, UINT cbExtraArgs, PBYTE pExtraArgs)
michael@0 234 {
michael@0 235 if (!getGestureInfo || !hGestureInfo || !pExtraArgs)
michael@0 236 return false;
michael@0 237
michael@0 238 return getGestureExtraArgs(hGestureInfo, cbExtraArgs, pExtraArgs);
michael@0 239 }
michael@0 240
michael@0 241 bool nsWinGesture::SetGestureConfig(HWND hWnd, UINT cIDs, PGESTURECONFIG pGestureConfig)
michael@0 242 {
michael@0 243 if (!getGestureInfo || !pGestureConfig)
michael@0 244 return false;
michael@0 245
michael@0 246 return setGestureConfig(hWnd, 0, cIDs, pGestureConfig, sizeof(GESTURECONFIG));
michael@0 247 }
michael@0 248
michael@0 249 bool nsWinGesture::GetGestureConfig(HWND hWnd, DWORD dwFlags, PUINT pcIDs, PGESTURECONFIG pGestureConfig)
michael@0 250 {
michael@0 251 if (!getGestureInfo || !pGestureConfig)
michael@0 252 return false;
michael@0 253
michael@0 254 return getGestureConfig(hWnd, 0, dwFlags, pcIDs, pGestureConfig, sizeof(GESTURECONFIG));
michael@0 255 }
michael@0 256
michael@0 257 bool nsWinGesture::BeginPanningFeedback(HWND hWnd)
michael@0 258 {
michael@0 259 if (!beginPanningFeedback)
michael@0 260 return false;
michael@0 261
michael@0 262 return beginPanningFeedback(hWnd);
michael@0 263 }
michael@0 264
michael@0 265 bool nsWinGesture::EndPanningFeedback(HWND hWnd)
michael@0 266 {
michael@0 267 if (!beginPanningFeedback)
michael@0 268 return false;
michael@0 269
michael@0 270 return endPanningFeedback(hWnd, TRUE);
michael@0 271 }
michael@0 272
michael@0 273 bool nsWinGesture::UpdatePanningFeedback(HWND hWnd, LONG offsetX, LONG offsetY, BOOL fInInertia)
michael@0 274 {
michael@0 275 if (!beginPanningFeedback)
michael@0 276 return false;
michael@0 277
michael@0 278 return updatePanningFeedback(hWnd, offsetX, offsetY, fInInertia);
michael@0 279 }
michael@0 280
michael@0 281 bool nsWinGesture::IsPanEvent(LPARAM lParam)
michael@0 282 {
michael@0 283 GESTUREINFO gi;
michael@0 284
michael@0 285 ZeroMemory(&gi,sizeof(GESTUREINFO));
michael@0 286 gi.cbSize = sizeof(GESTUREINFO);
michael@0 287
michael@0 288 BOOL result = GetGestureInfo((HGESTUREINFO)lParam, &gi);
michael@0 289 if (!result)
michael@0 290 return false;
michael@0 291
michael@0 292 if (gi.dwID == GID_PAN)
michael@0 293 return true;
michael@0 294
michael@0 295 return false;
michael@0 296 }
michael@0 297
michael@0 298 /* Gesture event processing */
michael@0 299
michael@0 300 bool
michael@0 301 nsWinGesture::ProcessGestureMessage(HWND hWnd, WPARAM wParam, LPARAM lParam,
michael@0 302 WidgetSimpleGestureEvent& evt)
michael@0 303 {
michael@0 304 GESTUREINFO gi;
michael@0 305
michael@0 306 ZeroMemory(&gi,sizeof(GESTUREINFO));
michael@0 307 gi.cbSize = sizeof(GESTUREINFO);
michael@0 308
michael@0 309 BOOL result = GetGestureInfo((HGESTUREINFO)lParam, &gi);
michael@0 310 if (!result)
michael@0 311 return false;
michael@0 312
michael@0 313 // The coordinates of this event
michael@0 314 nsPointWin coord;
michael@0 315 coord = gi.ptsLocation;
michael@0 316 coord.ScreenToClient(hWnd);
michael@0 317
michael@0 318 evt.refPoint.x = coord.x;
michael@0 319 evt.refPoint.y = coord.y;
michael@0 320
michael@0 321 // Multiple gesture can occur at the same time so gesture state
michael@0 322 // info can't be shared.
michael@0 323 switch(gi.dwID)
michael@0 324 {
michael@0 325 case GID_BEGIN:
michael@0 326 case GID_END:
michael@0 327 // These should always fall through to DefWndProc
michael@0 328 return false;
michael@0 329 break;
michael@0 330
michael@0 331 case GID_ZOOM:
michael@0 332 {
michael@0 333 if (gi.dwFlags & GF_BEGIN) {
michael@0 334 // Send a zoom start event
michael@0 335
michael@0 336 // The low 32 bits are the distance in pixels.
michael@0 337 mZoomIntermediate = (float)gi.ullArguments;
michael@0 338
michael@0 339 evt.message = NS_SIMPLE_GESTURE_MAGNIFY_START;
michael@0 340 evt.delta = 0.0;
michael@0 341 }
michael@0 342 else if (gi.dwFlags & GF_END) {
michael@0 343 // Send a zoom end event, the delta is the change
michael@0 344 // in touch points.
michael@0 345 evt.message = NS_SIMPLE_GESTURE_MAGNIFY;
michael@0 346 // (positive for a "zoom in")
michael@0 347 evt.delta = -1.0 * (mZoomIntermediate - (float)gi.ullArguments);
michael@0 348 mZoomIntermediate = (float)gi.ullArguments;
michael@0 349 }
michael@0 350 else {
michael@0 351 // Send a zoom intermediate event, the delta is the change
michael@0 352 // in touch points.
michael@0 353 evt.message = NS_SIMPLE_GESTURE_MAGNIFY_UPDATE;
michael@0 354 // (positive for a "zoom in")
michael@0 355 evt.delta = -1.0 * (mZoomIntermediate - (float)gi.ullArguments);
michael@0 356 mZoomIntermediate = (float)gi.ullArguments;
michael@0 357 }
michael@0 358 }
michael@0 359 break;
michael@0 360
michael@0 361 case GID_ROTATE:
michael@0 362 {
michael@0 363 // Send a rotate start event
michael@0 364 double radians = 0.0;
michael@0 365
michael@0 366 // On GF_BEGIN, ullArguments contains the absolute rotation at the
michael@0 367 // start of the gesture. In later events it contains the offset from
michael@0 368 // the start angle.
michael@0 369 if (gi.ullArguments != 0)
michael@0 370 radians = GID_ROTATE_ANGLE_FROM_ARGUMENT(gi.ullArguments);
michael@0 371
michael@0 372 double degrees = -1 * radians * (180/M_PI);
michael@0 373
michael@0 374 if (gi.dwFlags & GF_BEGIN) {
michael@0 375 // At some point we should pass the initial angle in
michael@0 376 // along with delta. It's useful.
michael@0 377 degrees = mRotateIntermediate = 0.0;
michael@0 378 }
michael@0 379
michael@0 380 evt.direction = 0;
michael@0 381 evt.delta = degrees - mRotateIntermediate;
michael@0 382 mRotateIntermediate = degrees;
michael@0 383
michael@0 384 if (evt.delta > 0)
michael@0 385 evt.direction = nsIDOMSimpleGestureEvent::ROTATION_COUNTERCLOCKWISE;
michael@0 386 else if (evt.delta < 0)
michael@0 387 evt.direction = nsIDOMSimpleGestureEvent::ROTATION_CLOCKWISE;
michael@0 388
michael@0 389 if (gi.dwFlags & GF_BEGIN)
michael@0 390 evt.message = NS_SIMPLE_GESTURE_ROTATE_START;
michael@0 391 else if (gi.dwFlags & GF_END)
michael@0 392 evt.message = NS_SIMPLE_GESTURE_ROTATE;
michael@0 393 else
michael@0 394 evt.message = NS_SIMPLE_GESTURE_ROTATE_UPDATE;
michael@0 395 }
michael@0 396 break;
michael@0 397
michael@0 398 case GID_TWOFINGERTAP:
michael@0 399 {
michael@0 400 // Normally maps to "restore" from whatever you may have recently changed. A simple
michael@0 401 // double click.
michael@0 402 evt.message = NS_SIMPLE_GESTURE_TAP;
michael@0 403 evt.clickCount = 1;
michael@0 404 }
michael@0 405 break;
michael@0 406
michael@0 407 case GID_PRESSANDTAP:
michael@0 408 {
michael@0 409 // Two finger right click. Defaults to right click if it falls through.
michael@0 410 evt.message = NS_SIMPLE_GESTURE_PRESSTAP;
michael@0 411 evt.clickCount = 1;
michael@0 412 }
michael@0 413 break;
michael@0 414 }
michael@0 415
michael@0 416 return true;
michael@0 417 }
michael@0 418
michael@0 419 bool
michael@0 420 nsWinGesture::ProcessPanMessage(HWND hWnd, WPARAM wParam, LPARAM lParam)
michael@0 421 {
michael@0 422 GESTUREINFO gi;
michael@0 423
michael@0 424 ZeroMemory(&gi,sizeof(GESTUREINFO));
michael@0 425 gi.cbSize = sizeof(GESTUREINFO);
michael@0 426
michael@0 427 BOOL result = GetGestureInfo((HGESTUREINFO)lParam, &gi);
michael@0 428 if (!result)
michael@0 429 return false;
michael@0 430
michael@0 431 // The coordinates of this event
michael@0 432 nsPointWin coord;
michael@0 433 coord = mPanRefPoint = gi.ptsLocation;
michael@0 434 // We want screen coordinates in our local offsets as client coordinates will change
michael@0 435 // when feedback is taking place. Gui events though require client coordinates.
michael@0 436 mPanRefPoint.ScreenToClient(hWnd);
michael@0 437
michael@0 438 switch(gi.dwID)
michael@0 439 {
michael@0 440 case GID_BEGIN:
michael@0 441 case GID_END:
michael@0 442 // These should always fall through to DefWndProc
michael@0 443 return false;
michael@0 444 break;
michael@0 445
michael@0 446 // Setup pixel scroll events for both axis
michael@0 447 case GID_PAN:
michael@0 448 {
michael@0 449 if (gi.dwFlags & GF_BEGIN) {
michael@0 450 mPanIntermediate = coord;
michael@0 451 mPixelScrollDelta = 0;
michael@0 452 mPanActive = true;
michael@0 453 mPanInertiaActive = false;
michael@0 454 }
michael@0 455 else {
michael@0 456
michael@0 457 #ifdef DBG_jimm
michael@0 458 int32_t deltaX = mPanIntermediate.x - coord.x;
michael@0 459 int32_t deltaY = mPanIntermediate.y - coord.y;
michael@0 460 PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
michael@0 461 ("coordX=%d coordY=%d deltaX=%d deltaY=%d x:%d y:%d\n", coord.x,
michael@0 462 coord.y, deltaX, deltaY, mXAxisFeedback, mYAxisFeedback));
michael@0 463 #endif
michael@0 464
michael@0 465 mPixelScrollDelta.x = mPanIntermediate.x - coord.x;
michael@0 466 mPixelScrollDelta.y = mPanIntermediate.y - coord.y;
michael@0 467 mPanIntermediate = coord;
michael@0 468
michael@0 469 if (gi.dwFlags & GF_INERTIA)
michael@0 470 mPanInertiaActive = true;
michael@0 471
michael@0 472 if (gi.dwFlags & GF_END) {
michael@0 473 mPanActive = false;
michael@0 474 mPanInertiaActive = false;
michael@0 475 PanFeedbackFinalize(hWnd, true);
michael@0 476 }
michael@0 477 }
michael@0 478 }
michael@0 479 break;
michael@0 480 }
michael@0 481 return true;
michael@0 482 }
michael@0 483
michael@0 484 inline bool TestTransition(int32_t a, int32_t b)
michael@0 485 {
michael@0 486 // If a is zero, overflow is zero, implying the cursor has moved back to the start position.
michael@0 487 // If b is zero, cached overscroll is zero, implying feedback just begun.
michael@0 488 if (a == 0 || b == 0) return true;
michael@0 489 // Test for different signs.
michael@0 490 return (a < 0) == (b < 0);
michael@0 491 }
michael@0 492
michael@0 493 void
michael@0 494 nsWinGesture::UpdatePanFeedbackX(HWND hWnd, int32_t scrollOverflow, bool& endFeedback)
michael@0 495 {
michael@0 496 // If scroll overflow was returned indicating we panned past the bounds of
michael@0 497 // the scrollable view port, start feeback.
michael@0 498 if (scrollOverflow != 0) {
michael@0 499 if (!mFeedbackActive) {
michael@0 500 BeginPanningFeedback(hWnd);
michael@0 501 mFeedbackActive = true;
michael@0 502 }
michael@0 503 endFeedback = false;
michael@0 504 mXAxisFeedback = true;
michael@0 505 return;
michael@0 506 }
michael@0 507
michael@0 508 if (mXAxisFeedback) {
michael@0 509 int32_t newOverflow = mPixelScrollOverflow.x - mPixelScrollDelta.x;
michael@0 510
michael@0 511 // Detect a reverse transition past the starting drag point. This tells us the user
michael@0 512 // has panned all the way back so we can stop providing feedback for this axis.
michael@0 513 if (!TestTransition(newOverflow, mPixelScrollOverflow.x) || newOverflow == 0)
michael@0 514 return;
michael@0 515
michael@0 516 // Cache the total over scroll in pixels.
michael@0 517 mPixelScrollOverflow.x = newOverflow;
michael@0 518 endFeedback = false;
michael@0 519 }
michael@0 520 }
michael@0 521
michael@0 522 void
michael@0 523 nsWinGesture::UpdatePanFeedbackY(HWND hWnd, int32_t scrollOverflow, bool& endFeedback)
michael@0 524 {
michael@0 525 // If scroll overflow was returned indicating we panned past the bounds of
michael@0 526 // the scrollable view port, start feeback.
michael@0 527 if (scrollOverflow != 0) {
michael@0 528 if (!mFeedbackActive) {
michael@0 529 BeginPanningFeedback(hWnd);
michael@0 530 mFeedbackActive = true;
michael@0 531 }
michael@0 532 endFeedback = false;
michael@0 533 mYAxisFeedback = true;
michael@0 534 return;
michael@0 535 }
michael@0 536
michael@0 537 if (mYAxisFeedback) {
michael@0 538 int32_t newOverflow = mPixelScrollOverflow.y - mPixelScrollDelta.y;
michael@0 539
michael@0 540 // Detect a reverse transition past the starting drag point. This tells us the user
michael@0 541 // has panned all the way back so we can stop providing feedback for this axis.
michael@0 542 if (!TestTransition(newOverflow, mPixelScrollOverflow.y) || newOverflow == 0)
michael@0 543 return;
michael@0 544
michael@0 545 // Cache the total over scroll in pixels.
michael@0 546 mPixelScrollOverflow.y = newOverflow;
michael@0 547 endFeedback = false;
michael@0 548 }
michael@0 549 }
michael@0 550
michael@0 551 void
michael@0 552 nsWinGesture::PanFeedbackFinalize(HWND hWnd, bool endFeedback)
michael@0 553 {
michael@0 554 if (!mFeedbackActive)
michael@0 555 return;
michael@0 556
michael@0 557 if (endFeedback) {
michael@0 558 mFeedbackActive = false;
michael@0 559 mXAxisFeedback = false;
michael@0 560 mYAxisFeedback = false;
michael@0 561 mPixelScrollOverflow = 0;
michael@0 562 EndPanningFeedback(hWnd);
michael@0 563 return;
michael@0 564 }
michael@0 565
michael@0 566 UpdatePanningFeedback(hWnd, mPixelScrollOverflow.x, mPixelScrollOverflow.y, mPanInertiaActive);
michael@0 567 }
michael@0 568
michael@0 569 bool
michael@0 570 nsWinGesture::PanDeltaToPixelScroll(WidgetWheelEvent& aWheelEvent)
michael@0 571 {
michael@0 572 aWheelEvent.deltaX = aWheelEvent.deltaY = aWheelEvent.deltaZ = 0.0;
michael@0 573 aWheelEvent.lineOrPageDeltaX = aWheelEvent.lineOrPageDeltaY = 0;
michael@0 574
michael@0 575 aWheelEvent.refPoint.x = mPanRefPoint.x;
michael@0 576 aWheelEvent.refPoint.y = mPanRefPoint.y;
michael@0 577 aWheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_PIXEL;
michael@0 578 aWheelEvent.scrollType = WidgetWheelEvent::SCROLL_SYNCHRONOUSLY;
michael@0 579 aWheelEvent.isPixelOnlyDevice = true;
michael@0 580
michael@0 581 aWheelEvent.overflowDeltaX = 0.0;
michael@0 582 aWheelEvent.overflowDeltaY = 0.0;
michael@0 583
michael@0 584 // Don't scroll the view if we are currently at a bounds, or, if we are
michael@0 585 // panning back from a max feedback position. This keeps the original drag point
michael@0 586 // constant.
michael@0 587 if (!mXAxisFeedback) {
michael@0 588 aWheelEvent.deltaX = mPixelScrollDelta.x;
michael@0 589 }
michael@0 590 if (!mYAxisFeedback) {
michael@0 591 aWheelEvent.deltaY = mPixelScrollDelta.y;
michael@0 592 }
michael@0 593
michael@0 594 return (aWheelEvent.deltaX != 0 || aWheelEvent.deltaY != 0);
michael@0 595 }

mercurial