Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/widget/windows/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 10.2.2025 mit Größe 11 kB image not shown  

SSL nsWinGesture.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 2; 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/. */


/*
 * nsWinGesture - Touch input handling for tablet displays.
 */


#include "nscore.h"
#include "nsWinGesture.h"
#include "nsUXThemeData.h"
#include "mozilla/Logging.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/Preferences.h"
#include "mozilla/TouchEvents.h"
#include "mozilla/dom/SimpleGestureEventBinding.h"
#include "mozilla/dom/WheelEventBinding.h"

#include <cmath>

using namespace mozilla;
using namespace mozilla::widget;

extern mozilla::LazyLogModule gWindowsLog;

static bool gEnableSingleFingerPanEvents = false;

nsWinGesture::nsWinGesture()
    : mPanActive(false),
      mFeedbackActive(false),
      mXAxisFeedback(false),
      mYAxisFeedback(false),
      mPanInertiaActive(false) {
  (void)InitLibrary();
  mPixelScrollOverflow = 0;
}

/* Load and shutdown */

bool nsWinGesture::InitLibrary() {
  // Check to see if we want single finger gesture input. Only do this once
  // for the app so we don't have to look it up on every window create.
  gEnableSingleFingerPanEvents =
      Preferences::GetBool("gestures.enable_single_finger_input"false);

  return true;
}

#define GCOUNT 5

bool nsWinGesture::SetWinGestureSupport(
    HWND hWnd, WidgetGestureNotifyEvent::PanDirection aDirection) {
  GESTURECONFIG config[GCOUNT];

  memset(&config, 0, sizeof(config));

  config[0].dwID = GID_ZOOM;
  config[0].dwWant = GC_ZOOM;
  config[0].dwBlock = 0;

  config[1].dwID = GID_ROTATE;
  config[1].dwWant = GC_ROTATE;
  config[1].dwBlock = 0;

  config[2].dwID = GID_PAN;
  config[2].dwWant = GC_PAN | GC_PAN_WITH_INERTIA | GC_PAN_WITH_GUTTER;
  config[2].dwBlock = GC_PAN_WITH_SINGLE_FINGER_VERTICALLY |
                      GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;

  if (gEnableSingleFingerPanEvents) {
    if (aDirection == WidgetGestureNotifyEvent::ePanVertical ||
        aDirection == WidgetGestureNotifyEvent::ePanBoth) {
      config[2].dwWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
      config[2].dwBlock -= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
    }

    if (aDirection == WidgetGestureNotifyEvent::ePanHorizontal ||
        aDirection == WidgetGestureNotifyEvent::ePanBoth) {
      config[2].dwWant |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
      config[2].dwBlock -= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
    }
  }

  config[3].dwWant = GC_TWOFINGERTAP;
  config[3].dwID = GID_TWOFINGERTAP;
  config[3].dwBlock = 0;

  config[4].dwWant = GC_PRESSANDTAP;
  config[4].dwID = GID_PRESSANDTAP;
  config[4].dwBlock = 0;

  return SetGestureConfig(hWnd, 0, GCOUNT, (PGESTURECONFIG)&config,
                          sizeof(GESTURECONFIG));
}

/* Helpers */

bool nsWinGesture::IsPanEvent(LPARAM lParam) {
  GESTUREINFO gi;

  ZeroMemory(&gi, sizeof(GESTUREINFO));
  gi.cbSize = sizeof(GESTUREINFO);

  BOOL result = GetGestureInfo((HGESTUREINFO)lParam, &gi);
  if (!result) return false;

  if (gi.dwID == GID_PAN) return true;

  return false;
}

/* Gesture event processing */

