Bug 941774 - Win32/winrt shared implementation. r=bbondy

This commit is contained in:
Jim Mathies 2013-12-14 14:40:56 -06:00
parent 10b178f798
commit de63519aea
3 changed files with 314 additions and 0 deletions

View File

@ -6,9 +6,16 @@
#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)
@ -27,3 +34,164 @@ nsWindowBase::DispatchPluginEvent(const MSG& aMsg)
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;
}

View File

@ -8,7 +8,10 @@
#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
@ -75,6 +78,42 @@ public:
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;
};

View File

@ -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