Bug 941774 - Win32/winrt shared implementation. r=bbondy a=lsblakk
--- a/widget/windows/nsWindowBase.cpp
+++ b/widget/windows/nsWindowBase.cpp
@@ -1,19 +1,26 @@
/* -*- 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 "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)
{
if (!PluginHasFocus()) {
return false;
}
WidgetPluginEvent pluginEvent(true, NS_PLUGIN_INPUT_EVENT, this);
@@ -22,8 +29,169 @@ nsWindowBase::DispatchPluginEvent(const
NPEvent npEvent;
npEvent.event = aMsg.message;
npEvent.wParam = aMsg.wParam;
npEvent.lParam = aMsg.lParam;
pluginEvent.pluginEvent = &npEvent;
pluginEvent.retargetToFocusedDocument = true;
return DispatchWindowEvent(&pluginEvent);
}
+
+// 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, nsIntPoint& aPointerScreenPoint,
+ 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 = WinUtils::LogToPhys(aPointerScreenPoint.x);
+ info.pointerInfo.ptPixelLocation.y = WinUtils::LogToPhys(aPointerScreenPoint.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;
+}
+
+nsresult
+nsWindowBase::SynthesizeNativeTouchPoint(uint32_t aPointerId,
+ nsIWidget::TouchPointerState aPointerState,
+ nsIntPoint aPointerScreenPoint,
+ double aPointerPressure,
+ uint32_t aPointerOrientation)
+{
+ if (!InitTouchInjection()) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+ }
+
+ 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, aPointerScreenPoint, 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, aPointerScreenPoint);
+
+ POINTER_FLAGS flags = POINTER_FLAG_INRANGE;
+ if (contact) {
+ flags |= POINTER_FLAG_INCONTACT|POINTER_FLAG_DOWN;
+ }
+
+ mActivePointers.Put(aPointerId, info);
+ return !InjectTouchPoint(aPointerId, aPointerScreenPoint, flags,
+ pressure, aPointerOrientation) ?
+ NS_ERROR_UNEXPECTED : NS_OK;
+}
+
+// static
+PLDHashOperator
+nsWindowBase::CancelTouchPoints(const unsigned int& aPointerId, nsAutoPtr<PointerInfo>& aInfo, void* aUserArg)
+{
+ nsWindowBase* self = static_cast<nsWindowBase*>(aUserArg);
+ self->InjectTouchPoint(aInfo.get()->mPointerId, aInfo.get()->mPosition, POINTER_FLAG_CANCELED);
+ return (PLDHashOperator)(PL_DHASH_NEXT|PL_DHASH_REMOVE);
+}
+
+nsresult
+nsWindowBase::ClearNativeTouchSequence()
+{
+ if (!sTouchInjectInitialized) {
+ return NS_OK;
+ }
+
+ // cancel all input points
+ mActivePointers.Enumerate(CancelTouchPoints, (void*)this);
+
+ nsBaseWidget::ClearNativeTouchSequence();
+
+ return NS_OK;
+}
+
+
--- a/widget/windows/nsWindowBase.h
+++ b/widget/windows/nsWindowBase.h
@@ -3,17 +3,20 @@
* 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/. */
#ifndef nsWindowBase_h_
#define nsWindowBase_h_
#include "mozilla/EventForwards.h"
#include "nsBaseWidget.h"
+#include "nsClassHashtable.h"
+
#include <windows.h>
+#include "touchinjection_sdk80.h"
/*
* nsWindowBase - Base class of common methods other classes need to access
* in both win32 and winrt window classes.
*/
class nsWindowBase : public nsBaseWidget
{
public:
@@ -70,13 +73,49 @@ public:
/*
* Returns true if a plugin has focus on this widget. Otherwise, false.
*/
virtual bool PluginHasFocus() const MOZ_FINAL
{
return (mInputContext.mIMEState.mEnabled == IMEState::PLUGIN);
}
+public:
+ /*
+ * Touch input injection apis
+ */
+ virtual nsresult SynthesizeNativeTouchPoint(uint32_t aPointerId,
+ TouchPointerState aPointerState,
+ nsIntPoint aPointerScreenPoint,
+ double aPointerPressure,
+ uint32_t aPointerOrientation);
+ virtual nsresult ClearNativeTouchSequence();
+
+protected:
+ static bool InitTouchInjection();
+ bool InjectTouchPoint(uint32_t aId, nsIntPoint& aPointerScreenPoint,
+ POINTER_FLAGS aFlags, uint32_t aPressure = 1024,
+ uint32_t aOrientation = 90);
+
+ class PointerInfo
+ {
+ public:
+ PointerInfo(int32_t aPointerId, nsIntPoint& aPoint) :
+ mPointerId(aPointerId),
+ mPosition(aPoint)
+ {
+ }
+
+ int32_t mPointerId;
+ nsIntPoint mPosition;
+ };
+
+ static PLDHashOperator CancelTouchPoints(const unsigned int& aPointerId, nsAutoPtr<PointerInfo>& aInfo, void* aUserArg);
+
+ nsClassHashtable<nsUint32HashKey, PointerInfo> mActivePointers;
+ static bool sTouchInjectInitialized;
+ static InjectTouchInputPtr sInjectTouchFuncPtr;
+
protected:
InputContext mInputContext;
};
#endif // nsWindowBase_h_
new file mode 100644
--- /dev/null
+++ b/widget/windows/touchinjection_sdk80.h
@@ -0,0 +1,107 @@
+/* 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/. */
+
+#ifndef touchinjection_sdk80_h
+#define touchinjection_sdk80_h
+
+// Note, this isn't inclusive of all touch injection header info.
+// You may need to add more to expand on current apis.
+
+#ifndef TOUCH_FEEDBACK_DEFAULT
+
+#define TOUCH_FEEDBACK_DEFAULT 0x1
+#define TOUCH_FEEDBACK_INDIRECT 0x2
+#define TOUCH_FEEDBACK_NONE 0x3
+
+enum {
+ PT_POINTER = 0x00000001, // Generic pointer
+ PT_TOUCH = 0x00000002, // Touch
+ PT_PEN = 0x00000003, // Pen
+ PT_MOUSE = 0x00000004, // Mouse
+};
+
+typedef DWORD POINTER_INPUT_TYPE;
+typedef UINT32 POINTER_FLAGS;
+
+typedef enum {
+ POINTER_CHANGE_NONE,
+ POINTER_CHANGE_FIRSTBUTTON_DOWN,
+ POINTER_CHANGE_FIRSTBUTTON_UP,
+ POINTER_CHANGE_SECONDBUTTON_DOWN,
+ POINTER_CHANGE_SECONDBUTTON_UP,
+ POINTER_CHANGE_THIRDBUTTON_DOWN,
+ POINTER_CHANGE_THIRDBUTTON_UP,
+ POINTER_CHANGE_FOURTHBUTTON_DOWN,
+ POINTER_CHANGE_FOURTHBUTTON_UP,
+ POINTER_CHANGE_FIFTHBUTTON_DOWN,
+ POINTER_CHANGE_FIFTHBUTTON_UP,
+} POINTER_BUTTON_CHANGE_TYPE;
+
+typedef struct {
+ POINTER_INPUT_TYPE pointerType;
+ UINT32 pointerId;
+ UINT32 frameId;
+ POINTER_FLAGS pointerFlags;
+ HANDLE sourceDevice;
+ HWND hwndTarget;
+ POINT ptPixelLocation;
+ POINT ptHimetricLocation;
+ POINT ptPixelLocationRaw;
+ POINT ptHimetricLocationRaw;
+ DWORD dwTime;
+ UINT32 historyCount;
+ INT32 InputData;
+ DWORD dwKeyStates;
+ UINT64 PerformanceCount;
+ POINTER_BUTTON_CHANGE_TYPE ButtonChangeType;
+} POINTER_INFO;
+
+typedef UINT32 TOUCH_FLAGS;
+typedef UINT32 TOUCH_MASK;
+
+typedef struct {
+ POINTER_INFO pointerInfo;
+ TOUCH_FLAGS touchFlags;
+ TOUCH_MASK touchMask;
+ RECT rcContact;
+ RECT rcContactRaw;
+ UINT32 orientation;
+ UINT32 pressure;
+} POINTER_TOUCH_INFO;
+
+#define TOUCH_FLAG_NONE 0x00000000 // Default
+
+#define TOUCH_MASK_NONE 0x00000000 // Default - none of the optional fields are valid
+#define TOUCH_MASK_CONTACTAREA 0x00000001 // The rcContact field is valid
+#define TOUCH_MASK_ORIENTATION 0x00000002 // The orientation field is valid
+#define TOUCH_MASK_PRESSURE 0x00000004 // The pressure field is valid
+
+#define POINTER_FLAG_NONE 0x00000000 // Default
+#define POINTER_FLAG_NEW 0x00000001 // New pointer
+#define POINTER_FLAG_INRANGE 0x00000002 // Pointer has not departed
+#define POINTER_FLAG_INCONTACT 0x00000004 // Pointer is in contact
+#define POINTER_FLAG_FIRSTBUTTON 0x00000010 // Primary action
+#define POINTER_FLAG_SECONDBUTTON 0x00000020 // Secondary action
+#define POINTER_FLAG_THIRDBUTTON 0x00000040 // Third button
+#define POINTER_FLAG_FOURTHBUTTON 0x00000080 // Fourth button
+#define POINTER_FLAG_FIFTHBUTTON 0x00000100 // Fifth button
+#define POINTER_FLAG_PRIMARY 0x00002000 // Pointer is primary
+#define POINTER_FLAG_CONFIDENCE 0x00004000 // Pointer is considered unlikely to be accidental
+#define POINTER_FLAG_CANCELED 0x00008000 // Pointer is departing in an abnormal manner
+#define POINTER_FLAG_DOWN 0x00010000 // Pointer transitioned to down state (made contact)
+#define POINTER_FLAG_UPDATE 0x00020000 // Pointer update
+#define POINTER_FLAG_UP 0x00040000 // Pointer transitioned from down state (broke contact)
+#define POINTER_FLAG_WHEEL 0x00080000 // Vertical wheel
+#define POINTER_FLAG_HWHEEL 0x00100000 // Horizontal wheel
+#define POINTER_FLAG_CAPTURECHANGED 0x00200000 // Lost capture
+
+#endif // TOUCH_FEEDBACK_DEFAULT
+
+#define TOUCH_FLAGS_CONTACTUPDATE (POINTER_FLAG_UPDATE|POINTER_FLAG_INRANGE|POINTER_FLAG_INCONTACT)
+#define TOUCH_FLAGS_CONTACTDOWN (POINTER_FLAG_DOWN|POINTER_FLAG_INRANGE|POINTER_FLAG_INCONTACT)
+
+typedef BOOL (WINAPI* InitializeTouchInjectionPtr)(UINT32 maxCount, DWORD dwMode);
+typedef BOOL (WINAPI* InjectTouchInputPtr)(UINT32 count, CONST POINTER_TOUCH_INFO *info);
+
+#endif // touchinjection_sdk80_h
\ No newline at end of file