bool nsWinGesture::ProcessGestureMessage(HWND hWnd, WPARAM wParam,
                                         LPARAM lParam,
                                         WidgetSimpleGestureEvent& evt) {
  GESTUREINFO gi;

  ZeroMemory(&gi, sizeof(GESTUREINFO));
  gi.cbSize = sizeof(GESTUREINFO);

  BOOL result = GetGestureInfo((HGESTUREINFO)lParam, &gi);
  if (!result) return false;

  // The coordinates of this event
  nsPointWin coord;
  coord = gi.ptsLocation;
  coord.ScreenToClient(hWnd);

  evt.mRefPoint = LayoutDeviceIntPoint(coord.x, coord.y);

  // Multiple gesture can occur at the same time so gesture state
  // info can't be shared.
  switch (gi.dwID) {
    case GID_BEGIN:
    case GID_END:
      // These should always fall through to DefWndProc
      return false;
      break;

    case GID_ZOOM: {
      if (gi.dwFlags & GF_BEGIN) {
        // Send a zoom start event

        // The low 32 bits are the distance in pixels.
        mZoomIntermediate = (float)gi.ullArguments;

        evt.mMessage = eMagnifyGestureStart;
        evt.mDelta = 0.0;
      } else if (gi.dwFlags & GF_END) {
        // Send a zoom end event, the delta is the change
        // in touch points.
        evt.mMessage = eMagnifyGesture;
        // (positive for a "zoom in")
        evt.mDelta = -1.0 * (mZoomIntermediate - (float)gi.ullArguments);
        mZoomIntermediate = (float)gi.ullArguments;
      } else {
        // Send a zoom intermediate event, the delta is the change
        // in touch points.
        evt.mMessage = eMagnifyGestureUpdate;
        // (positive for a "zoom in")
        evt.mDelta = -1.0 * (mZoomIntermediate - (float)gi.ullArguments);
        mZoomIntermediate = (float)gi.ullArguments;
      }
    } break;

    case GID_ROTATE: {
      // Send a rotate start event
      double radians = 0.0;

      // On GF_BEGIN, ullArguments contains the absolute rotation at the
      // start of the gesture. In later events it contains the offset from
      // the start angle.
      if (gi.ullArguments != 0)
        radians = GID_ROTATE_ANGLE_FROM_ARGUMENT(gi.ullArguments);

      double degrees = -1 * radians * (180 / M_PI);

      if (gi.dwFlags & GF_BEGIN) {
        // At some point we should pass the initial angle in
        // along with delta. It's useful.
        degrees = mRotateIntermediate = 0.0;
      }

      evt.mDirection = 0;
      evt.mDelta = degrees - mRotateIntermediate;
      mRotateIntermediate = degrees;

      if (evt.mDelta > 0) {
        evt.mDirection =
            dom::SimpleGestureEvent_Binding::ROTATION_COUNTERCLOCKWISE;
      } else if (evt.mDelta < 0) {
        evt.mDirection = dom::SimpleGestureEvent_Binding::ROTATION_CLOCKWISE;
      }

      if (gi.dwFlags & GF_BEGIN) {
        evt.mMessage = eRotateGestureStart;
      } else if (gi.dwFlags & GF_END) {
        evt.mMessage = eRotateGesture;
      } else {
        evt.mMessage = eRotateGestureUpdate;
      }
    } break;

    case GID_TWOFINGERTAP:
      // Normally maps to "restore" from whatever you may have recently changed.
      // A simple double click.
      evt.mMessage = eTapGesture;
      evt.mClickCount = 1;
      break;

    case GID_PRESSANDTAP:
      // Two finger right click. Defaults to right click if it falls through.
      evt.mMessage = ePressTapGesture;
      evt.mClickCount = 1;
      break;
  }

  return true;
}

bool nsWinGesture::ProcessPanMessage(HWND hWnd, WPARAM wParam, LPARAM lParam) {
  GESTUREINFO gi;

  ZeroMemory(&gi, sizeof(GESTUREINFO));
  gi.cbSize = sizeof(GESTUREINFO);

  BOOL result = GetGestureInfo((HGESTUREINFO)lParam, &gi);
  if (!result) return false;

  // The coordinates of this event
  nsPointWin coord;
  coord = mPanRefPoint = gi.ptsLocation;
  // We want screen coordinates in our local offsets as client coordinates will
  // change when feedback is taking place. Gui events though require client
  // coordinates.
  mPanRefPoint.ScreenToClient(hWnd);

  switch (gi.dwID) {
    case GID_BEGIN:
    case GID_END:
      // These should always fall through to DefWndProc
      return false;
      break;

    // Setup pixel scroll events for both axis
    case GID_PAN: {
      if (gi.dwFlags & GF_BEGIN) {
        mPanIntermediate = coord;
        mPixelScrollDelta = 0;
        mPanActive = true;
        mPanInertiaActive = false;
      } else {
#ifdef DBG_jimm
        int32_t deltaX = mPanIntermediate.x - coord.x;
        int32_t deltaY = mPanIntermediate.y - coord.y;
        MOZ_LOG(gWindowsLog, LogLevel::Info,
                ("coordX=%d coordY=%d deltaX=%d deltaY=%d x:%d y:%d\n", coord.x,
                 coord.y, deltaX, deltaY, mXAxisFeedback, mYAxisFeedback));
#endif

        mPixelScrollDelta.x = mPanIntermediate.x - coord.x;
        mPixelScrollDelta.y = mPanIntermediate.y - coord.y;
        mPanIntermediate = coord;

        if (gi.dwFlags & GF_INERTIA) mPanInertiaActive = true;

        if (gi.dwFlags & GF_END) {
          mPanActive = false;
          mPanInertiaActive = false;
          PanFeedbackFinalize(hWnd, true);
        }
      }
    } break;
  }
  return true;
}

