summaryrefslogtreecommitdiffstats
path: root/widget/windows/nsWindowBase.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /widget/windows/nsWindowBase.cpp
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--widget/windows/nsWindowBase.cpp224
1 files changed, 224 insertions, 0 deletions
diff --git a/widget/windows/nsWindowBase.cpp b/widget/windows/nsWindowBase.cpp
new file mode 100644
index 0000000000..a9c9d2b53e
--- /dev/null
+++ b/widget/windows/nsWindowBase.cpp
@@ -0,0 +1,224 @@
+/* -*- 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 "mozilla/PresShell.h"
+#include "mozilla/StaticPrefs_apz.h"
+#include "KeyboardLayout.h"
+#include "WinUtils.h"
+#include "npapi.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) { return false; }
+
+// 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;
+
+ for (int i = 0; i < 3; i++) {
+ if (sInjectTouchFuncPtr(1, &info)) {
+ break;
+ }
+ DWORD error = GetLastError();
+ if (error == ERROR_NOT_READY && i < 2) {
+ // We sent it too quickly after the previous injection (see bug 1535140
+ // comment 10). On the first loop iteration we just yield (via Sleep(0))
+ // and try again. If it happens again on the second loop iteration we
+ // explicitly Sleep(1) and try again. If that doesn't work either we just
+ // error out.
+ ::Sleep(i);
+ continue;
+ }
+ WinUtils::Log("InjectTouchInput failure. GetLastError=%d", error);
+ return false;
+ }
+ return true;
+}
+
+void nsWindowBase::ChangedDPI() {
+ if (mWidgetListener) {
+ if (PresShell* presShell = mWidgetListener->GetPresShell()) {
+ presShell->BackingScaleFactorChanged();
+ }
+ }
+}
+
+nsresult nsWindowBase::SynthesizeNativeTouchPoint(
+ uint32_t aPointerId, nsIWidget::TouchPointerState aPointerState,
+ LayoutDeviceIntPoint aPoint, double aPointerPressure,
+ uint32_t aPointerOrientation, nsIObserver* aObserver) {
+ AutoObserverNotifier notifier(aObserver, "touchpoint");
+
+ if (StaticPrefs::apz_test_fails_with_native_injection() ||
+ !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()) {
+ auto info = iter.UserData();
+ InjectTouchPoint(info->mPointerId, info->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;
+}