forked from mirrors/gecko-dev
		
	 3277c04273
			
		
	
	
		3277c04273
		
	
	
	
	
		
			
			MozReview-Commit-ID: A0thvn5bBDy --HG-- extra : rebase_source : 50795a1b7f7704b0cb636faf2f60acd89ea5bfab
		
			
				
	
	
		
			244 lines
		
	
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
	
		
			7.4 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"
 | |
| #include "nsIPresShell.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();
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 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;
 | |
| }
 |