mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-12 21:05:36 +00:00
eac959a338
Currently, NativeKey::DispatchPluginEventsAndDiscardsCharMessages() calls nsWindowBase::DispatchPluginEvent() and nsWindowBase::DispatchPluginEvent() does nothing when windowless plugin doesn't have focus. However, this is unclear when other developers read the code of DispatchPluginEventsAndDiscardsCharMessages() and it causes unnecessary virtual calls. So, it should try to dispatch plugin events only when a windowless plugin has focus. For making the check safer, nsWindowBase should expose the method to check it as ShouldDispatchPluginEvent(). Unfortunately, we cannot mark this method as const due to PluginHasFocus() needs to be not const method, though. Then, for loops in DispatchPluginEventsAndDiscardsCharMessages() should check it at each try. This change helps to log the behavior (working on bug 1297013) without noise. Additionally, this patch renames the method to MaybeDispatchPluginEventsForRemovedCharMessages() because it doesn't remove any char messages anymore. MozReview-Commit-ID: F14Lcx47M6U --HG-- extra : rebase_source : 64b6da75590c99299f75358023844762198136d6
243 lines
7.3 KiB
C++
243 lines
7.3 KiB
C++
/* -*- 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 (!InitTouchInjection()) {
|
|
// If we don't have touch injection from the OS, 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;
|
|
}
|