Thu, 15 Jan 2015 15:59:08 +0100
Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set ts=2 et sw=2 tw=80: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 5 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "mozilla/DebugOnly.h" |
michael@0 | 8 | |
michael@0 | 9 | #ifdef MOZ_LOGGING |
michael@0 | 10 | #define FORCE_PR_LOG /* Allow logging in the release build */ |
michael@0 | 11 | #endif // MOZ_LOGGING |
michael@0 | 12 | #include "prlog.h" |
michael@0 | 13 | |
michael@0 | 14 | #include "WinMouseScrollHandler.h" |
michael@0 | 15 | #include "nsWindow.h" |
michael@0 | 16 | #include "nsWindowDefs.h" |
michael@0 | 17 | #include "KeyboardLayout.h" |
michael@0 | 18 | #include "WinUtils.h" |
michael@0 | 19 | #include "nsGkAtoms.h" |
michael@0 | 20 | #include "nsIDOMWindowUtils.h" |
michael@0 | 21 | #include "nsIDOMWheelEvent.h" |
michael@0 | 22 | |
michael@0 | 23 | #include "mozilla/MiscEvents.h" |
michael@0 | 24 | #include "mozilla/MouseEvents.h" |
michael@0 | 25 | #include "mozilla/Preferences.h" |
michael@0 | 26 | #include "mozilla/WindowsVersion.h" |
michael@0 | 27 | |
michael@0 | 28 | #include <psapi.h> |
michael@0 | 29 | |
michael@0 | 30 | namespace mozilla { |
michael@0 | 31 | namespace widget { |
michael@0 | 32 | |
michael@0 | 33 | #ifdef PR_LOGGING |
michael@0 | 34 | PRLogModuleInfo* gMouseScrollLog = nullptr; |
michael@0 | 35 | |
michael@0 | 36 | static const char* GetBoolName(bool aBool) |
michael@0 | 37 | { |
michael@0 | 38 | return aBool ? "TRUE" : "FALSE"; |
michael@0 | 39 | } |
michael@0 | 40 | |
michael@0 | 41 | static void LogKeyStateImpl() |
michael@0 | 42 | { |
michael@0 | 43 | if (!PR_LOG_TEST(gMouseScrollLog, PR_LOG_DEBUG)) { |
michael@0 | 44 | return; |
michael@0 | 45 | } |
michael@0 | 46 | BYTE keyboardState[256]; |
michael@0 | 47 | if (::GetKeyboardState(keyboardState)) { |
michael@0 | 48 | for (size_t i = 0; i < ArrayLength(keyboardState); i++) { |
michael@0 | 49 | if (keyboardState[i]) { |
michael@0 | 50 | PR_LOG(gMouseScrollLog, PR_LOG_DEBUG, |
michael@0 | 51 | (" Current key state: keyboardState[0x%02X]=0x%02X (%s)", |
michael@0 | 52 | i, keyboardState[i], |
michael@0 | 53 | ((keyboardState[i] & 0x81) == 0x81) ? "Pressed and Toggled" : |
michael@0 | 54 | (keyboardState[i] & 0x80) ? "Pressed" : |
michael@0 | 55 | (keyboardState[i] & 0x01) ? "Toggled" : "Unknown")); |
michael@0 | 56 | } |
michael@0 | 57 | } |
michael@0 | 58 | } else { |
michael@0 | 59 | PR_LOG(gMouseScrollLog, PR_LOG_DEBUG, |
michael@0 | 60 | ("MouseScroll::Device::Elantech::HandleKeyMessage(): Failed to print " |
michael@0 | 61 | "current keyboard state")); |
michael@0 | 62 | } |
michael@0 | 63 | } |
michael@0 | 64 | |
michael@0 | 65 | #define LOG_KEYSTATE() LogKeyStateImpl() |
michael@0 | 66 | #else // PR_LOGGING |
michael@0 | 67 | #define LOG_KEYSTATE() |
michael@0 | 68 | #endif |
michael@0 | 69 | |
michael@0 | 70 | MouseScrollHandler* MouseScrollHandler::sInstance = nullptr; |
michael@0 | 71 | |
michael@0 | 72 | bool MouseScrollHandler::Device::sFakeScrollableWindowNeeded = false; |
michael@0 | 73 | |
michael@0 | 74 | bool MouseScrollHandler::Device::Elantech::sUseSwipeHack = false; |
michael@0 | 75 | bool MouseScrollHandler::Device::Elantech::sUsePinchHack = false; |
michael@0 | 76 | DWORD MouseScrollHandler::Device::Elantech::sZoomUntil = 0; |
michael@0 | 77 | |
michael@0 | 78 | bool MouseScrollHandler::Device::SetPoint::sMightBeUsing = false; |
michael@0 | 79 | |
michael@0 | 80 | // The duration until timeout of events transaction. The value is 1.5 sec, |
michael@0 | 81 | // it's just a magic number, it was suggested by Logitech's engineer, see |
michael@0 | 82 | // bug 605648 comment 90. |
michael@0 | 83 | #define DEFAULT_TIMEOUT_DURATION 1500 |
michael@0 | 84 | |
michael@0 | 85 | /****************************************************************************** |
michael@0 | 86 | * |
michael@0 | 87 | * MouseScrollHandler |
michael@0 | 88 | * |
michael@0 | 89 | ******************************************************************************/ |
michael@0 | 90 | |
michael@0 | 91 | /* static */ |
michael@0 | 92 | POINTS |
michael@0 | 93 | MouseScrollHandler::GetCurrentMessagePos() |
michael@0 | 94 | { |
michael@0 | 95 | if (SynthesizingEvent::IsSynthesizing()) { |
michael@0 | 96 | return sInstance->mSynthesizingEvent->GetCursorPoint(); |
michael@0 | 97 | } |
michael@0 | 98 | DWORD pos = ::GetMessagePos(); |
michael@0 | 99 | return MAKEPOINTS(pos); |
michael@0 | 100 | } |
michael@0 | 101 | |
michael@0 | 102 | // Get rid of the GetMessagePos() API. |
michael@0 | 103 | #define GetMessagePos() |
michael@0 | 104 | |
michael@0 | 105 | /* static */ |
michael@0 | 106 | void |
michael@0 | 107 | MouseScrollHandler::Initialize() |
michael@0 | 108 | { |
michael@0 | 109 | #ifdef PR_LOGGING |
michael@0 | 110 | if (!gMouseScrollLog) { |
michael@0 | 111 | gMouseScrollLog = PR_NewLogModule("MouseScrollHandlerWidgets"); |
michael@0 | 112 | } |
michael@0 | 113 | #endif |
michael@0 | 114 | Device::Init(); |
michael@0 | 115 | } |
michael@0 | 116 | |
michael@0 | 117 | /* static */ |
michael@0 | 118 | void |
michael@0 | 119 | MouseScrollHandler::Shutdown() |
michael@0 | 120 | { |
michael@0 | 121 | delete sInstance; |
michael@0 | 122 | sInstance = nullptr; |
michael@0 | 123 | } |
michael@0 | 124 | |
michael@0 | 125 | /* static */ |
michael@0 | 126 | MouseScrollHandler* |
michael@0 | 127 | MouseScrollHandler::GetInstance() |
michael@0 | 128 | { |
michael@0 | 129 | if (!sInstance) { |
michael@0 | 130 | sInstance = new MouseScrollHandler(); |
michael@0 | 131 | } |
michael@0 | 132 | return sInstance; |
michael@0 | 133 | } |
michael@0 | 134 | |
michael@0 | 135 | MouseScrollHandler::MouseScrollHandler() : |
michael@0 | 136 | mIsWaitingInternalMessage(false), |
michael@0 | 137 | mSynthesizingEvent(nullptr) |
michael@0 | 138 | { |
michael@0 | 139 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 140 | ("MouseScroll: Creating an instance, this=%p, sInstance=%p", |
michael@0 | 141 | this, sInstance)); |
michael@0 | 142 | } |
michael@0 | 143 | |
michael@0 | 144 | MouseScrollHandler::~MouseScrollHandler() |
michael@0 | 145 | { |
michael@0 | 146 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 147 | ("MouseScroll: Destroying an instance, this=%p, sInstance=%p", |
michael@0 | 148 | this, sInstance)); |
michael@0 | 149 | |
michael@0 | 150 | delete mSynthesizingEvent; |
michael@0 | 151 | } |
michael@0 | 152 | |
michael@0 | 153 | /* static */ |
michael@0 | 154 | bool |
michael@0 | 155 | MouseScrollHandler::NeedsMessage(UINT aMsg) |
michael@0 | 156 | { |
michael@0 | 157 | switch (aMsg) { |
michael@0 | 158 | case WM_SETTINGCHANGE: |
michael@0 | 159 | case WM_MOUSEWHEEL: |
michael@0 | 160 | case WM_MOUSEHWHEEL: |
michael@0 | 161 | case WM_HSCROLL: |
michael@0 | 162 | case WM_VSCROLL: |
michael@0 | 163 | case MOZ_WM_MOUSEVWHEEL: |
michael@0 | 164 | case MOZ_WM_MOUSEHWHEEL: |
michael@0 | 165 | case MOZ_WM_HSCROLL: |
michael@0 | 166 | case MOZ_WM_VSCROLL: |
michael@0 | 167 | case WM_KEYDOWN: |
michael@0 | 168 | case WM_KEYUP: |
michael@0 | 169 | return true; |
michael@0 | 170 | } |
michael@0 | 171 | return false; |
michael@0 | 172 | } |
michael@0 | 173 | |
michael@0 | 174 | /* static */ |
michael@0 | 175 | bool |
michael@0 | 176 | MouseScrollHandler::ProcessMessage(nsWindowBase* aWidget, UINT msg, |
michael@0 | 177 | WPARAM wParam, LPARAM lParam, |
michael@0 | 178 | MSGResult& aResult) |
michael@0 | 179 | { |
michael@0 | 180 | Device::Elantech::UpdateZoomUntil(); |
michael@0 | 181 | |
michael@0 | 182 | switch (msg) { |
michael@0 | 183 | case WM_SETTINGCHANGE: |
michael@0 | 184 | if (!sInstance) { |
michael@0 | 185 | return false; |
michael@0 | 186 | } |
michael@0 | 187 | if (wParam == SPI_SETWHEELSCROLLLINES || |
michael@0 | 188 | wParam == SPI_SETWHEELSCROLLCHARS) { |
michael@0 | 189 | sInstance->mSystemSettings.MarkDirty(); |
michael@0 | 190 | } |
michael@0 | 191 | return false; |
michael@0 | 192 | |
michael@0 | 193 | case WM_MOUSEWHEEL: |
michael@0 | 194 | case WM_MOUSEHWHEEL: |
michael@0 | 195 | GetInstance()-> |
michael@0 | 196 | ProcessNativeMouseWheelMessage(aWidget, msg, wParam, lParam); |
michael@0 | 197 | sInstance->mSynthesizingEvent->NotifyNativeMessageHandlingFinished(); |
michael@0 | 198 | // We don't need to call next wndproc for WM_MOUSEWHEEL and |
michael@0 | 199 | // WM_MOUSEHWHEEL. We should consume them always. If the messages |
michael@0 | 200 | // would be handled by our window again, it caused making infinite |
michael@0 | 201 | // message loop. |
michael@0 | 202 | aResult.mConsumed = true; |
michael@0 | 203 | aResult.mResult = (msg != WM_MOUSEHWHEEL); |
michael@0 | 204 | return true; |
michael@0 | 205 | |
michael@0 | 206 | case WM_HSCROLL: |
michael@0 | 207 | case WM_VSCROLL: |
michael@0 | 208 | aResult.mConsumed = |
michael@0 | 209 | GetInstance()->ProcessNativeScrollMessage(aWidget, msg, wParam, lParam); |
michael@0 | 210 | sInstance->mSynthesizingEvent->NotifyNativeMessageHandlingFinished(); |
michael@0 | 211 | aResult.mResult = 0; |
michael@0 | 212 | return true; |
michael@0 | 213 | |
michael@0 | 214 | case MOZ_WM_MOUSEVWHEEL: |
michael@0 | 215 | case MOZ_WM_MOUSEHWHEEL: |
michael@0 | 216 | GetInstance()->HandleMouseWheelMessage(aWidget, msg, wParam, lParam); |
michael@0 | 217 | sInstance->mSynthesizingEvent->NotifyInternalMessageHandlingFinished(); |
michael@0 | 218 | // Doesn't need to call next wndproc for internal wheel message. |
michael@0 | 219 | aResult.mConsumed = true; |
michael@0 | 220 | return true; |
michael@0 | 221 | |
michael@0 | 222 | case MOZ_WM_HSCROLL: |
michael@0 | 223 | case MOZ_WM_VSCROLL: |
michael@0 | 224 | GetInstance()-> |
michael@0 | 225 | HandleScrollMessageAsMouseWheelMessage(aWidget, msg, wParam, lParam); |
michael@0 | 226 | sInstance->mSynthesizingEvent->NotifyInternalMessageHandlingFinished(); |
michael@0 | 227 | // Doesn't need to call next wndproc for internal scroll message. |
michael@0 | 228 | aResult.mConsumed = true; |
michael@0 | 229 | return true; |
michael@0 | 230 | |
michael@0 | 231 | case WM_KEYDOWN: |
michael@0 | 232 | case WM_KEYUP: |
michael@0 | 233 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 234 | ("MouseScroll::ProcessMessage(): aWidget=%p, " |
michael@0 | 235 | "msg=%s(0x%04X), wParam=0x%02X, ::GetMessageTime()=%d", |
michael@0 | 236 | aWidget, msg == WM_KEYDOWN ? "WM_KEYDOWN" : |
michael@0 | 237 | msg == WM_KEYUP ? "WM_KEYUP" : "Unknown", msg, wParam, |
michael@0 | 238 | ::GetMessageTime())); |
michael@0 | 239 | LOG_KEYSTATE(); |
michael@0 | 240 | if (Device::Elantech::HandleKeyMessage(aWidget, msg, wParam)) { |
michael@0 | 241 | aResult.mResult = 0; |
michael@0 | 242 | aResult.mConsumed = true; |
michael@0 | 243 | return true; |
michael@0 | 244 | } |
michael@0 | 245 | return false; |
michael@0 | 246 | |
michael@0 | 247 | default: |
michael@0 | 248 | return false; |
michael@0 | 249 | } |
michael@0 | 250 | } |
michael@0 | 251 | |
michael@0 | 252 | /* static */ |
michael@0 | 253 | nsresult |
michael@0 | 254 | MouseScrollHandler::SynthesizeNativeMouseScrollEvent(nsWindowBase* aWidget, |
michael@0 | 255 | const nsIntPoint& aPoint, |
michael@0 | 256 | uint32_t aNativeMessage, |
michael@0 | 257 | int32_t aDelta, |
michael@0 | 258 | uint32_t aModifierFlags, |
michael@0 | 259 | uint32_t aAdditionalFlags) |
michael@0 | 260 | { |
michael@0 | 261 | bool useFocusedWindow = |
michael@0 | 262 | !(aAdditionalFlags & nsIDOMWindowUtils::MOUSESCROLL_PREFER_WIDGET_AT_POINT); |
michael@0 | 263 | |
michael@0 | 264 | POINT pt; |
michael@0 | 265 | pt.x = aPoint.x; |
michael@0 | 266 | pt.y = aPoint.y; |
michael@0 | 267 | |
michael@0 | 268 | HWND target = useFocusedWindow ? ::WindowFromPoint(pt) : ::GetFocus(); |
michael@0 | 269 | NS_ENSURE_TRUE(target, NS_ERROR_FAILURE); |
michael@0 | 270 | |
michael@0 | 271 | WPARAM wParam = 0; |
michael@0 | 272 | LPARAM lParam = 0; |
michael@0 | 273 | switch (aNativeMessage) { |
michael@0 | 274 | case WM_MOUSEWHEEL: |
michael@0 | 275 | case WM_MOUSEHWHEEL: { |
michael@0 | 276 | lParam = MAKELPARAM(pt.x, pt.y); |
michael@0 | 277 | WORD mod = 0; |
michael@0 | 278 | if (aModifierFlags & (nsIWidget::CTRL_L | nsIWidget::CTRL_R)) { |
michael@0 | 279 | mod |= MK_CONTROL; |
michael@0 | 280 | } |
michael@0 | 281 | if (aModifierFlags & (nsIWidget::SHIFT_L | nsIWidget::SHIFT_R)) { |
michael@0 | 282 | mod |= MK_SHIFT; |
michael@0 | 283 | } |
michael@0 | 284 | wParam = MAKEWPARAM(mod, aDelta); |
michael@0 | 285 | break; |
michael@0 | 286 | } |
michael@0 | 287 | case WM_VSCROLL: |
michael@0 | 288 | case WM_HSCROLL: |
michael@0 | 289 | lParam = (aAdditionalFlags & |
michael@0 | 290 | nsIDOMWindowUtils::MOUSESCROLL_WIN_SCROLL_LPARAM_NOT_NULL) ? |
michael@0 | 291 | reinterpret_cast<LPARAM>(target) : 0; |
michael@0 | 292 | wParam = aDelta; |
michael@0 | 293 | break; |
michael@0 | 294 | default: |
michael@0 | 295 | return NS_ERROR_INVALID_ARG; |
michael@0 | 296 | } |
michael@0 | 297 | |
michael@0 | 298 | // Ensure to make the instance. |
michael@0 | 299 | GetInstance(); |
michael@0 | 300 | |
michael@0 | 301 | BYTE kbdState[256]; |
michael@0 | 302 | memset(kbdState, 0, sizeof(kbdState)); |
michael@0 | 303 | |
michael@0 | 304 | nsAutoTArray<KeyPair,10> keySequence; |
michael@0 | 305 | WinUtils::SetupKeyModifiersSequence(&keySequence, aModifierFlags); |
michael@0 | 306 | |
michael@0 | 307 | for (uint32_t i = 0; i < keySequence.Length(); ++i) { |
michael@0 | 308 | uint8_t key = keySequence[i].mGeneral; |
michael@0 | 309 | uint8_t keySpecific = keySequence[i].mSpecific; |
michael@0 | 310 | kbdState[key] = 0x81; // key is down and toggled on if appropriate |
michael@0 | 311 | if (keySpecific) { |
michael@0 | 312 | kbdState[keySpecific] = 0x81; |
michael@0 | 313 | } |
michael@0 | 314 | } |
michael@0 | 315 | |
michael@0 | 316 | if (!sInstance->mSynthesizingEvent) { |
michael@0 | 317 | sInstance->mSynthesizingEvent = new SynthesizingEvent(); |
michael@0 | 318 | } |
michael@0 | 319 | |
michael@0 | 320 | POINTS pts; |
michael@0 | 321 | pts.x = static_cast<SHORT>(pt.x); |
michael@0 | 322 | pts.y = static_cast<SHORT>(pt.y); |
michael@0 | 323 | return sInstance->mSynthesizingEvent-> |
michael@0 | 324 | Synthesize(pts, target, aNativeMessage, wParam, lParam, kbdState); |
michael@0 | 325 | } |
michael@0 | 326 | |
michael@0 | 327 | /* static */ |
michael@0 | 328 | bool |
michael@0 | 329 | MouseScrollHandler::DispatchEvent(nsWindowBase* aWidget, |
michael@0 | 330 | WidgetGUIEvent& aEvent) |
michael@0 | 331 | { |
michael@0 | 332 | // note, in metrofx, this will always return false for now |
michael@0 | 333 | return aWidget->DispatchScrollEvent(&aEvent); |
michael@0 | 334 | } |
michael@0 | 335 | |
michael@0 | 336 | /* static */ |
michael@0 | 337 | void |
michael@0 | 338 | MouseScrollHandler::InitEvent(nsWindowBase* aWidget, |
michael@0 | 339 | WidgetGUIEvent& aEvent, |
michael@0 | 340 | nsIntPoint* aPoint) |
michael@0 | 341 | { |
michael@0 | 342 | NS_ENSURE_TRUE_VOID(aWidget); |
michael@0 | 343 | nsIntPoint point; |
michael@0 | 344 | if (aPoint) { |
michael@0 | 345 | point = *aPoint; |
michael@0 | 346 | } else { |
michael@0 | 347 | POINTS pts = GetCurrentMessagePos(); |
michael@0 | 348 | POINT pt; |
michael@0 | 349 | pt.x = pts.x; |
michael@0 | 350 | pt.y = pts.y; |
michael@0 | 351 | ::ScreenToClient(aWidget->GetWindowHandle(), &pt); |
michael@0 | 352 | point.x = pt.x; |
michael@0 | 353 | point.y = pt.y; |
michael@0 | 354 | } |
michael@0 | 355 | aWidget->InitEvent(aEvent, &point); |
michael@0 | 356 | } |
michael@0 | 357 | |
michael@0 | 358 | /* static */ |
michael@0 | 359 | ModifierKeyState |
michael@0 | 360 | MouseScrollHandler::GetModifierKeyState(UINT aMessage) |
michael@0 | 361 | { |
michael@0 | 362 | ModifierKeyState result; |
michael@0 | 363 | // Assume the Control key is down if the Elantech touchpad has sent the |
michael@0 | 364 | // mis-ordered WM_KEYDOWN/WM_MOUSEWHEEL messages. (See the comment in |
michael@0 | 365 | // MouseScrollHandler::Device::Elantech::HandleKeyMessage().) |
michael@0 | 366 | if ((aMessage == MOZ_WM_MOUSEVWHEEL || aMessage == WM_MOUSEWHEEL) && |
michael@0 | 367 | !result.IsControl() && Device::Elantech::IsZooming()) { |
michael@0 | 368 | result.Set(MODIFIER_CONTROL); |
michael@0 | 369 | } |
michael@0 | 370 | return result; |
michael@0 | 371 | } |
michael@0 | 372 | |
michael@0 | 373 | POINT |
michael@0 | 374 | MouseScrollHandler::ComputeMessagePos(UINT aMessage, |
michael@0 | 375 | WPARAM aWParam, |
michael@0 | 376 | LPARAM aLParam) |
michael@0 | 377 | { |
michael@0 | 378 | POINT point; |
michael@0 | 379 | if (Device::SetPoint::IsGetMessagePosResponseValid(aMessage, |
michael@0 | 380 | aWParam, aLParam)) { |
michael@0 | 381 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 382 | ("MouseScroll::ComputeMessagePos: Using ::GetCursorPos()")); |
michael@0 | 383 | ::GetCursorPos(&point); |
michael@0 | 384 | } else { |
michael@0 | 385 | POINTS pts = GetCurrentMessagePos(); |
michael@0 | 386 | point.x = pts.x; |
michael@0 | 387 | point.y = pts.y; |
michael@0 | 388 | } |
michael@0 | 389 | return point; |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | void |
michael@0 | 393 | MouseScrollHandler::ProcessNativeMouseWheelMessage(nsWindowBase* aWidget, |
michael@0 | 394 | UINT aMessage, |
michael@0 | 395 | WPARAM aWParam, |
michael@0 | 396 | LPARAM aLParam) |
michael@0 | 397 | { |
michael@0 | 398 | if (SynthesizingEvent::IsSynthesizing()) { |
michael@0 | 399 | mSynthesizingEvent->NativeMessageReceived(aWidget, aMessage, |
michael@0 | 400 | aWParam, aLParam); |
michael@0 | 401 | } |
michael@0 | 402 | |
michael@0 | 403 | POINT point = ComputeMessagePos(aMessage, aWParam, aLParam); |
michael@0 | 404 | |
michael@0 | 405 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 406 | ("MouseScroll::ProcessNativeMouseWheelMessage: aWidget=%p, " |
michael@0 | 407 | "aMessage=%s, wParam=0x%08X, lParam=0x%08X, point: { x=%d, y=%d }", |
michael@0 | 408 | aWidget, aMessage == WM_MOUSEWHEEL ? "WM_MOUSEWHEEL" : |
michael@0 | 409 | aMessage == WM_MOUSEHWHEEL ? "WM_MOUSEHWHEEL" : |
michael@0 | 410 | aMessage == WM_VSCROLL ? "WM_VSCROLL" : "WM_HSCROLL", |
michael@0 | 411 | aWParam, aLParam, point.x, point.y)); |
michael@0 | 412 | LOG_KEYSTATE(); |
michael@0 | 413 | |
michael@0 | 414 | HWND underCursorWnd = ::WindowFromPoint(point); |
michael@0 | 415 | if (!underCursorWnd) { |
michael@0 | 416 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 417 | ("MouseScroll::ProcessNativeMouseWheelMessage: " |
michael@0 | 418 | "No window is not found under the cursor")); |
michael@0 | 419 | return; |
michael@0 | 420 | } |
michael@0 | 421 | |
michael@0 | 422 | if (Device::Elantech::IsPinchHackNeeded() && |
michael@0 | 423 | Device::Elantech::IsHelperWindow(underCursorWnd)) { |
michael@0 | 424 | // The Elantech driver places a window right underneath the cursor |
michael@0 | 425 | // when sending a WM_MOUSEWHEEL event to us as part of a pinch-to-zoom |
michael@0 | 426 | // gesture. We detect that here, and search for our window that would |
michael@0 | 427 | // be beneath the cursor if that window wasn't there. |
michael@0 | 428 | underCursorWnd = WinUtils::FindOurWindowAtPoint(point); |
michael@0 | 429 | if (!underCursorWnd) { |
michael@0 | 430 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 431 | ("MouseScroll::ProcessNativeMouseWheelMessage: " |
michael@0 | 432 | "Our window is not found under the Elantech helper window")); |
michael@0 | 433 | return; |
michael@0 | 434 | } |
michael@0 | 435 | } |
michael@0 | 436 | |
michael@0 | 437 | // Handle most cases first. If the window under mouse cursor is our window |
michael@0 | 438 | // except plugin window (MozillaWindowClass), we should handle the message |
michael@0 | 439 | // on the window. |
michael@0 | 440 | if (WinUtils::IsOurProcessWindow(underCursorWnd)) { |
michael@0 | 441 | nsWindowBase* destWindow = WinUtils::GetNSWindowBasePtr(underCursorWnd); |
michael@0 | 442 | if (!destWindow) { |
michael@0 | 443 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 444 | ("MouseScroll::ProcessNativeMouseWheelMessage: " |
michael@0 | 445 | "Found window under the cursor isn't managed by nsWindow...")); |
michael@0 | 446 | HWND wnd = ::GetParent(underCursorWnd); |
michael@0 | 447 | for (; wnd; wnd = ::GetParent(wnd)) { |
michael@0 | 448 | destWindow = WinUtils::GetNSWindowBasePtr(wnd); |
michael@0 | 449 | if (destWindow) { |
michael@0 | 450 | break; |
michael@0 | 451 | } |
michael@0 | 452 | } |
michael@0 | 453 | if (!wnd) { |
michael@0 | 454 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 455 | ("MouseScroll::ProcessNativeMouseWheelMessage: Our window which is " |
michael@0 | 456 | "managed by nsWindow is not found under the cursor")); |
michael@0 | 457 | return; |
michael@0 | 458 | } |
michael@0 | 459 | } |
michael@0 | 460 | |
michael@0 | 461 | MOZ_ASSERT(destWindow, "destWindow must not be NULL"); |
michael@0 | 462 | |
michael@0 | 463 | // If the found window is our plugin window, it means that the message |
michael@0 | 464 | // has been handled by the plugin but not consumed. We should handle the |
michael@0 | 465 | // message on its parent window. However, note that the DOM event may |
michael@0 | 466 | // cause accessing the plugin. Therefore, we should unlock the plugin |
michael@0 | 467 | // process by using PostMessage(). |
michael@0 | 468 | if (destWindow->WindowType() == eWindowType_plugin) { |
michael@0 | 469 | destWindow = destWindow->GetParentWindowBase(false); |
michael@0 | 470 | if (!destWindow) { |
michael@0 | 471 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 472 | ("MouseScroll::ProcessNativeMouseWheelMessage: " |
michael@0 | 473 | "Our window which is a parent of a plugin window is not found")); |
michael@0 | 474 | return; |
michael@0 | 475 | } |
michael@0 | 476 | } |
michael@0 | 477 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 478 | ("MouseScroll::ProcessNativeMouseWheelMessage: Succeeded, " |
michael@0 | 479 | "Posting internal message to an nsWindow (%p)...", |
michael@0 | 480 | destWindow)); |
michael@0 | 481 | mIsWaitingInternalMessage = true; |
michael@0 | 482 | UINT internalMessage = WinUtils::GetInternalMessage(aMessage); |
michael@0 | 483 | ::PostMessage(destWindow->GetWindowHandle(), internalMessage, |
michael@0 | 484 | aWParam, aLParam); |
michael@0 | 485 | return; |
michael@0 | 486 | } |
michael@0 | 487 | |
michael@0 | 488 | // If the window under cursor is not in our process, it means: |
michael@0 | 489 | // 1. The window may be a plugin window (GeckoPluginWindow or its descendant). |
michael@0 | 490 | // 2. The window may be another application's window. |
michael@0 | 491 | HWND pluginWnd = WinUtils::FindOurProcessWindow(underCursorWnd); |
michael@0 | 492 | if (!pluginWnd) { |
michael@0 | 493 | // If there is no plugin window in ancestors of the window under cursor, |
michael@0 | 494 | // the window is for another applications (case 2). |
michael@0 | 495 | // We don't need to handle this message. |
michael@0 | 496 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 497 | ("MouseScroll::ProcessNativeMouseWheelMessage: " |
michael@0 | 498 | "Our window is not found under the cursor")); |
michael@0 | 499 | return; |
michael@0 | 500 | } |
michael@0 | 501 | |
michael@0 | 502 | // If we're a plugin window (MozillaWindowClass) and cursor in this window, |
michael@0 | 503 | // the message shouldn't go to plugin's wndproc again. So, we should handle |
michael@0 | 504 | // it on parent window. However, note that the DOM event may cause accessing |
michael@0 | 505 | // the plugin. Therefore, we should unlock the plugin process by using |
michael@0 | 506 | // PostMessage(). |
michael@0 | 507 | if (aWidget->WindowType() == eWindowType_plugin && |
michael@0 | 508 | aWidget->GetWindowHandle() == pluginWnd) { |
michael@0 | 509 | nsWindowBase* destWindow = aWidget->GetParentWindowBase(false); |
michael@0 | 510 | if (!destWindow) { |
michael@0 | 511 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 512 | ("MouseScroll::ProcessNativeMouseWheelMessage: Our normal window which " |
michael@0 | 513 | "is a parent of this plugin window is not found")); |
michael@0 | 514 | return; |
michael@0 | 515 | } |
michael@0 | 516 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 517 | ("MouseScroll::ProcessNativeMouseWheelMessage: Succeeded, " |
michael@0 | 518 | "Posting internal message to an nsWindow (%p) which is parent of this " |
michael@0 | 519 | "plugin window...", |
michael@0 | 520 | destWindow)); |
michael@0 | 521 | mIsWaitingInternalMessage = true; |
michael@0 | 522 | UINT internalMessage = WinUtils::GetInternalMessage(aMessage); |
michael@0 | 523 | ::PostMessage(destWindow->GetWindowHandle(), internalMessage, |
michael@0 | 524 | aWParam, aLParam); |
michael@0 | 525 | return; |
michael@0 | 526 | } |
michael@0 | 527 | |
michael@0 | 528 | // If the window is a part of plugin, we should post the message to it. |
michael@0 | 529 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 530 | ("MouseScroll::ProcessNativeMouseWheelMessage: Succeeded, " |
michael@0 | 531 | "Redirecting the message to a window which is a plugin child window")); |
michael@0 | 532 | ::PostMessage(underCursorWnd, aMessage, aWParam, aLParam); |
michael@0 | 533 | } |
michael@0 | 534 | |
michael@0 | 535 | bool |
michael@0 | 536 | MouseScrollHandler::ProcessNativeScrollMessage(nsWindowBase* aWidget, |
michael@0 | 537 | UINT aMessage, |
michael@0 | 538 | WPARAM aWParam, |
michael@0 | 539 | LPARAM aLParam) |
michael@0 | 540 | { |
michael@0 | 541 | if (aLParam || mUserPrefs.IsScrollMessageHandledAsWheelMessage()) { |
michael@0 | 542 | // Scroll message generated by Thinkpad Trackpoint Driver or similar |
michael@0 | 543 | // Treat as a mousewheel message and scroll appropriately |
michael@0 | 544 | ProcessNativeMouseWheelMessage(aWidget, aMessage, aWParam, aLParam); |
michael@0 | 545 | // Always consume the scroll message if we try to emulate mouse wheel |
michael@0 | 546 | // action. |
michael@0 | 547 | return true; |
michael@0 | 548 | } |
michael@0 | 549 | |
michael@0 | 550 | if (SynthesizingEvent::IsSynthesizing()) { |
michael@0 | 551 | mSynthesizingEvent->NativeMessageReceived(aWidget, aMessage, |
michael@0 | 552 | aWParam, aLParam); |
michael@0 | 553 | } |
michael@0 | 554 | |
michael@0 | 555 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 556 | ("MouseScroll::ProcessNativeScrollMessage: aWidget=%p, " |
michael@0 | 557 | "aMessage=%s, wParam=0x%08X, lParam=0x%08X", |
michael@0 | 558 | aWidget, aMessage == WM_VSCROLL ? "WM_VSCROLL" : "WM_HSCROLL", |
michael@0 | 559 | aWParam, aLParam)); |
michael@0 | 560 | |
michael@0 | 561 | // Scroll message generated by external application |
michael@0 | 562 | WidgetContentCommandEvent commandEvent(true, NS_CONTENT_COMMAND_SCROLL, |
michael@0 | 563 | aWidget); |
michael@0 | 564 | |
michael@0 | 565 | commandEvent.mScroll.mIsHorizontal = (aMessage == WM_HSCROLL); |
michael@0 | 566 | |
michael@0 | 567 | switch (LOWORD(aWParam)) { |
michael@0 | 568 | case SB_LINEUP: // SB_LINELEFT |
michael@0 | 569 | commandEvent.mScroll.mUnit = |
michael@0 | 570 | WidgetContentCommandEvent::eCmdScrollUnit_Line; |
michael@0 | 571 | commandEvent.mScroll.mAmount = -1; |
michael@0 | 572 | break; |
michael@0 | 573 | case SB_LINEDOWN: // SB_LINERIGHT |
michael@0 | 574 | commandEvent.mScroll.mUnit = |
michael@0 | 575 | WidgetContentCommandEvent::eCmdScrollUnit_Line; |
michael@0 | 576 | commandEvent.mScroll.mAmount = 1; |
michael@0 | 577 | break; |
michael@0 | 578 | case SB_PAGEUP: // SB_PAGELEFT |
michael@0 | 579 | commandEvent.mScroll.mUnit = |
michael@0 | 580 | WidgetContentCommandEvent::eCmdScrollUnit_Page; |
michael@0 | 581 | commandEvent.mScroll.mAmount = -1; |
michael@0 | 582 | break; |
michael@0 | 583 | case SB_PAGEDOWN: // SB_PAGERIGHT |
michael@0 | 584 | commandEvent.mScroll.mUnit = |
michael@0 | 585 | WidgetContentCommandEvent::eCmdScrollUnit_Page; |
michael@0 | 586 | commandEvent.mScroll.mAmount = 1; |
michael@0 | 587 | break; |
michael@0 | 588 | case SB_TOP: // SB_LEFT |
michael@0 | 589 | commandEvent.mScroll.mUnit = |
michael@0 | 590 | WidgetContentCommandEvent::eCmdScrollUnit_Whole; |
michael@0 | 591 | commandEvent.mScroll.mAmount = -1; |
michael@0 | 592 | break; |
michael@0 | 593 | case SB_BOTTOM: // SB_RIGHT |
michael@0 | 594 | commandEvent.mScroll.mUnit = |
michael@0 | 595 | WidgetContentCommandEvent::eCmdScrollUnit_Whole; |
michael@0 | 596 | commandEvent.mScroll.mAmount = 1; |
michael@0 | 597 | break; |
michael@0 | 598 | default: |
michael@0 | 599 | return false; |
michael@0 | 600 | } |
michael@0 | 601 | // XXX If this is a plugin window, we should dispatch the event from |
michael@0 | 602 | // parent window. |
michael@0 | 603 | DispatchEvent(aWidget, commandEvent); |
michael@0 | 604 | return true; |
michael@0 | 605 | } |
michael@0 | 606 | |
michael@0 | 607 | void |
michael@0 | 608 | MouseScrollHandler::HandleMouseWheelMessage(nsWindowBase* aWidget, |
michael@0 | 609 | UINT aMessage, |
michael@0 | 610 | WPARAM aWParam, |
michael@0 | 611 | LPARAM aLParam) |
michael@0 | 612 | { |
michael@0 | 613 | NS_ABORT_IF_FALSE( |
michael@0 | 614 | (aMessage == MOZ_WM_MOUSEVWHEEL || aMessage == MOZ_WM_MOUSEHWHEEL), |
michael@0 | 615 | "HandleMouseWheelMessage must be called with " |
michael@0 | 616 | "MOZ_WM_MOUSEVWHEEL or MOZ_WM_MOUSEHWHEEL"); |
michael@0 | 617 | |
michael@0 | 618 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 619 | ("MouseScroll::HandleMouseWheelMessage: aWidget=%p, " |
michael@0 | 620 | "aMessage=MOZ_WM_MOUSE%sWHEEL, aWParam=0x%08X, aLParam=0x%08X", |
michael@0 | 621 | aWidget, aMessage == MOZ_WM_MOUSEVWHEEL ? "V" : "H", |
michael@0 | 622 | aWParam, aLParam)); |
michael@0 | 623 | |
michael@0 | 624 | mIsWaitingInternalMessage = false; |
michael@0 | 625 | |
michael@0 | 626 | EventInfo eventInfo(aWidget, WinUtils::GetNativeMessage(aMessage), |
michael@0 | 627 | aWParam, aLParam); |
michael@0 | 628 | if (!eventInfo.CanDispatchWheelEvent()) { |
michael@0 | 629 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 630 | ("MouseScroll::HandleMouseWheelMessage: Cannot dispatch the events")); |
michael@0 | 631 | mLastEventInfo.ResetTransaction(); |
michael@0 | 632 | return; |
michael@0 | 633 | } |
michael@0 | 634 | |
michael@0 | 635 | // Discard the remaining delta if current wheel message and last one are |
michael@0 | 636 | // received by different window or to scroll different direction or |
michael@0 | 637 | // different unit scroll. Furthermore, if the last event was too old. |
michael@0 | 638 | if (!mLastEventInfo.CanContinueTransaction(eventInfo)) { |
michael@0 | 639 | mLastEventInfo.ResetTransaction(); |
michael@0 | 640 | } |
michael@0 | 641 | |
michael@0 | 642 | mLastEventInfo.RecordEvent(eventInfo); |
michael@0 | 643 | |
michael@0 | 644 | ModifierKeyState modKeyState = GetModifierKeyState(aMessage); |
michael@0 | 645 | |
michael@0 | 646 | // Grab the widget, it might be destroyed by a DOM event handler. |
michael@0 | 647 | nsRefPtr<nsWindowBase> kungFuDethGrip(aWidget); |
michael@0 | 648 | |
michael@0 | 649 | WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, aWidget); |
michael@0 | 650 | if (mLastEventInfo.InitWheelEvent(aWidget, wheelEvent, modKeyState)) { |
michael@0 | 651 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 652 | ("MouseScroll::HandleMouseWheelMessage: dispatching " |
michael@0 | 653 | "NS_WHEEL_WHEEL event")); |
michael@0 | 654 | DispatchEvent(aWidget, wheelEvent); |
michael@0 | 655 | if (aWidget->Destroyed()) { |
michael@0 | 656 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 657 | ("MouseScroll::HandleMouseWheelMessage: The window was destroyed " |
michael@0 | 658 | "by NS_WHEEL_WHEEL event")); |
michael@0 | 659 | mLastEventInfo.ResetTransaction(); |
michael@0 | 660 | return; |
michael@0 | 661 | } |
michael@0 | 662 | } |
michael@0 | 663 | #ifdef PR_LOGGING |
michael@0 | 664 | else { |
michael@0 | 665 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 666 | ("MouseScroll::HandleMouseWheelMessage: NS_WHEEL_WHEEL event is not " |
michael@0 | 667 | "dispatched")); |
michael@0 | 668 | } |
michael@0 | 669 | #endif |
michael@0 | 670 | } |
michael@0 | 671 | |
michael@0 | 672 | void |
michael@0 | 673 | MouseScrollHandler::HandleScrollMessageAsMouseWheelMessage(nsWindowBase* aWidget, |
michael@0 | 674 | UINT aMessage, |
michael@0 | 675 | WPARAM aWParam, |
michael@0 | 676 | LPARAM aLParam) |
michael@0 | 677 | { |
michael@0 | 678 | NS_ABORT_IF_FALSE( |
michael@0 | 679 | (aMessage == MOZ_WM_VSCROLL || aMessage == MOZ_WM_HSCROLL), |
michael@0 | 680 | "HandleScrollMessageAsMouseWheelMessage must be called with " |
michael@0 | 681 | "MOZ_WM_VSCROLL or MOZ_WM_HSCROLL"); |
michael@0 | 682 | |
michael@0 | 683 | mIsWaitingInternalMessage = false; |
michael@0 | 684 | |
michael@0 | 685 | ModifierKeyState modKeyState = GetModifierKeyState(aMessage); |
michael@0 | 686 | |
michael@0 | 687 | WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, aWidget); |
michael@0 | 688 | double& delta = |
michael@0 | 689 | (aMessage == MOZ_WM_VSCROLL) ? wheelEvent.deltaY : wheelEvent.deltaX; |
michael@0 | 690 | int32_t& lineOrPageDelta = |
michael@0 | 691 | (aMessage == MOZ_WM_VSCROLL) ? wheelEvent.lineOrPageDeltaY : |
michael@0 | 692 | wheelEvent.lineOrPageDeltaX; |
michael@0 | 693 | |
michael@0 | 694 | delta = 1.0; |
michael@0 | 695 | lineOrPageDelta = 1; |
michael@0 | 696 | |
michael@0 | 697 | switch (LOWORD(aWParam)) { |
michael@0 | 698 | case SB_PAGEUP: |
michael@0 | 699 | delta = -1.0; |
michael@0 | 700 | lineOrPageDelta = -1; |
michael@0 | 701 | case SB_PAGEDOWN: |
michael@0 | 702 | wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_PAGE; |
michael@0 | 703 | break; |
michael@0 | 704 | |
michael@0 | 705 | case SB_LINEUP: |
michael@0 | 706 | delta = -1.0; |
michael@0 | 707 | lineOrPageDelta = -1; |
michael@0 | 708 | case SB_LINEDOWN: |
michael@0 | 709 | wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE; |
michael@0 | 710 | break; |
michael@0 | 711 | |
michael@0 | 712 | default: |
michael@0 | 713 | return; |
michael@0 | 714 | } |
michael@0 | 715 | modKeyState.InitInputEvent(wheelEvent); |
michael@0 | 716 | // XXX Current mouse position may not be same as when the original message |
michael@0 | 717 | // is received. We need to know the actual mouse cursor position when |
michael@0 | 718 | // the original message was received. |
michael@0 | 719 | InitEvent(aWidget, wheelEvent); |
michael@0 | 720 | |
michael@0 | 721 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 722 | ("MouseScroll::HandleScrollMessageAsMouseWheelMessage: aWidget=%p, " |
michael@0 | 723 | "aMessage=MOZ_WM_%sSCROLL, aWParam=0x%08X, aLParam=0x%08X, " |
michael@0 | 724 | "wheelEvent { refPoint: { x: %d, y: %d }, deltaX: %f, deltaY: %f, " |
michael@0 | 725 | "lineOrPageDeltaX: %d, lineOrPageDeltaY: %d, " |
michael@0 | 726 | "isShift: %s, isControl: %s, isAlt: %s, isMeta: %s }", |
michael@0 | 727 | aWidget, (aMessage == MOZ_WM_VSCROLL) ? "V" : "H", aWParam, aLParam, |
michael@0 | 728 | wheelEvent.refPoint.x, wheelEvent.refPoint.y, |
michael@0 | 729 | wheelEvent.deltaX, wheelEvent.deltaY, |
michael@0 | 730 | wheelEvent.lineOrPageDeltaX, wheelEvent.lineOrPageDeltaY, |
michael@0 | 731 | GetBoolName(wheelEvent.IsShift()), |
michael@0 | 732 | GetBoolName(wheelEvent.IsControl()), |
michael@0 | 733 | GetBoolName(wheelEvent.IsAlt()), |
michael@0 | 734 | GetBoolName(wheelEvent.IsMeta()))); |
michael@0 | 735 | |
michael@0 | 736 | DispatchEvent(aWidget, wheelEvent); |
michael@0 | 737 | } |
michael@0 | 738 | |
michael@0 | 739 | /****************************************************************************** |
michael@0 | 740 | * |
michael@0 | 741 | * EventInfo |
michael@0 | 742 | * |
michael@0 | 743 | ******************************************************************************/ |
michael@0 | 744 | |
michael@0 | 745 | MouseScrollHandler::EventInfo::EventInfo(nsWindowBase* aWidget, |
michael@0 | 746 | UINT aMessage, |
michael@0 | 747 | WPARAM aWParam, LPARAM aLParam) |
michael@0 | 748 | { |
michael@0 | 749 | NS_ABORT_IF_FALSE(aMessage == WM_MOUSEWHEEL || aMessage == WM_MOUSEHWHEEL, |
michael@0 | 750 | "EventInfo must be initialized with WM_MOUSEWHEEL or WM_MOUSEHWHEEL"); |
michael@0 | 751 | |
michael@0 | 752 | MouseScrollHandler::GetInstance()->mSystemSettings.Init(); |
michael@0 | 753 | |
michael@0 | 754 | mIsVertical = (aMessage == WM_MOUSEWHEEL); |
michael@0 | 755 | mIsPage = MouseScrollHandler::sInstance-> |
michael@0 | 756 | mSystemSettings.IsPageScroll(mIsVertical); |
michael@0 | 757 | mDelta = (short)HIWORD(aWParam); |
michael@0 | 758 | mWnd = aWidget->GetWindowHandle(); |
michael@0 | 759 | mTimeStamp = TimeStamp::Now(); |
michael@0 | 760 | } |
michael@0 | 761 | |
michael@0 | 762 | bool |
michael@0 | 763 | MouseScrollHandler::EventInfo::CanDispatchWheelEvent() const |
michael@0 | 764 | { |
michael@0 | 765 | if (!GetScrollAmount()) { |
michael@0 | 766 | // XXX I think that we should dispatch mouse wheel events even if the |
michael@0 | 767 | // operation will not scroll because the wheel operation really happened |
michael@0 | 768 | // and web application may want to handle the event for non-scroll action. |
michael@0 | 769 | return false; |
michael@0 | 770 | } |
michael@0 | 771 | |
michael@0 | 772 | return (mDelta != 0); |
michael@0 | 773 | } |
michael@0 | 774 | |
michael@0 | 775 | int32_t |
michael@0 | 776 | MouseScrollHandler::EventInfo::GetScrollAmount() const |
michael@0 | 777 | { |
michael@0 | 778 | if (mIsPage) { |
michael@0 | 779 | return 1; |
michael@0 | 780 | } |
michael@0 | 781 | return MouseScrollHandler::sInstance-> |
michael@0 | 782 | mSystemSettings.GetScrollAmount(mIsVertical); |
michael@0 | 783 | } |
michael@0 | 784 | |
michael@0 | 785 | /****************************************************************************** |
michael@0 | 786 | * |
michael@0 | 787 | * LastEventInfo |
michael@0 | 788 | * |
michael@0 | 789 | ******************************************************************************/ |
michael@0 | 790 | |
michael@0 | 791 | bool |
michael@0 | 792 | MouseScrollHandler::LastEventInfo::CanContinueTransaction( |
michael@0 | 793 | const EventInfo& aNewEvent) |
michael@0 | 794 | { |
michael@0 | 795 | int32_t timeout = MouseScrollHandler::sInstance-> |
michael@0 | 796 | mUserPrefs.GetMouseScrollTransactionTimeout(); |
michael@0 | 797 | return !mWnd || |
michael@0 | 798 | (mWnd == aNewEvent.GetWindowHandle() && |
michael@0 | 799 | IsPositive() == aNewEvent.IsPositive() && |
michael@0 | 800 | mIsVertical == aNewEvent.IsVertical() && |
michael@0 | 801 | mIsPage == aNewEvent.IsPage() && |
michael@0 | 802 | (timeout < 0 || |
michael@0 | 803 | TimeStamp::Now() - mTimeStamp <= |
michael@0 | 804 | TimeDuration::FromMilliseconds(timeout))); |
michael@0 | 805 | } |
michael@0 | 806 | |
michael@0 | 807 | void |
michael@0 | 808 | MouseScrollHandler::LastEventInfo::ResetTransaction() |
michael@0 | 809 | { |
michael@0 | 810 | if (!mWnd) { |
michael@0 | 811 | return; |
michael@0 | 812 | } |
michael@0 | 813 | |
michael@0 | 814 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 815 | ("MouseScroll::LastEventInfo::ResetTransaction()")); |
michael@0 | 816 | |
michael@0 | 817 | mWnd = nullptr; |
michael@0 | 818 | mAccumulatedDelta = 0; |
michael@0 | 819 | } |
michael@0 | 820 | |
michael@0 | 821 | void |
michael@0 | 822 | MouseScrollHandler::LastEventInfo::RecordEvent(const EventInfo& aEvent) |
michael@0 | 823 | { |
michael@0 | 824 | mWnd = aEvent.GetWindowHandle(); |
michael@0 | 825 | mDelta = aEvent.GetNativeDelta(); |
michael@0 | 826 | mIsVertical = aEvent.IsVertical(); |
michael@0 | 827 | mIsPage = aEvent.IsPage(); |
michael@0 | 828 | mTimeStamp = TimeStamp::Now(); |
michael@0 | 829 | } |
michael@0 | 830 | |
michael@0 | 831 | /* static */ |
michael@0 | 832 | int32_t |
michael@0 | 833 | MouseScrollHandler::LastEventInfo::RoundDelta(double aDelta) |
michael@0 | 834 | { |
michael@0 | 835 | return (aDelta >= 0) ? (int32_t)floor(aDelta) : (int32_t)ceil(aDelta); |
michael@0 | 836 | } |
michael@0 | 837 | |
michael@0 | 838 | bool |
michael@0 | 839 | MouseScrollHandler::LastEventInfo::InitWheelEvent( |
michael@0 | 840 | nsWindowBase* aWidget, |
michael@0 | 841 | WidgetWheelEvent& aWheelEvent, |
michael@0 | 842 | const ModifierKeyState& aModKeyState) |
michael@0 | 843 | { |
michael@0 | 844 | MOZ_ASSERT(aWheelEvent.message == NS_WHEEL_WHEEL); |
michael@0 | 845 | |
michael@0 | 846 | // XXX Why don't we use lParam value? We should use lParam value because |
michael@0 | 847 | // our internal message is always posted by original message handler. |
michael@0 | 848 | // So, GetMessagePos() may return different cursor position. |
michael@0 | 849 | InitEvent(aWidget, aWheelEvent); |
michael@0 | 850 | |
michael@0 | 851 | aModKeyState.InitInputEvent(aWheelEvent); |
michael@0 | 852 | |
michael@0 | 853 | // Our positive delta value means to bottom or right. |
michael@0 | 854 | // But positive native delta value means to top or right. |
michael@0 | 855 | // Use orienter for computing our delta value with native delta value. |
michael@0 | 856 | int32_t orienter = mIsVertical ? -1 : 1; |
michael@0 | 857 | |
michael@0 | 858 | aWheelEvent.deltaMode = mIsPage ? nsIDOMWheelEvent::DOM_DELTA_PAGE : |
michael@0 | 859 | nsIDOMWheelEvent::DOM_DELTA_LINE; |
michael@0 | 860 | |
michael@0 | 861 | double& delta = mIsVertical ? aWheelEvent.deltaY : aWheelEvent.deltaX; |
michael@0 | 862 | int32_t& lineOrPageDelta = mIsVertical ? aWheelEvent.lineOrPageDeltaY : |
michael@0 | 863 | aWheelEvent.lineOrPageDeltaX; |
michael@0 | 864 | |
michael@0 | 865 | double nativeDeltaPerUnit = |
michael@0 | 866 | mIsPage ? static_cast<double>(WHEEL_DELTA) : |
michael@0 | 867 | static_cast<double>(WHEEL_DELTA) / GetScrollAmount(); |
michael@0 | 868 | |
michael@0 | 869 | delta = static_cast<double>(mDelta) * orienter / nativeDeltaPerUnit; |
michael@0 | 870 | mAccumulatedDelta += mDelta; |
michael@0 | 871 | lineOrPageDelta = |
michael@0 | 872 | mAccumulatedDelta * orienter / RoundDelta(nativeDeltaPerUnit); |
michael@0 | 873 | mAccumulatedDelta -= |
michael@0 | 874 | lineOrPageDelta * orienter * RoundDelta(nativeDeltaPerUnit); |
michael@0 | 875 | |
michael@0 | 876 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 877 | ("MouseScroll::LastEventInfo::InitWheelEvent: aWidget=%p, " |
michael@0 | 878 | "aWheelEvent { refPoint: { x: %d, y: %d }, deltaX: %f, deltaY: %f, " |
michael@0 | 879 | "lineOrPageDeltaX: %d, lineOrPageDeltaY: %d, " |
michael@0 | 880 | "isShift: %s, isControl: %s, isAlt: %s, isMeta: %s }, " |
michael@0 | 881 | "mAccumulatedDelta: %d", |
michael@0 | 882 | aWidget, aWheelEvent.refPoint.x, aWheelEvent.refPoint.y, |
michael@0 | 883 | aWheelEvent.deltaX, aWheelEvent.deltaY, |
michael@0 | 884 | aWheelEvent.lineOrPageDeltaX, aWheelEvent.lineOrPageDeltaY, |
michael@0 | 885 | GetBoolName(aWheelEvent.IsShift()), |
michael@0 | 886 | GetBoolName(aWheelEvent.IsControl()), |
michael@0 | 887 | GetBoolName(aWheelEvent.IsAlt()), |
michael@0 | 888 | GetBoolName(aWheelEvent.IsMeta()), mAccumulatedDelta)); |
michael@0 | 889 | |
michael@0 | 890 | return (delta != 0); |
michael@0 | 891 | } |
michael@0 | 892 | |
michael@0 | 893 | /****************************************************************************** |
michael@0 | 894 | * |
michael@0 | 895 | * SystemSettings |
michael@0 | 896 | * |
michael@0 | 897 | ******************************************************************************/ |
michael@0 | 898 | |
michael@0 | 899 | void |
michael@0 | 900 | MouseScrollHandler::SystemSettings::Init() |
michael@0 | 901 | { |
michael@0 | 902 | if (mInitialized) { |
michael@0 | 903 | return; |
michael@0 | 904 | } |
michael@0 | 905 | |
michael@0 | 906 | mInitialized = true; |
michael@0 | 907 | |
michael@0 | 908 | MouseScrollHandler::UserPrefs& userPrefs = |
michael@0 | 909 | MouseScrollHandler::sInstance->mUserPrefs; |
michael@0 | 910 | |
michael@0 | 911 | mScrollLines = userPrefs.GetOverriddenVerticalScrollAmout(); |
michael@0 | 912 | if (mScrollLines >= 0) { |
michael@0 | 913 | // overridden by the pref. |
michael@0 | 914 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 915 | ("MouseScroll::SystemSettings::Init(): mScrollLines is overridden by " |
michael@0 | 916 | "the pref: %d", |
michael@0 | 917 | mScrollLines)); |
michael@0 | 918 | } else if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, |
michael@0 | 919 | &mScrollLines, 0)) { |
michael@0 | 920 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 921 | ("MouseScroll::SystemSettings::Init(): ::SystemParametersInfo(" |
michael@0 | 922 | "SPI_GETWHEELSCROLLLINES) failed")); |
michael@0 | 923 | mScrollLines = 3; |
michael@0 | 924 | } |
michael@0 | 925 | |
michael@0 | 926 | if (mScrollLines > WHEEL_DELTA) { |
michael@0 | 927 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 928 | ("MouseScroll::SystemSettings::Init(): the result of " |
michael@0 | 929 | "::SystemParametersInfo(SPI_GETWHEELSCROLLLINES) is too large: %d", |
michael@0 | 930 | mScrollLines)); |
michael@0 | 931 | // sScrollLines usually equals 3 or 0 (for no scrolling) |
michael@0 | 932 | // However, if sScrollLines > WHEEL_DELTA, we assume that |
michael@0 | 933 | // the mouse driver wants a page scroll. The docs state that |
michael@0 | 934 | // sScrollLines should explicitly equal WHEEL_PAGESCROLL, but |
michael@0 | 935 | // since some mouse drivers use an arbitrary large number instead, |
michael@0 | 936 | // we have to handle that as well. |
michael@0 | 937 | mScrollLines = WHEEL_PAGESCROLL; |
michael@0 | 938 | } |
michael@0 | 939 | |
michael@0 | 940 | mScrollChars = userPrefs.GetOverriddenHorizontalScrollAmout(); |
michael@0 | 941 | if (mScrollChars >= 0) { |
michael@0 | 942 | // overridden by the pref. |
michael@0 | 943 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 944 | ("MouseScroll::SystemSettings::Init(): mScrollChars is overridden by " |
michael@0 | 945 | "the pref: %d", |
michael@0 | 946 | mScrollChars)); |
michael@0 | 947 | } else if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, |
michael@0 | 948 | &mScrollChars, 0)) { |
michael@0 | 949 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 950 | ("MouseScroll::SystemSettings::Init(): ::SystemParametersInfo(" |
michael@0 | 951 | "SPI_GETWHEELSCROLLCHARS) failed, %s", |
michael@0 | 952 | IsVistaOrLater() ? |
michael@0 | 953 | "this is unexpected on Vista or later" : |
michael@0 | 954 | "but on XP or earlier, this is not a problem")); |
michael@0 | 955 | mScrollChars = 1; |
michael@0 | 956 | } |
michael@0 | 957 | |
michael@0 | 958 | if (mScrollChars > WHEEL_DELTA) { |
michael@0 | 959 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 960 | ("MouseScroll::SystemSettings::Init(): the result of " |
michael@0 | 961 | "::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS) is too large: %d", |
michael@0 | 962 | mScrollChars)); |
michael@0 | 963 | // See the comments for the case mScrollLines > WHEEL_DELTA. |
michael@0 | 964 | mScrollChars = WHEEL_PAGESCROLL; |
michael@0 | 965 | } |
michael@0 | 966 | |
michael@0 | 967 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 968 | ("MouseScroll::SystemSettings::Init(): initialized, " |
michael@0 | 969 | "mScrollLines=%d, mScrollChars=%d", |
michael@0 | 970 | mScrollLines, mScrollChars)); |
michael@0 | 971 | } |
michael@0 | 972 | |
michael@0 | 973 | void |
michael@0 | 974 | MouseScrollHandler::SystemSettings::MarkDirty() |
michael@0 | 975 | { |
michael@0 | 976 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 977 | ("MouseScrollHandler::SystemSettings::MarkDirty(): " |
michael@0 | 978 | "Marking SystemSettings dirty")); |
michael@0 | 979 | mInitialized = false; |
michael@0 | 980 | // When system settings are changed, we should reset current transaction. |
michael@0 | 981 | MOZ_ASSERT(sInstance, |
michael@0 | 982 | "Must not be called at initializing MouseScrollHandler"); |
michael@0 | 983 | MouseScrollHandler::sInstance->mLastEventInfo.ResetTransaction(); |
michael@0 | 984 | } |
michael@0 | 985 | |
michael@0 | 986 | /****************************************************************************** |
michael@0 | 987 | * |
michael@0 | 988 | * UserPrefs |
michael@0 | 989 | * |
michael@0 | 990 | ******************************************************************************/ |
michael@0 | 991 | |
michael@0 | 992 | MouseScrollHandler::UserPrefs::UserPrefs() : |
michael@0 | 993 | mInitialized(false) |
michael@0 | 994 | { |
michael@0 | 995 | // We need to reset mouse wheel transaction when all of mousewheel related |
michael@0 | 996 | // prefs are changed. |
michael@0 | 997 | DebugOnly<nsresult> rv = |
michael@0 | 998 | Preferences::RegisterCallback(OnChange, "mousewheel.", this); |
michael@0 | 999 | MOZ_ASSERT(NS_SUCCEEDED(rv), |
michael@0 | 1000 | "Failed to register callback for mousewheel."); |
michael@0 | 1001 | } |
michael@0 | 1002 | |
michael@0 | 1003 | MouseScrollHandler::UserPrefs::~UserPrefs() |
michael@0 | 1004 | { |
michael@0 | 1005 | DebugOnly<nsresult> rv = |
michael@0 | 1006 | Preferences::UnregisterCallback(OnChange, "mousewheel.", this); |
michael@0 | 1007 | MOZ_ASSERT(NS_SUCCEEDED(rv), |
michael@0 | 1008 | "Failed to unregister callback for mousewheel."); |
michael@0 | 1009 | } |
michael@0 | 1010 | |
michael@0 | 1011 | void |
michael@0 | 1012 | MouseScrollHandler::UserPrefs::Init() |
michael@0 | 1013 | { |
michael@0 | 1014 | if (mInitialized) { |
michael@0 | 1015 | return; |
michael@0 | 1016 | } |
michael@0 | 1017 | |
michael@0 | 1018 | mInitialized = true; |
michael@0 | 1019 | |
michael@0 | 1020 | mScrollMessageHandledAsWheelMessage = |
michael@0 | 1021 | Preferences::GetBool("mousewheel.emulate_at_wm_scroll", false); |
michael@0 | 1022 | mOverriddenVerticalScrollAmount = |
michael@0 | 1023 | Preferences::GetInt("mousewheel.windows.vertical_amount_override", -1); |
michael@0 | 1024 | mOverriddenHorizontalScrollAmount = |
michael@0 | 1025 | Preferences::GetInt("mousewheel.windows.horizontal_amount_override", -1); |
michael@0 | 1026 | mMouseScrollTransactionTimeout = |
michael@0 | 1027 | Preferences::GetInt("mousewheel.windows.transaction.timeout", |
michael@0 | 1028 | DEFAULT_TIMEOUT_DURATION); |
michael@0 | 1029 | |
michael@0 | 1030 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1031 | ("MouseScroll::UserPrefs::Init(): initialized, " |
michael@0 | 1032 | "mScrollMessageHandledAsWheelMessage=%s, " |
michael@0 | 1033 | "mOverriddenVerticalScrollAmount=%d, " |
michael@0 | 1034 | "mOverriddenHorizontalScrollAmount=%d, " |
michael@0 | 1035 | "mMouseScrollTransactionTimeout=%d", |
michael@0 | 1036 | GetBoolName(mScrollMessageHandledAsWheelMessage), |
michael@0 | 1037 | mOverriddenVerticalScrollAmount, mOverriddenHorizontalScrollAmount, |
michael@0 | 1038 | mMouseScrollTransactionTimeout)); |
michael@0 | 1039 | } |
michael@0 | 1040 | |
michael@0 | 1041 | void |
michael@0 | 1042 | MouseScrollHandler::UserPrefs::MarkDirty() |
michael@0 | 1043 | { |
michael@0 | 1044 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1045 | ("MouseScrollHandler::UserPrefs::MarkDirty(): Marking UserPrefs dirty")); |
michael@0 | 1046 | mInitialized = false; |
michael@0 | 1047 | // Some prefs might override system settings, so, we should mark them dirty. |
michael@0 | 1048 | MouseScrollHandler::sInstance->mSystemSettings.MarkDirty(); |
michael@0 | 1049 | // When user prefs for mousewheel are changed, we should reset current |
michael@0 | 1050 | // transaction. |
michael@0 | 1051 | MOZ_ASSERT(sInstance, |
michael@0 | 1052 | "Must not be called at initializing MouseScrollHandler"); |
michael@0 | 1053 | MouseScrollHandler::sInstance->mLastEventInfo.ResetTransaction(); |
michael@0 | 1054 | } |
michael@0 | 1055 | |
michael@0 | 1056 | /****************************************************************************** |
michael@0 | 1057 | * |
michael@0 | 1058 | * Device |
michael@0 | 1059 | * |
michael@0 | 1060 | ******************************************************************************/ |
michael@0 | 1061 | |
michael@0 | 1062 | /* static */ |
michael@0 | 1063 | bool |
michael@0 | 1064 | MouseScrollHandler::Device::GetWorkaroundPref(const char* aPrefName, |
michael@0 | 1065 | bool aValueIfAutomatic) |
michael@0 | 1066 | { |
michael@0 | 1067 | if (!aPrefName) { |
michael@0 | 1068 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1069 | ("MouseScroll::Device::GetWorkaroundPref(): Failed, aPrefName is NULL")); |
michael@0 | 1070 | return aValueIfAutomatic; |
michael@0 | 1071 | } |
michael@0 | 1072 | |
michael@0 | 1073 | int32_t lHackValue = 0; |
michael@0 | 1074 | if (NS_FAILED(Preferences::GetInt(aPrefName, &lHackValue))) { |
michael@0 | 1075 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1076 | ("MouseScroll::Device::GetWorkaroundPref(): Preferences::GetInt() failed," |
michael@0 | 1077 | " aPrefName=\"%s\", aValueIfAutomatic=%s", |
michael@0 | 1078 | aPrefName, GetBoolName(aValueIfAutomatic))); |
michael@0 | 1079 | return aValueIfAutomatic; |
michael@0 | 1080 | } |
michael@0 | 1081 | |
michael@0 | 1082 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1083 | ("MouseScroll::Device::GetWorkaroundPref(): Succeeded, " |
michael@0 | 1084 | "aPrefName=\"%s\", aValueIfAutomatic=%s, lHackValue=%d", |
michael@0 | 1085 | aPrefName, GetBoolName(aValueIfAutomatic), lHackValue)); |
michael@0 | 1086 | |
michael@0 | 1087 | switch (lHackValue) { |
michael@0 | 1088 | case 0: // disabled |
michael@0 | 1089 | return false; |
michael@0 | 1090 | case 1: // enabled |
michael@0 | 1091 | return true; |
michael@0 | 1092 | default: // -1: autodetect |
michael@0 | 1093 | return aValueIfAutomatic; |
michael@0 | 1094 | } |
michael@0 | 1095 | } |
michael@0 | 1096 | |
michael@0 | 1097 | /* static */ |
michael@0 | 1098 | void |
michael@0 | 1099 | MouseScrollHandler::Device::Init() |
michael@0 | 1100 | { |
michael@0 | 1101 | // Not supported in metro mode. |
michael@0 | 1102 | if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) { |
michael@0 | 1103 | return; |
michael@0 | 1104 | } |
michael@0 | 1105 | |
michael@0 | 1106 | sFakeScrollableWindowNeeded = |
michael@0 | 1107 | GetWorkaroundPref("ui.trackpoint_hack.enabled", |
michael@0 | 1108 | (TrackPoint::IsDriverInstalled() || |
michael@0 | 1109 | UltraNav::IsObsoleteDriverInstalled())); |
michael@0 | 1110 | |
michael@0 | 1111 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1112 | ("MouseScroll::Device::Init(): sFakeScrollableWindowNeeded=%s", |
michael@0 | 1113 | GetBoolName(sFakeScrollableWindowNeeded))); |
michael@0 | 1114 | |
michael@0 | 1115 | Elantech::Init(); |
michael@0 | 1116 | } |
michael@0 | 1117 | |
michael@0 | 1118 | /****************************************************************************** |
michael@0 | 1119 | * |
michael@0 | 1120 | * Device::Elantech |
michael@0 | 1121 | * |
michael@0 | 1122 | ******************************************************************************/ |
michael@0 | 1123 | |
michael@0 | 1124 | /* static */ |
michael@0 | 1125 | void |
michael@0 | 1126 | MouseScrollHandler::Device::Elantech::Init() |
michael@0 | 1127 | { |
michael@0 | 1128 | int32_t version = GetDriverMajorVersion(); |
michael@0 | 1129 | bool needsHack = |
michael@0 | 1130 | Device::GetWorkaroundPref("ui.elantech_gesture_hacks.enabled", |
michael@0 | 1131 | version != 0); |
michael@0 | 1132 | sUseSwipeHack = needsHack && version <= 7; |
michael@0 | 1133 | sUsePinchHack = needsHack && version <= 8; |
michael@0 | 1134 | |
michael@0 | 1135 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1136 | ("MouseScroll::Device::Elantech::Init(): version=%d, sUseSwipeHack=%s, " |
michael@0 | 1137 | "sUsePinchHack=%s", |
michael@0 | 1138 | version, GetBoolName(sUseSwipeHack), GetBoolName(sUsePinchHack))); |
michael@0 | 1139 | } |
michael@0 | 1140 | |
michael@0 | 1141 | /* static */ |
michael@0 | 1142 | int32_t |
michael@0 | 1143 | MouseScrollHandler::Device::Elantech::GetDriverMajorVersion() |
michael@0 | 1144 | { |
michael@0 | 1145 | wchar_t buf[40]; |
michael@0 | 1146 | // The driver version is found in one of these two registry keys. |
michael@0 | 1147 | bool foundKey = |
michael@0 | 1148 | WinUtils::GetRegistryKey(HKEY_CURRENT_USER, |
michael@0 | 1149 | L"Software\\Elantech\\MainOption", |
michael@0 | 1150 | L"DriverVersion", |
michael@0 | 1151 | buf, sizeof buf); |
michael@0 | 1152 | if (!foundKey) { |
michael@0 | 1153 | foundKey = |
michael@0 | 1154 | WinUtils::GetRegistryKey(HKEY_CURRENT_USER, |
michael@0 | 1155 | L"Software\\Elantech", |
michael@0 | 1156 | L"DriverVersion", |
michael@0 | 1157 | buf, sizeof buf); |
michael@0 | 1158 | } |
michael@0 | 1159 | |
michael@0 | 1160 | if (!foundKey) { |
michael@0 | 1161 | return 0; |
michael@0 | 1162 | } |
michael@0 | 1163 | |
michael@0 | 1164 | // Assume that the major version number can be found just after a space |
michael@0 | 1165 | // or at the start of the string. |
michael@0 | 1166 | for (wchar_t* p = buf; *p; p++) { |
michael@0 | 1167 | if (*p >= L'0' && *p <= L'9' && (p == buf || *(p - 1) == L' ')) { |
michael@0 | 1168 | return wcstol(p, nullptr, 10); |
michael@0 | 1169 | } |
michael@0 | 1170 | } |
michael@0 | 1171 | |
michael@0 | 1172 | return 0; |
michael@0 | 1173 | } |
michael@0 | 1174 | |
michael@0 | 1175 | /* static */ |
michael@0 | 1176 | bool |
michael@0 | 1177 | MouseScrollHandler::Device::Elantech::IsHelperWindow(HWND aWnd) |
michael@0 | 1178 | { |
michael@0 | 1179 | // The helper window cannot be distinguished based on its window class, so we |
michael@0 | 1180 | // need to check if it is owned by the helper process, ETDCtrl.exe. |
michael@0 | 1181 | |
michael@0 | 1182 | const wchar_t* filenameSuffix = L"\\etdctrl.exe"; |
michael@0 | 1183 | const int filenameSuffixLength = 12; |
michael@0 | 1184 | |
michael@0 | 1185 | DWORD pid; |
michael@0 | 1186 | ::GetWindowThreadProcessId(aWnd, &pid); |
michael@0 | 1187 | |
michael@0 | 1188 | HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); |
michael@0 | 1189 | if (!hProcess) { |
michael@0 | 1190 | return false; |
michael@0 | 1191 | } |
michael@0 | 1192 | |
michael@0 | 1193 | bool result = false; |
michael@0 | 1194 | wchar_t path[256] = {L'\0'}; |
michael@0 | 1195 | if (::GetProcessImageFileNameW(hProcess, path, ArrayLength(path))) { |
michael@0 | 1196 | int pathLength = lstrlenW(path); |
michael@0 | 1197 | if (pathLength >= filenameSuffixLength) { |
michael@0 | 1198 | if (lstrcmpiW(path + pathLength - filenameSuffixLength, |
michael@0 | 1199 | filenameSuffix) == 0) { |
michael@0 | 1200 | result = true; |
michael@0 | 1201 | } |
michael@0 | 1202 | } |
michael@0 | 1203 | } |
michael@0 | 1204 | ::CloseHandle(hProcess); |
michael@0 | 1205 | |
michael@0 | 1206 | return result; |
michael@0 | 1207 | } |
michael@0 | 1208 | |
michael@0 | 1209 | /* static */ |
michael@0 | 1210 | bool |
michael@0 | 1211 | MouseScrollHandler::Device::Elantech::HandleKeyMessage(nsWindowBase* aWidget, |
michael@0 | 1212 | UINT aMsg, |
michael@0 | 1213 | WPARAM aWParam) |
michael@0 | 1214 | { |
michael@0 | 1215 | // The Elantech touchpad driver understands three-finger swipe left and |
michael@0 | 1216 | // right gestures, and translates them into Page Up and Page Down key |
michael@0 | 1217 | // events for most applications. For Firefox 3.6, it instead sends |
michael@0 | 1218 | // Alt+Left and Alt+Right to trigger browser back/forward actions. As |
michael@0 | 1219 | // with the Thinkpad Driver hack in nsWindow::Create, the change in |
michael@0 | 1220 | // HWND structure makes Firefox not trigger the driver's heuristics |
michael@0 | 1221 | // any longer. |
michael@0 | 1222 | // |
michael@0 | 1223 | // The Elantech driver actually sends these messages for a three-finger |
michael@0 | 1224 | // swipe right: |
michael@0 | 1225 | // |
michael@0 | 1226 | // WM_KEYDOWN virtual_key = 0xCC or 0xFF (depending on driver version) |
michael@0 | 1227 | // WM_KEYDOWN virtual_key = VK_NEXT |
michael@0 | 1228 | // WM_KEYUP virtual_key = VK_NEXT |
michael@0 | 1229 | // WM_KEYUP virtual_key = 0xCC or 0xFF |
michael@0 | 1230 | // |
michael@0 | 1231 | // so we use the 0xCC or 0xFF key modifier to detect whether the Page Down |
michael@0 | 1232 | // is due to the gesture rather than a regular Page Down keypress. We then |
michael@0 | 1233 | // pretend that we should dispatch "Go Forward" command. Similarly |
michael@0 | 1234 | // for VK_PRIOR and "Go Back" command. |
michael@0 | 1235 | if (sUseSwipeHack && |
michael@0 | 1236 | (aWParam == VK_NEXT || aWParam == VK_PRIOR) && |
michael@0 | 1237 | (IS_VK_DOWN(0xFF) || IS_VK_DOWN(0xCC))) { |
michael@0 | 1238 | if (aMsg == WM_KEYDOWN) { |
michael@0 | 1239 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1240 | ("MouseScroll::Device::Elantech::HandleKeyMessage(): Dispatching " |
michael@0 | 1241 | "%s command event", |
michael@0 | 1242 | aWParam == VK_NEXT ? "Forward" : "Back")); |
michael@0 | 1243 | |
michael@0 | 1244 | WidgetCommandEvent commandEvent(true, nsGkAtoms::onAppCommand, |
michael@0 | 1245 | (aWParam == VK_NEXT) ? nsGkAtoms::Forward : nsGkAtoms::Back, aWidget); |
michael@0 | 1246 | InitEvent(aWidget, commandEvent); |
michael@0 | 1247 | MouseScrollHandler::DispatchEvent(aWidget, commandEvent); |
michael@0 | 1248 | } |
michael@0 | 1249 | #ifdef PR_LOGGING |
michael@0 | 1250 | else { |
michael@0 | 1251 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1252 | ("MouseScroll::Device::Elantech::HandleKeyMessage(): Consumed")); |
michael@0 | 1253 | } |
michael@0 | 1254 | #endif |
michael@0 | 1255 | return true; // consume the message (doesn't need to dispatch key events) |
michael@0 | 1256 | } |
michael@0 | 1257 | |
michael@0 | 1258 | // Version 8 of the Elantech touchpad driver sends these messages for |
michael@0 | 1259 | // zoom gestures: |
michael@0 | 1260 | // |
michael@0 | 1261 | // WM_KEYDOWN virtual_key = 0xCC time = 10 |
michael@0 | 1262 | // WM_KEYDOWN virtual_key = VK_CONTROL time = 10 |
michael@0 | 1263 | // WM_MOUSEWHEEL time = ::GetTickCount() |
michael@0 | 1264 | // WM_KEYUP virtual_key = VK_CONTROL time = 10 |
michael@0 | 1265 | // WM_KEYUP virtual_key = 0xCC time = 10 |
michael@0 | 1266 | // |
michael@0 | 1267 | // The result of this is that we process all of the WM_KEYDOWN/WM_KEYUP |
michael@0 | 1268 | // messages first because their timestamps make them appear to have |
michael@0 | 1269 | // been sent before the WM_MOUSEWHEEL message. To work around this, |
michael@0 | 1270 | // we store the current time when we process the WM_KEYUP message and |
michael@0 | 1271 | // assume that any WM_MOUSEWHEEL message with a timestamp before that |
michael@0 | 1272 | // time is one that should be processed as if the Control key was down. |
michael@0 | 1273 | if (sUsePinchHack && aMsg == WM_KEYUP && |
michael@0 | 1274 | aWParam == VK_CONTROL && ::GetMessageTime() == 10) { |
michael@0 | 1275 | // We look only at the bottom 31 bits of the system tick count since |
michael@0 | 1276 | // GetMessageTime returns a LONG, which is signed, so we want values |
michael@0 | 1277 | // that are more easily comparable. |
michael@0 | 1278 | sZoomUntil = ::GetTickCount() & 0x7FFFFFFF; |
michael@0 | 1279 | |
michael@0 | 1280 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1281 | ("MouseScroll::Device::Elantech::HandleKeyMessage(): sZoomUntil=%d", |
michael@0 | 1282 | sZoomUntil)); |
michael@0 | 1283 | } |
michael@0 | 1284 | |
michael@0 | 1285 | return false; |
michael@0 | 1286 | } |
michael@0 | 1287 | |
michael@0 | 1288 | /* static */ |
michael@0 | 1289 | void |
michael@0 | 1290 | MouseScrollHandler::Device::Elantech::UpdateZoomUntil() |
michael@0 | 1291 | { |
michael@0 | 1292 | if (!sZoomUntil) { |
michael@0 | 1293 | return; |
michael@0 | 1294 | } |
michael@0 | 1295 | |
michael@0 | 1296 | // For the Elantech Touchpad Zoom Gesture Hack, we should check that the |
michael@0 | 1297 | // system time (32-bit milliseconds) hasn't wrapped around. Otherwise we |
michael@0 | 1298 | // might get into the situation where wheel events for the next 50 days of |
michael@0 | 1299 | // system uptime are assumed to be Ctrl+Wheel events. (It is unlikely that |
michael@0 | 1300 | // we would get into that state, because the system would already need to be |
michael@0 | 1301 | // up for 50 days and the Control key message would need to be processed just |
michael@0 | 1302 | // before the system time overflow and the wheel message just after.) |
michael@0 | 1303 | // |
michael@0 | 1304 | // We also take the chance to reset sZoomUntil if we simply have passed that |
michael@0 | 1305 | // time. |
michael@0 | 1306 | LONG msgTime = ::GetMessageTime(); |
michael@0 | 1307 | if ((sZoomUntil >= 0x3fffffffu && DWORD(msgTime) < 0x40000000u) || |
michael@0 | 1308 | (sZoomUntil < DWORD(msgTime))) { |
michael@0 | 1309 | sZoomUntil = 0; |
michael@0 | 1310 | |
michael@0 | 1311 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1312 | ("MouseScroll::Device::Elantech::UpdateZoomUntil(): " |
michael@0 | 1313 | "sZoomUntil was reset")); |
michael@0 | 1314 | } |
michael@0 | 1315 | } |
michael@0 | 1316 | |
michael@0 | 1317 | /* static */ |
michael@0 | 1318 | bool |
michael@0 | 1319 | MouseScrollHandler::Device::Elantech::IsZooming() |
michael@0 | 1320 | { |
michael@0 | 1321 | // Assume the Control key is down if the Elantech touchpad has sent the |
michael@0 | 1322 | // mis-ordered WM_KEYDOWN/WM_MOUSEWHEEL messages. (See the comment in |
michael@0 | 1323 | // OnKeyUp.) |
michael@0 | 1324 | return (sZoomUntil && static_cast<DWORD>(::GetMessageTime()) < sZoomUntil); |
michael@0 | 1325 | } |
michael@0 | 1326 | |
michael@0 | 1327 | /****************************************************************************** |
michael@0 | 1328 | * |
michael@0 | 1329 | * Device::TrackPoint |
michael@0 | 1330 | * |
michael@0 | 1331 | ******************************************************************************/ |
michael@0 | 1332 | |
michael@0 | 1333 | /* static */ |
michael@0 | 1334 | bool |
michael@0 | 1335 | MouseScrollHandler::Device::TrackPoint::IsDriverInstalled() |
michael@0 | 1336 | { |
michael@0 | 1337 | if (WinUtils::HasRegistryKey(HKEY_CURRENT_USER, |
michael@0 | 1338 | L"Software\\Lenovo\\TrackPoint")) { |
michael@0 | 1339 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1340 | ("MouseScroll::Device::TrackPoint::IsDriverInstalled(): " |
michael@0 | 1341 | "Lenovo's TrackPoint driver is found")); |
michael@0 | 1342 | return true; |
michael@0 | 1343 | } |
michael@0 | 1344 | |
michael@0 | 1345 | if (WinUtils::HasRegistryKey(HKEY_CURRENT_USER, |
michael@0 | 1346 | L"Software\\Alps\\Apoint\\TrackPoint")) { |
michael@0 | 1347 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1348 | ("MouseScroll::Device::TrackPoint::IsDriverInstalled(): " |
michael@0 | 1349 | "Alps's TrackPoint driver is found")); |
michael@0 | 1350 | } |
michael@0 | 1351 | |
michael@0 | 1352 | return false; |
michael@0 | 1353 | } |
michael@0 | 1354 | |
michael@0 | 1355 | /****************************************************************************** |
michael@0 | 1356 | * |
michael@0 | 1357 | * Device::UltraNav |
michael@0 | 1358 | * |
michael@0 | 1359 | ******************************************************************************/ |
michael@0 | 1360 | |
michael@0 | 1361 | /* static */ |
michael@0 | 1362 | bool |
michael@0 | 1363 | MouseScrollHandler::Device::UltraNav::IsObsoleteDriverInstalled() |
michael@0 | 1364 | { |
michael@0 | 1365 | if (WinUtils::HasRegistryKey(HKEY_CURRENT_USER, |
michael@0 | 1366 | L"Software\\Lenovo\\UltraNav")) { |
michael@0 | 1367 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1368 | ("MouseScroll::Device::UltraNav::IsObsoleteDriverInstalled(): " |
michael@0 | 1369 | "Lenovo's UltraNav driver is found")); |
michael@0 | 1370 | return true; |
michael@0 | 1371 | } |
michael@0 | 1372 | |
michael@0 | 1373 | bool installed = false; |
michael@0 | 1374 | if (WinUtils::HasRegistryKey(HKEY_CURRENT_USER, |
michael@0 | 1375 | L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB")) { |
michael@0 | 1376 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1377 | ("MouseScroll::Device::UltraNav::IsObsoleteDriverInstalled(): " |
michael@0 | 1378 | "Synaptics's UltraNav (USB) driver is found")); |
michael@0 | 1379 | installed = true; |
michael@0 | 1380 | } else if (WinUtils::HasRegistryKey(HKEY_CURRENT_USER, |
michael@0 | 1381 | L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2")) { |
michael@0 | 1382 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1383 | ("MouseScroll::Device::UltraNav::IsObsoleteDriverInstalled(): " |
michael@0 | 1384 | "Synaptics's UltraNav (PS/2) driver is found")); |
michael@0 | 1385 | installed = true; |
michael@0 | 1386 | } |
michael@0 | 1387 | |
michael@0 | 1388 | if (!installed) { |
michael@0 | 1389 | return false; |
michael@0 | 1390 | } |
michael@0 | 1391 | |
michael@0 | 1392 | wchar_t buf[40]; |
michael@0 | 1393 | bool foundKey = |
michael@0 | 1394 | WinUtils::GetRegistryKey(HKEY_LOCAL_MACHINE, |
michael@0 | 1395 | L"Software\\Synaptics\\SynTP\\Install", |
michael@0 | 1396 | L"DriverVersion", |
michael@0 | 1397 | buf, sizeof buf); |
michael@0 | 1398 | if (!foundKey) { |
michael@0 | 1399 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1400 | ("MouseScroll::Device::UltraNav::IsObsoleteDriverInstalled(): " |
michael@0 | 1401 | "Failed to get UltraNav driver version")); |
michael@0 | 1402 | return false; |
michael@0 | 1403 | } |
michael@0 | 1404 | |
michael@0 | 1405 | int majorVersion = wcstol(buf, nullptr, 10); |
michael@0 | 1406 | int minorVersion = 0; |
michael@0 | 1407 | wchar_t* p = wcschr(buf, L'.'); |
michael@0 | 1408 | if (p) { |
michael@0 | 1409 | minorVersion = wcstol(p + 1, nullptr, 10); |
michael@0 | 1410 | } |
michael@0 | 1411 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1412 | ("MouseScroll::Device::UltraNav::IsObsoleteDriverInstalled(): " |
michael@0 | 1413 | "found driver version = %d.%d", |
michael@0 | 1414 | majorVersion, minorVersion)); |
michael@0 | 1415 | return majorVersion < 15 || (majorVersion == 15 && minorVersion == 0); |
michael@0 | 1416 | } |
michael@0 | 1417 | |
michael@0 | 1418 | /****************************************************************************** |
michael@0 | 1419 | * |
michael@0 | 1420 | * Device::SetPoint |
michael@0 | 1421 | * |
michael@0 | 1422 | ******************************************************************************/ |
michael@0 | 1423 | |
michael@0 | 1424 | /* static */ |
michael@0 | 1425 | bool |
michael@0 | 1426 | MouseScrollHandler::Device::SetPoint::IsGetMessagePosResponseValid( |
michael@0 | 1427 | UINT aMessage, |
michael@0 | 1428 | WPARAM aWParam, |
michael@0 | 1429 | LPARAM aLParam) |
michael@0 | 1430 | { |
michael@0 | 1431 | if (aMessage != WM_MOUSEHWHEEL) { |
michael@0 | 1432 | return false; |
michael@0 | 1433 | } |
michael@0 | 1434 | |
michael@0 | 1435 | POINTS pts = MouseScrollHandler::GetCurrentMessagePos(); |
michael@0 | 1436 | LPARAM messagePos = MAKELPARAM(pts.x, pts.y); |
michael@0 | 1437 | |
michael@0 | 1438 | // XXX We should check whether SetPoint is installed or not by registry. |
michael@0 | 1439 | |
michael@0 | 1440 | // SetPoint, Logitech (Logicool) mouse driver, (confirmed with 4.82.11 and |
michael@0 | 1441 | // MX-1100) always sets 0 to the lParam of WM_MOUSEHWHEEL. The driver SENDs |
michael@0 | 1442 | // one message at first time, this time, ::GetMessagePos() works fine. |
michael@0 | 1443 | // Then, we will return 0 (0 means we process it) to the message. Then, the |
michael@0 | 1444 | // driver will POST the same messages continuously during the wheel tilted. |
michael@0 | 1445 | // But ::GetMessagePos() API always returns (0, 0) for them, even if the |
michael@0 | 1446 | // actual mouse cursor isn't 0,0. Therefore, we cannot trust the result of |
michael@0 | 1447 | // ::GetMessagePos API if the sender is SetPoint. |
michael@0 | 1448 | if (!sMightBeUsing && !aLParam && aLParam != messagePos && |
michael@0 | 1449 | ::InSendMessage()) { |
michael@0 | 1450 | sMightBeUsing = true; |
michael@0 | 1451 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1452 | ("MouseScroll::Device::SetPoint::IsGetMessagePosResponseValid(): " |
michael@0 | 1453 | "Might using SetPoint")); |
michael@0 | 1454 | } else if (sMightBeUsing && aLParam != 0 && ::InSendMessage()) { |
michael@0 | 1455 | // The user has changed the mouse from Logitech's to another one (e.g., |
michael@0 | 1456 | // the user has changed to the touchpad of the notebook. |
michael@0 | 1457 | sMightBeUsing = false; |
michael@0 | 1458 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1459 | ("MouseScroll::Device::SetPoint::IsGetMessagePosResponseValid(): " |
michael@0 | 1460 | "Might stop using SetPoint")); |
michael@0 | 1461 | } |
michael@0 | 1462 | return (sMightBeUsing && !aLParam && !messagePos); |
michael@0 | 1463 | } |
michael@0 | 1464 | |
michael@0 | 1465 | /****************************************************************************** |
michael@0 | 1466 | * |
michael@0 | 1467 | * SynthesizingEvent |
michael@0 | 1468 | * |
michael@0 | 1469 | ******************************************************************************/ |
michael@0 | 1470 | |
michael@0 | 1471 | /* static */ |
michael@0 | 1472 | bool |
michael@0 | 1473 | MouseScrollHandler::SynthesizingEvent::IsSynthesizing() |
michael@0 | 1474 | { |
michael@0 | 1475 | return MouseScrollHandler::sInstance && |
michael@0 | 1476 | MouseScrollHandler::sInstance->mSynthesizingEvent && |
michael@0 | 1477 | MouseScrollHandler::sInstance->mSynthesizingEvent->mStatus != |
michael@0 | 1478 | NOT_SYNTHESIZING; |
michael@0 | 1479 | } |
michael@0 | 1480 | |
michael@0 | 1481 | nsresult |
michael@0 | 1482 | MouseScrollHandler::SynthesizingEvent::Synthesize(const POINTS& aCursorPoint, |
michael@0 | 1483 | HWND aWnd, |
michael@0 | 1484 | UINT aMessage, |
michael@0 | 1485 | WPARAM aWParam, |
michael@0 | 1486 | LPARAM aLParam, |
michael@0 | 1487 | const BYTE (&aKeyStates)[256]) |
michael@0 | 1488 | { |
michael@0 | 1489 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1490 | ("MouseScrollHandler::SynthesizingEvent::Synthesize(): aCursorPoint: { " |
michael@0 | 1491 | "x: %d, y: %d }, aWnd=0x%X, aMessage=0x%04X, aWParam=0x%08X, " |
michael@0 | 1492 | "aLParam=0x%08X, IsSynthesized()=%s, mStatus=%s", |
michael@0 | 1493 | aCursorPoint.x, aCursorPoint.y, aWnd, aMessage, aWParam, aLParam, |
michael@0 | 1494 | GetBoolName(IsSynthesizing()), GetStatusName())); |
michael@0 | 1495 | |
michael@0 | 1496 | if (IsSynthesizing()) { |
michael@0 | 1497 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1498 | } |
michael@0 | 1499 | |
michael@0 | 1500 | ::GetKeyboardState(mOriginalKeyState); |
michael@0 | 1501 | |
michael@0 | 1502 | // Note that we cannot use ::SetCursorPos() because it works asynchronously. |
michael@0 | 1503 | // We should SEND the message for reducing the possibility of receiving |
michael@0 | 1504 | // unexpected message which were not sent from here. |
michael@0 | 1505 | mCursorPoint = aCursorPoint; |
michael@0 | 1506 | |
michael@0 | 1507 | mWnd = aWnd; |
michael@0 | 1508 | mMessage = aMessage; |
michael@0 | 1509 | mWParam = aWParam; |
michael@0 | 1510 | mLParam = aLParam; |
michael@0 | 1511 | |
michael@0 | 1512 | memcpy(mKeyState, aKeyStates, sizeof(mKeyState)); |
michael@0 | 1513 | ::SetKeyboardState(mKeyState); |
michael@0 | 1514 | |
michael@0 | 1515 | mStatus = SENDING_MESSAGE; |
michael@0 | 1516 | |
michael@0 | 1517 | // Don't assume that aWnd is always managed by nsWindow. It might be |
michael@0 | 1518 | // a plugin window. |
michael@0 | 1519 | ::SendMessage(aWnd, aMessage, aWParam, aLParam); |
michael@0 | 1520 | |
michael@0 | 1521 | return NS_OK; |
michael@0 | 1522 | } |
michael@0 | 1523 | |
michael@0 | 1524 | void |
michael@0 | 1525 | MouseScrollHandler::SynthesizingEvent::NativeMessageReceived(nsWindowBase* aWidget, |
michael@0 | 1526 | UINT aMessage, |
michael@0 | 1527 | WPARAM aWParam, |
michael@0 | 1528 | LPARAM aLParam) |
michael@0 | 1529 | { |
michael@0 | 1530 | if (mStatus == SENDING_MESSAGE && mMessage == aMessage && |
michael@0 | 1531 | mWParam == aWParam && mLParam == aLParam) { |
michael@0 | 1532 | mStatus = NATIVE_MESSAGE_RECEIVED; |
michael@0 | 1533 | if (aWidget && aWidget->GetWindowHandle() == mWnd) { |
michael@0 | 1534 | return; |
michael@0 | 1535 | } |
michael@0 | 1536 | // If the target window is not ours and received window is our plugin |
michael@0 | 1537 | // window, it comes from child window of the plugin. |
michael@0 | 1538 | if (aWidget && aWidget->WindowType() == eWindowType_plugin && |
michael@0 | 1539 | !WinUtils::GetNSWindowBasePtr(mWnd)) { |
michael@0 | 1540 | return; |
michael@0 | 1541 | } |
michael@0 | 1542 | // Otherwise, the message may not be sent by us. |
michael@0 | 1543 | } |
michael@0 | 1544 | |
michael@0 | 1545 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1546 | ("MouseScrollHandler::SynthesizingEvent::NativeMessageReceived(): " |
michael@0 | 1547 | "aWidget=%p, aWidget->GetWindowHandle()=0x%X, mWnd=0x%X, " |
michael@0 | 1548 | "aMessage=0x%04X, aWParam=0x%08X, aLParam=0x%08X, mStatus=%s", |
michael@0 | 1549 | aWidget, aWidget ? aWidget->GetWindowHandle() : 0, mWnd, |
michael@0 | 1550 | aMessage, aWParam, aLParam, GetStatusName())); |
michael@0 | 1551 | |
michael@0 | 1552 | // We failed to receive our sent message, we failed to do the job. |
michael@0 | 1553 | Finish(); |
michael@0 | 1554 | |
michael@0 | 1555 | return; |
michael@0 | 1556 | } |
michael@0 | 1557 | |
michael@0 | 1558 | void |
michael@0 | 1559 | MouseScrollHandler::SynthesizingEvent::NotifyNativeMessageHandlingFinished() |
michael@0 | 1560 | { |
michael@0 | 1561 | if (!IsSynthesizing()) { |
michael@0 | 1562 | return; |
michael@0 | 1563 | } |
michael@0 | 1564 | |
michael@0 | 1565 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1566 | ("MouseScrollHandler::SynthesizingEvent::" |
michael@0 | 1567 | "NotifyNativeMessageHandlingFinished(): IsWaitingInternalMessage=%s", |
michael@0 | 1568 | GetBoolName(MouseScrollHandler::IsWaitingInternalMessage()))); |
michael@0 | 1569 | |
michael@0 | 1570 | if (MouseScrollHandler::IsWaitingInternalMessage()) { |
michael@0 | 1571 | mStatus = INTERNAL_MESSAGE_POSTED; |
michael@0 | 1572 | return; |
michael@0 | 1573 | } |
michael@0 | 1574 | |
michael@0 | 1575 | // If the native message handler didn't post our internal message, |
michael@0 | 1576 | // we our job is finished. |
michael@0 | 1577 | // TODO: When we post the message to plugin window, there is remaning job. |
michael@0 | 1578 | Finish(); |
michael@0 | 1579 | } |
michael@0 | 1580 | |
michael@0 | 1581 | void |
michael@0 | 1582 | MouseScrollHandler::SynthesizingEvent::NotifyInternalMessageHandlingFinished() |
michael@0 | 1583 | { |
michael@0 | 1584 | if (!IsSynthesizing()) { |
michael@0 | 1585 | return; |
michael@0 | 1586 | } |
michael@0 | 1587 | |
michael@0 | 1588 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1589 | ("MouseScrollHandler::SynthesizingEvent::" |
michael@0 | 1590 | "NotifyInternalMessageHandlingFinished()")); |
michael@0 | 1591 | |
michael@0 | 1592 | Finish(); |
michael@0 | 1593 | } |
michael@0 | 1594 | |
michael@0 | 1595 | void |
michael@0 | 1596 | MouseScrollHandler::SynthesizingEvent::Finish() |
michael@0 | 1597 | { |
michael@0 | 1598 | if (!IsSynthesizing()) { |
michael@0 | 1599 | return; |
michael@0 | 1600 | } |
michael@0 | 1601 | |
michael@0 | 1602 | PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, |
michael@0 | 1603 | ("MouseScrollHandler::SynthesizingEvent::Finish()")); |
michael@0 | 1604 | |
michael@0 | 1605 | // Restore the original key state. |
michael@0 | 1606 | ::SetKeyboardState(mOriginalKeyState); |
michael@0 | 1607 | |
michael@0 | 1608 | mStatus = NOT_SYNTHESIZING; |
michael@0 | 1609 | } |
michael@0 | 1610 | |
michael@0 | 1611 | } // namespace widget |
michael@0 | 1612 | } // namespace mozilla |