Revision 838bebb936d4440c16c7e109e50203b80ad8a1bf authored by Brad Lassey on 23 January 2014, 20:00:17 UTC, committed by Brad Lassey on 23 January 2014, 20:00:17 UTC
1 parent 4d5f91b
Raw File
nsWindowBase.cpp
/* -*- 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;
}


back to top