mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-15 04:39:31 +00:00
Bug 970964 - Implement generic mouse/touch -> Pointer events converter. r=smaug,jimm
--HG-- extra : rebase_source : 165dc4e5c598f9e9f9de928efe16824037b95ff3
This commit is contained in:
parent
443d4364bc
commit
6cea53ee81
@ -8,6 +8,7 @@
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "Units.h"
|
||||
@ -21,6 +22,7 @@ class EventTarget;
|
||||
|
||||
class Touch MOZ_FINAL : public nsISupports
|
||||
, public nsWrapperCache
|
||||
, public WidgetPointerHelper
|
||||
{
|
||||
public:
|
||||
static bool PrefEnabled(JSContext* aCx, JSObject* aGlobal);
|
||||
|
@ -688,6 +688,7 @@ nsIPresShell::FrameSelection()
|
||||
|
||||
static bool sSynthMouseMove = true;
|
||||
static uint32_t sNextPresShellId;
|
||||
static bool sPointerEventEnabled = true;
|
||||
|
||||
PresShell::PresShell()
|
||||
: mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
|
||||
@ -736,6 +737,12 @@ PresShell::PresShell()
|
||||
"layout.reflow.synthMouseMove", true);
|
||||
addedSynthMouseMove = true;
|
||||
}
|
||||
static bool addedPointerEventEnabled = false;
|
||||
if (addedPointerEventEnabled) {
|
||||
Preferences::AddBoolVarCache(&sPointerEventEnabled,
|
||||
"dom.w3c_pointer_events.enabled", true);
|
||||
addedPointerEventEnabled = true;
|
||||
}
|
||||
|
||||
mPaintingIsFrozen = false;
|
||||
}
|
||||
@ -6299,12 +6306,102 @@ FlushThrottledStyles(nsIDocument *aDocument, void *aData)
|
||||
return true;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
DispatchPointerFromMouseOrTouch(PresShell* aShell,
|
||||
nsIFrame* aFrame,
|
||||
WidgetGUIEvent* aEvent,
|
||||
bool aDontRetargetEvents,
|
||||
nsEventStatus* aStatus)
|
||||
{
|
||||
uint32_t pointerMessage = 0;
|
||||
if (aEvent->eventStructType == NS_MOUSE_EVENT) {
|
||||
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
|
||||
// if it is not mouse then it is likely will come as touch event
|
||||
if (!mouseEvent->convertToPointer) {
|
||||
return NS_OK;
|
||||
}
|
||||
int16_t button = mouseEvent->button;
|
||||
switch (mouseEvent->message) {
|
||||
case NS_MOUSE_MOVE:
|
||||
if (mouseEvent->buttons == 0) {
|
||||
button = -1;
|
||||
}
|
||||
pointerMessage = NS_POINTER_MOVE;
|
||||
break;
|
||||
case NS_MOUSE_BUTTON_UP:
|
||||
pointerMessage = NS_POINTER_UP;
|
||||
break;
|
||||
case NS_MOUSE_BUTTON_DOWN:
|
||||
pointerMessage = NS_POINTER_DOWN;
|
||||
break;
|
||||
default:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
WidgetPointerEvent event(*mouseEvent);
|
||||
event.message = pointerMessage;
|
||||
event.button = button;
|
||||
event.convertToPointer = mouseEvent->convertToPointer = false;
|
||||
aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus);
|
||||
} else if (aEvent->eventStructType == NS_TOUCH_EVENT) {
|
||||
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
|
||||
// loop over all touches and dispatch pointer events on each touch
|
||||
// copy the event
|
||||
switch (touchEvent->message) {
|
||||
case NS_TOUCH_MOVE:
|
||||
pointerMessage = NS_POINTER_MOVE;
|
||||
break;
|
||||
case NS_TOUCH_END:
|
||||
pointerMessage = NS_POINTER_UP;
|
||||
break;
|
||||
case NS_TOUCH_START:
|
||||
pointerMessage = NS_POINTER_DOWN;
|
||||
break;
|
||||
case NS_TOUCH_CANCEL:
|
||||
pointerMessage = NS_POINTER_CANCEL;
|
||||
break;
|
||||
default:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
|
||||
mozilla::dom::Touch* touch = touchEvent->touches[i];
|
||||
if (!touch || !touch->convertToPointer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WidgetPointerEvent event(touchEvent->mFlags.mIsTrusted, pointerMessage, touchEvent->widget);
|
||||
event.isPrimary = i == 0;
|
||||
event.pointerId = touch->Identifier();
|
||||
event.refPoint.x = touch->mRefPoint.x;
|
||||
event.refPoint.y = touch->mRefPoint.y;
|
||||
event.modifiers = touchEvent->modifiers;
|
||||
event.width = touch->RadiusX();
|
||||
event.height = touch->RadiusY();
|
||||
event.tiltX = touch->tiltX;
|
||||
event.tiltY = touch->tiltY;
|
||||
event.time = touchEvent->time;
|
||||
event.mFlags = touchEvent->mFlags;
|
||||
event.button = WidgetMouseEvent::eLeftButton;
|
||||
event.buttons = WidgetMouseEvent::eLeftButtonFlag;
|
||||
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
event.convertToPointer = touch->convertToPointer = false;
|
||||
aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresShell::HandleEvent(nsIFrame* aFrame,
|
||||
WidgetGUIEvent* aEvent,
|
||||
bool aDontRetargetEvents,
|
||||
nsEventStatus* aEventStatus)
|
||||
{
|
||||
if (sPointerEventEnabled) {
|
||||
DispatchPointerFromMouseOrTouch(this, aFrame, aEvent, aDontRetargetEvents, aEventStatus);
|
||||
}
|
||||
|
||||
NS_ASSERTION(aFrame, "null frame");
|
||||
|
||||
if (mIsDestroying ||
|
||||
|
@ -36,6 +36,27 @@ namespace dom {
|
||||
class PBrowserChild;
|
||||
} // namespace dom
|
||||
|
||||
/******************************************************************************
|
||||
* mozilla::WidgetPointerHelper
|
||||
******************************************************************************/
|
||||
|
||||
class WidgetPointerHelper
|
||||
{
|
||||
public:
|
||||
bool convertToPointer;
|
||||
uint32_t tiltX;
|
||||
uint32_t tiltY;
|
||||
|
||||
WidgetPointerHelper() : convertToPointer(true), tiltX(0), tiltY(0) {}
|
||||
|
||||
void AssignPointerHelperData(const WidgetPointerHelper& aEvent)
|
||||
{
|
||||
convertToPointer = aEvent.convertToPointer;
|
||||
tiltX = aEvent.tiltX;
|
||||
tiltY = aEvent.tiltY;
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* mozilla::WidgetMouseEventBase
|
||||
******************************************************************************/
|
||||
@ -128,7 +149,7 @@ public:
|
||||
* mozilla::WidgetMouseEvent
|
||||
******************************************************************************/
|
||||
|
||||
class WidgetMouseEvent : public WidgetMouseEventBase
|
||||
class WidgetMouseEvent : public WidgetMouseEventBase, public WidgetPointerHelper
|
||||
{
|
||||
private:
|
||||
friend class mozilla::dom::PBrowserParent;
|
||||
@ -242,6 +263,7 @@ public:
|
||||
void AssignMouseEventData(const WidgetMouseEvent& aEvent, bool aCopyTargets)
|
||||
{
|
||||
AssignMouseEventBaseData(aEvent, aCopyTargets);
|
||||
AssignPointerHelperData(aEvent);
|
||||
|
||||
acceptActivation = aEvent.acceptActivation;
|
||||
ignoreRootScrollFrame = aEvent.ignoreRootScrollFrame;
|
||||
@ -532,8 +554,6 @@ public:
|
||||
, pointerId(0)
|
||||
, width(0)
|
||||
, height(0)
|
||||
, tiltX(0)
|
||||
, tiltY(0)
|
||||
, isPrimary(true)
|
||||
{
|
||||
UpdateFlags();
|
||||
@ -544,8 +564,6 @@ public:
|
||||
, pointerId(0)
|
||||
, width(0)
|
||||
, height(0)
|
||||
, tiltX(0)
|
||||
, tiltY(0)
|
||||
, isPrimary(true)
|
||||
{
|
||||
eventStructType = NS_POINTER_EVENT;
|
||||
@ -579,8 +597,6 @@ public:
|
||||
uint32_t pointerId;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t tiltX;
|
||||
uint32_t tiltY;
|
||||
bool isPrimary;
|
||||
|
||||
// XXX Not tested by test_assign_event_data.html
|
||||
@ -592,8 +608,6 @@ public:
|
||||
pointerId = aEvent.pointerId;
|
||||
width = aEvent.width;
|
||||
height = aEvent.height;
|
||||
tiltX = aEvent.tiltX;
|
||||
tiltY = aEvent.tiltY;
|
||||
isPrimary = aEvent.isPrimary;
|
||||
}
|
||||
};
|
||||
|
@ -558,6 +558,16 @@ WinUtils::GetMouseInputSource()
|
||||
return static_cast<uint16_t>(inputSource);
|
||||
}
|
||||
|
||||
bool
|
||||
WinUtils::GetIsMouseFromTouch(uint32_t aEventType)
|
||||
{
|
||||
#define MOUSEEVENTF_FROMTOUCH 0xFF515700
|
||||
return (aEventType == NS_MOUSE_BUTTON_DOWN ||
|
||||
aEventType == NS_MOUSE_BUTTON_UP ||
|
||||
aEventType == NS_MOUSE_MOVE) &&
|
||||
(GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH);
|
||||
}
|
||||
|
||||
/* static */
|
||||
MSG
|
||||
WinUtils::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam, HWND aWnd)
|
||||
|
@ -237,6 +237,8 @@ public:
|
||||
*/
|
||||
static uint16_t GetMouseInputSource();
|
||||
|
||||
static bool GetIsMouseFromTouch(uint32_t aEventType);
|
||||
|
||||
/**
|
||||
* SHCreateItemFromParsingName() calls native SHCreateItemFromParsingName()
|
||||
* API which is available on Vista and up.
|
||||
|
@ -283,6 +283,9 @@ static const int32_t kGlassMarginAdjustment = 2;
|
||||
// content.
|
||||
static const int32_t kResizableBorderMinSize = 3;
|
||||
|
||||
// Cached pointer events enabler value, True if pointer events are enabled.
|
||||
static bool gIsPointerEventsEnabled = false;
|
||||
|
||||
// We should never really try to accelerate windows bigger than this. In some
|
||||
// cases this might lead to no D3D9 acceleration where we could have had it
|
||||
// but D3D9 does not reliably report when it supports bigger windows. 8192
|
||||
@ -382,6 +385,10 @@ nsWindow::nsWindow() : nsWindowBase()
|
||||
// Init theme data
|
||||
nsUXThemeData::UpdateNativeThemeInfo();
|
||||
RedirectedKeyDownMessageManager::Forget();
|
||||
|
||||
Preferences::AddBoolVarCache(&gIsPointerEventsEnabled,
|
||||
"dom.w3c_pointer_events.enabled",
|
||||
gIsPointerEventsEnabled);
|
||||
} // !sInstanceCount
|
||||
|
||||
mIdleService = nullptr;
|
||||
@ -1271,7 +1278,8 @@ void nsWindow::SetThemeRegion()
|
||||
**************************************************************/
|
||||
|
||||
NS_METHOD nsWindow::RegisterTouchWindow() {
|
||||
if (Preferences::GetInt("dom.w3c_touch_events.enabled", 0)) {
|
||||
if (Preferences::GetInt("dom.w3c_touch_events.enabled", 0) ||
|
||||
gIsPointerEventsEnabled) {
|
||||
mTouchWindow = true;
|
||||
mGesture.RegisterTouchWindow(mWnd);
|
||||
::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0);
|
||||
@ -3792,6 +3800,10 @@ bool nsWindow::DispatchMouseEvent(uint32_t aEventType, WPARAM wParam,
|
||||
modifierKeyState.InitInputEvent(event);
|
||||
event.button = aButton;
|
||||
event.inputSource = aInputSource;
|
||||
// Convert Mouse events generated by pen device or if mouse not generated from touch
|
||||
event.convertToPointer =
|
||||
aInputSource == nsIDOMMouseEvent::MOZ_SOURCE_PEN ||
|
||||
!(WinUtils::GetIsMouseFromTouch(aEventType) && mTouchWindow);
|
||||
|
||||
nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset();
|
||||
|
||||
@ -5231,6 +5243,11 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
|
||||
// A GestureNotify event is dispatched to decide which single-finger panning
|
||||
// direction should be active (including none) and if pan feedback should
|
||||
// be displayed. Java and plugin windows can make their own calls.
|
||||
if (gIsPointerEventsEnabled) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
|
||||
nsPointWin touchPoint;
|
||||
touchPoint = gestureinfo->ptsLocation;
|
||||
@ -6093,6 +6110,10 @@ static int32_t RoundDown(double aDouble)
|
||||
// Gesture event processing. Handles WM_GESTURE events.
|
||||
bool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (gIsPointerEventsEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Treatment for pan events which translate into scroll events:
|
||||
if (mGesture.IsPanEvent(lParam)) {
|
||||
if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) )
|
||||
|
@ -76,18 +76,23 @@ namespace {
|
||||
uint32_t pointerId;
|
||||
Foundation::Rect contactRect;
|
||||
float pressure;
|
||||
float tiltX;
|
||||
float tiltY;
|
||||
|
||||
aPoint->get_Properties(props.GetAddressOf());
|
||||
aPoint->get_Position(&position);
|
||||
aPoint->get_PointerId(&pointerId);
|
||||
props->get_ContactRect(&contactRect);
|
||||
props->get_Pressure(&pressure);
|
||||
props->get_XTilt(&tiltX);
|
||||
props->get_YTilt(&tiltY);
|
||||
|
||||
nsIntPoint touchPoint = MetroUtils::LogToPhys(position);
|
||||
nsIntPoint touchRadius;
|
||||
touchRadius.x = WinUtils::LogToPhys(contactRect.Width) / 2;
|
||||
touchRadius.y = WinUtils::LogToPhys(contactRect.Height) / 2;
|
||||
return new Touch(pointerId,
|
||||
Touch* touch =
|
||||
new Touch(pointerId,
|
||||
touchPoint,
|
||||
// Rotation radius and angle.
|
||||
// W3C touch events v1 do not use these.
|
||||
@ -109,6 +114,9 @@ namespace {
|
||||
// draft says that the value should be 0.0 if no value
|
||||
// known.
|
||||
pressure);
|
||||
touch->tiltX = tiltX;
|
||||
touch->tiltY = tiltY;
|
||||
return touch;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -224,6 +232,8 @@ namespace {
|
||||
aData->mRadius,
|
||||
aData->mRotationAngle,
|
||||
aData->mForce);
|
||||
copy->tiltX = aData->tiltX;
|
||||
copy->tiltY = aData->tiltY;
|
||||
touches->AppendElement(copy);
|
||||
aData->mChanged = false;
|
||||
return PL_DHASH_NEXT;
|
||||
@ -789,6 +799,8 @@ MetroInput::InitGeckoMouseEventFromPointerPoint(
|
||||
uint64_t timestamp;
|
||||
float pressure;
|
||||
boolean canBeDoubleTap;
|
||||
float tiltX;
|
||||
float tiltY;
|
||||
|
||||
aPointerPoint->get_Position(&position);
|
||||
aPointerPoint->get_Timestamp(×tamp);
|
||||
@ -796,6 +808,9 @@ MetroInput::InitGeckoMouseEventFromPointerPoint(
|
||||
device->get_PointerDeviceType(&deviceType);
|
||||
aPointerPoint->get_Properties(props.GetAddressOf());
|
||||
props->get_Pressure(&pressure);
|
||||
props->get_XTilt(&tiltX);
|
||||
props->get_YTilt(&tiltY);
|
||||
|
||||
mGestureRecognizer->CanBeDoubleTap(aPointerPoint, &canBeDoubleTap);
|
||||
|
||||
TransformRefPoint(position, aEvent->refPoint);
|
||||
@ -806,6 +821,8 @@ MetroInput::InitGeckoMouseEventFromPointerPoint(
|
||||
aEvent->clickCount = 2;
|
||||
}
|
||||
aEvent->pressure = pressure;
|
||||
aEvent->tiltX = tiltX;
|
||||
aEvent->tiltY = tiltY;
|
||||
aEvent->buttons = ButtonsForPointerPoint(aPointerPoint);
|
||||
|
||||
MozInputSourceFromDeviceType(deviceType, aEvent->inputSource);
|
||||
|
Loading…
x
Reference in New Issue
Block a user