gecko/widget/windows/nsWindowBase.cpp

198 lines
5.9 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 "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);
nsIntPoint point(0, 0);
InitEvent(pluginEvent, &point);
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;
}