diff options
Diffstat (limited to 'widget/windows/nsWindowBase.cpp')
-rw-r--r-- | widget/windows/nsWindowBase.cpp | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/widget/windows/nsWindowBase.cpp b/widget/windows/nsWindowBase.cpp new file mode 100644 index 000000000..a374b3635 --- /dev/null +++ b/widget/windows/nsWindowBase.cpp @@ -0,0 +1,243 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsWindowBase.h" + +#include "mozilla/MiscEvents.h" +#include "KeyboardLayout.h" +#include "WinUtils.h" +#include "npapi.h" +#include "nsAutoPtr.h" + +using namespace mozilla; +using namespace mozilla::widget; + +static const wchar_t kUser32LibName[] = L"user32.dll"; +bool nsWindowBase::sTouchInjectInitialized = false; +InjectTouchInputPtr nsWindowBase::sInjectTouchFuncPtr; + +bool +nsWindowBase::DispatchPluginEvent(const MSG& aMsg) +{ + if (!ShouldDispatchPluginEvent()) { + return false; + } + WidgetPluginEvent pluginEvent(true, ePluginInputEvent, this); + LayoutDeviceIntPoint point(0, 0); + InitEvent(pluginEvent, &point); + NPEvent npEvent; + npEvent.event = aMsg.message; + npEvent.wParam = aMsg.wParam; + npEvent.lParam = aMsg.lParam; + pluginEvent.mPluginEvent.Copy(npEvent); + pluginEvent.mRetargetToFocusedDocument = true; + return DispatchWindowEvent(&pluginEvent); +} + +bool +nsWindowBase::ShouldDispatchPluginEvent() +{ + return PluginHasFocus(); +} + +// static +bool +nsWindowBase::InitTouchInjection() +{ + if (!sTouchInjectInitialized) { + // Initialize touch injection on the first call + HMODULE hMod = LoadLibraryW(kUser32LibName); + if (!hMod) { + return false; + } + + InitializeTouchInjectionPtr func = + (InitializeTouchInjectionPtr)GetProcAddress(hMod, "InitializeTouchInjection"); + if (!func) { + WinUtils::Log("InitializeTouchInjection not available."); + return false; + } + + if (!func(TOUCH_INJECT_MAX_POINTS, TOUCH_FEEDBACK_DEFAULT)) { + WinUtils::Log("InitializeTouchInjection failure. GetLastError=%d", GetLastError()); + return false; + } + + sInjectTouchFuncPtr = + (InjectTouchInputPtr)GetProcAddress(hMod, "InjectTouchInput"); + if (!sInjectTouchFuncPtr) { + WinUtils::Log("InjectTouchInput not available."); + return false; + } + sTouchInjectInitialized = true; + } + return true; +} + +bool +nsWindowBase::InjectTouchPoint(uint32_t aId, LayoutDeviceIntPoint& aPoint, + POINTER_FLAGS aFlags, uint32_t aPressure, + uint32_t aOrientation) +{ + if (aId > TOUCH_INJECT_MAX_POINTS) { + WinUtils::Log("Pointer ID exceeds maximum. See TOUCH_INJECT_MAX_POINTS."); + return false; + } + + POINTER_TOUCH_INFO info; + memset(&info, 0, sizeof(POINTER_TOUCH_INFO)); + + info.touchFlags = TOUCH_FLAG_NONE; + info.touchMask = TOUCH_MASK_CONTACTAREA|TOUCH_MASK_ORIENTATION|TOUCH_MASK_PRESSURE; + info.pressure = aPressure; + info.orientation = aOrientation; + + info.pointerInfo.pointerFlags = aFlags; + info.pointerInfo.pointerType = PT_TOUCH; + info.pointerInfo.pointerId = aId; + info.pointerInfo.ptPixelLocation.x = aPoint.x; + info.pointerInfo.ptPixelLocation.y = aPoint.y; + + info.rcContact.top = info.pointerInfo.ptPixelLocation.y - 2; + info.rcContact.bottom = info.pointerInfo.ptPixelLocation.y + 2; + info.rcContact.left = info.pointerInfo.ptPixelLocation.x - 2; + info.rcContact.right = info.pointerInfo.ptPixelLocation.x + 2; + + if (!sInjectTouchFuncPtr(1, &info)) { + WinUtils::Log("InjectTouchInput failure. GetLastError=%d", GetLastError()); + return false; + } + return true; +} + +void nsWindowBase::ChangedDPI() +{ + if (mWidgetListener) { + nsIPresShell* presShell = mWidgetListener->GetPresShell(); + if (presShell) { + presShell->BackingScaleFactorChanged(); + } + mWidgetListener->UIResolutionChanged(); + } +} + +nsresult +nsWindowBase::SynthesizeNativeTouchPoint(uint32_t aPointerId, + nsIWidget::TouchPointerState aPointerState, + LayoutDeviceIntPoint aPoint, + double aPointerPressure, + uint32_t aPointerOrientation, + nsIObserver* aObserver) +{ + AutoObserverNotifier notifier(aObserver, "touchpoint"); + + if (gfxPrefs::APZTestFailsWithNativeInjection() || !InitTouchInjection()) { + // If we don't have touch injection from the OS, or if we are running a test + // that cannot properly inject events to satisfy the OS requirements (see bug + // 1313170) we can just fake it and synthesize the events from here. + MOZ_ASSERT(NS_IsMainThread()); + if (aPointerState == TOUCH_HOVER) { + return NS_ERROR_UNEXPECTED; + } + + if (!mSynthesizedTouchInput) { + mSynthesizedTouchInput = MakeUnique<MultiTouchInput>(); + } + + WidgetEventTime time = CurrentMessageWidgetEventTime(); + LayoutDeviceIntPoint pointInWindow = aPoint - WidgetToScreenOffset(); + MultiTouchInput inputToDispatch = UpdateSynthesizedTouchState( + mSynthesizedTouchInput.get(), time.mTime, time.mTimeStamp, + aPointerId, aPointerState, pointInWindow, aPointerPressure, + aPointerOrientation); + DispatchTouchInput(inputToDispatch); + return NS_OK; + } + + bool hover = aPointerState & TOUCH_HOVER; + bool contact = aPointerState & TOUCH_CONTACT; + bool remove = aPointerState & TOUCH_REMOVE; + bool cancel = aPointerState & TOUCH_CANCEL; + + // win api expects a value from 0 to 1024. aPointerPressure is a value + // from 0.0 to 1.0. + uint32_t pressure = (uint32_t)ceil(aPointerPressure * 1024); + + // If we already know about this pointer id get it's record + PointerInfo* info = mActivePointers.Get(aPointerId); + + // We know about this pointer, send an update + if (info) { + POINTER_FLAGS flags = POINTER_FLAG_UPDATE; + if (hover) { + flags |= POINTER_FLAG_INRANGE; + } else if (contact) { + flags |= POINTER_FLAG_INCONTACT|POINTER_FLAG_INRANGE; + } else if (remove) { + flags = POINTER_FLAG_UP; + // Remove the pointer from our tracking list. This is nsAutPtr wrapped, + // so shouldn't leak. + mActivePointers.Remove(aPointerId); + } + + if (cancel) { + flags |= POINTER_FLAG_CANCELED; + } + + return !InjectTouchPoint(aPointerId, aPoint, flags, + pressure, aPointerOrientation) ? + NS_ERROR_UNEXPECTED : NS_OK; + } + + // Missing init state, error out + if (remove || cancel) { + return NS_ERROR_INVALID_ARG; + } + + // Create a new pointer + info = new PointerInfo(aPointerId, aPoint); + + POINTER_FLAGS flags = POINTER_FLAG_INRANGE; + if (contact) { + flags |= POINTER_FLAG_INCONTACT|POINTER_FLAG_DOWN; + } + + mActivePointers.Put(aPointerId, info); + return !InjectTouchPoint(aPointerId, aPoint, flags, + pressure, aPointerOrientation) ? + NS_ERROR_UNEXPECTED : NS_OK; +} + +nsresult +nsWindowBase::ClearNativeTouchSequence(nsIObserver* aObserver) +{ + AutoObserverNotifier notifier(aObserver, "cleartouch"); + if (!sTouchInjectInitialized) { + return NS_OK; + } + + // cancel all input points + for (auto iter = mActivePointers.Iter(); !iter.Done(); iter.Next()) { + nsAutoPtr<PointerInfo>& info = iter.Data(); + InjectTouchPoint(info.get()->mPointerId, info.get()->mPosition, + POINTER_FLAG_CANCELED); + iter.Remove(); + } + + nsBaseWidget::ClearNativeTouchSequence(nullptr); + + return NS_OK; +} + +bool +nsWindowBase::HandleAppCommandMsg(const MSG& aAppCommandMsg, + LRESULT *aRetValue) +{ + ModifierKeyState modKeyState; + NativeKey nativeKey(this, aAppCommandMsg, modKeyState); + bool consumed = nativeKey.HandleAppCommandMessage(); + *aRetValue = consumed ? 1 : 0; + return consumed; +} |