inline bool TestTransition(int32_t a, int32_t b) {
  // If a is zero, overflow is zero, implying the cursor has moved back to the
  // start position. If b is zero, cached overscroll is zero, implying feedback
  // just begun.
  if (a == 0 || b == 0) return true;
  // Test for different signs.
  return (a < 0) == (b < 0);
}

void nsWinGesture::UpdatePanFeedbackX(HWND hWnd, int32_t scrollOverflow,
                                      bool& endFeedback) {
  // If scroll overflow was returned indicating we panned past the bounds of
  // the scrollable view port, start feeback.
  if (scrollOverflow != 0) {
    if (!mFeedbackActive) {
      BeginPanningFeedback(hWnd);
      mFeedbackActive = true;
    }
    endFeedback = false;
    mXAxisFeedback = true;
    return;
  }

  if (mXAxisFeedback) {
    int32_t newOverflow = mPixelScrollOverflow.x - mPixelScrollDelta.x;

    // Detect a reverse transition past the starting drag point. This tells us
    // the user has panned all the way back so we can stop providing feedback
    // for this axis.
    if (!TestTransition(newOverflow, mPixelScrollOverflow.x) ||
        newOverflow == 0)
      return;

    // Cache the total over scroll in pixels.
    mPixelScrollOverflow.x = newOverflow;
    endFeedback = false;
  }
}

void nsWinGesture::UpdatePanFeedbackY(HWND hWnd, int32_t scrollOverflow,
                                      bool& endFeedback) {
  // If scroll overflow was returned indicating we panned past the bounds of
  // the scrollable view port, start feeback.
  if (scrollOverflow != 0) {
    if (!mFeedbackActive) {
      BeginPanningFeedback(hWnd);
      mFeedbackActive = true;
    }
    endFeedback = false;
    mYAxisFeedback = true;
    return;
  }

  if (mYAxisFeedback) {
    int32_t newOverflow = mPixelScrollOverflow.y - mPixelScrollDelta.y;

    // Detect a reverse transition past the starting drag point. This tells us
    // the user has panned all the way back so we can stop providing feedback
    // for this axis.
    if (!TestTransition(newOverflow, mPixelScrollOverflow.y) ||
        newOverflow == 0)
      return;

    // Cache the total over scroll in pixels.
    mPixelScrollOverflow.y = newOverflow;
    endFeedback = false;
  }
}

void nsWinGesture::PanFeedbackFinalize(HWND hWnd, bool endFeedback) {
  if (!mFeedbackActive) return;

  if (endFeedback) {
    mFeedbackActive = false;
    mXAxisFeedback = false;
    mYAxisFeedback = false;
    mPixelScrollOverflow = 0;
    EndPanningFeedback(hWnd, TRUE);
    return;
  }

  UpdatePanningFeedback(hWnd, mPixelScrollOverflow.x, mPixelScrollOverflow.y,
                        mPanInertiaActive);
}

bool nsWinGesture::PanDeltaToPixelScroll(WidgetWheelEvent& aWheelEvent) {
  aWheelEvent.mDeltaX = aWheelEvent.mDeltaY = aWheelEvent.mDeltaZ = 0.0;
  aWheelEvent.mLineOrPageDeltaX = aWheelEvent.mLineOrPageDeltaY = 0;

  aWheelEvent.mRefPoint = LayoutDeviceIntPoint(mPanRefPoint.x, mPanRefPoint.y);
  aWheelEvent.mDeltaMode = dom::WheelEvent_Binding::DOM_DELTA_PIXEL;
  aWheelEvent.mScrollType = WidgetWheelEvent::SCROLL_SYNCHRONOUSLY;
  aWheelEvent.mIsNoLineOrPageDelta = true;

  aWheelEvent.mOverflowDeltaX = 0.0;
  aWheelEvent.mOverflowDeltaY = 0.0;

  // Don't scroll the view if we are currently at a bounds, or, if we are
  // panning back from a max feedback position. This keeps the original drag
  // point constant.
  if (!mXAxisFeedback) {
    aWheelEvent.mDeltaX = mPixelScrollDelta.x;
  }
  if (!mYAxisFeedback) {
    aWheelEvent.mDeltaY = mPixelScrollDelta.y;
  }

  return (aWheelEvent.mDeltaX != 0 || aWheelEvent.mDeltaY != 0);
}

100%


¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.