summaryrefslogtreecommitdiffstats
path: root/widget/windows/nsWindowBase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'widget/windows/nsWindowBase.cpp')
-rw-r--r--widget/windows/nsWindowBase.cpp243
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;
+}