forked from mirrors/gecko-dev
		
	MozReview-Commit-ID: GxWehmDYB3t --HG-- extra : rebase_source : cd994e5c6abf777f77c5a708cbfb2f6afc49a44c
		
			
				
	
	
		
			244 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
	
		
			7.5 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 "gfxPrefs.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 (gfxPrefs::APZTestFailsWithNativeInjection() || !InitTouchInjection()) {
 | 
						|
    // If we don't have touch injection from the OS, or if we are running a test
 | 
						|
    // that cannot properly inject events to satisfy the OS requirements (see bug
 | 
						|
    // 1313170)  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;
 | 
						|
}
 |