This patch adds support for precision touchpad gestures on Windows 8.1 and newer using Direct Manipulation API. Gestures work exactly like on macOS, with full support for pan/pinch and inertia. This works by creating a viewport with a fake scrollable which is reset after every gesture and converts any changes to the content's transform into GHOST trackpad events (as explained [here](https://bugzilla.mozilla.org/show_bug.cgi?id=890878)). The code is based on the implementation from the [Chromium project](https://chromium.googlesource.com/chromium/src/+/refs/heads/master/content/browser/renderer_host/direct_manipulation_helper_win.cc). Tested on Windows 10. Fixes {T70754}, {T69264}. Demo:{F8520272} Reviewed By: nicholas_rishel Differential Revision: https://developer.blender.org/D7660
139 lines
4.4 KiB
C++
139 lines
4.4 KiB
C++
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup GHOST
|
|
* Declaration of GHOST DirectManipulation classes.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#ifndef WIN32
|
|
# error WIN32 only!
|
|
#endif // WIN32
|
|
|
|
#include "GHOST_Types.h"
|
|
|
|
#include <directmanipulation.h>
|
|
#include <wrl.h>
|
|
|
|
#define PINCH_SCALE_FACTOR 125.0f
|
|
|
|
typedef struct {
|
|
int32_t x, y, scale;
|
|
bool isScrollDirectionInverted;
|
|
} GHOST_TTrackpadInfo;
|
|
|
|
class GHOST_DirectManipulationHelper;
|
|
|
|
class GHOST_DirectManipulationViewportEventHandler
|
|
: public Microsoft::WRL::RuntimeClass<
|
|
Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::RuntimeClassType::ClassicCom>,
|
|
Microsoft::WRL::Implements<
|
|
Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::RuntimeClassType::ClassicCom>,
|
|
Microsoft::WRL::FtmBase,
|
|
IDirectManipulationViewportEventHandler>> {
|
|
public:
|
|
GHOST_DirectManipulationViewportEventHandler(uint16_t dpi);
|
|
|
|
/*
|
|
* Resets viewport and tracked touchpad state.
|
|
*/
|
|
void resetViewport(IDirectManipulationViewport *viewport);
|
|
|
|
/* DirectManipulation callbacks. */
|
|
HRESULT STDMETHODCALLTYPE OnViewportStatusChanged(IDirectManipulationViewport *viewport,
|
|
DIRECTMANIPULATION_STATUS current,
|
|
DIRECTMANIPULATION_STATUS previous) override;
|
|
|
|
HRESULT STDMETHODCALLTYPE OnViewportUpdated(IDirectManipulationViewport *viewport) override;
|
|
|
|
HRESULT STDMETHODCALLTYPE OnContentUpdated(IDirectManipulationViewport *viewport,
|
|
IDirectManipulationContent *content) override;
|
|
|
|
private:
|
|
enum { GESTURE_NONE, GESTURE_PAN, GESTURE_PINCH } gesture_state;
|
|
|
|
int32_t last_x, last_y, last_scale;
|
|
GHOST_TTrackpadInfo accumulated_values;
|
|
uint16_t dpi;
|
|
DIRECTMANIPULATION_STATUS dm_status;
|
|
|
|
friend class GHOST_DirectManipulationHelper;
|
|
};
|
|
|
|
class GHOST_DirectManipulationHelper {
|
|
public:
|
|
/*
|
|
* Creates a GHOST_DirectManipulationHelper for the provided window.
|
|
* \param hWnd: The window receiving DirectManipulation events.
|
|
* \param dpi: The current DPI.
|
|
* \return Pointer to the new GHOST_DirectManipulationHelper if created, nullptr if there was an
|
|
* error.
|
|
*/
|
|
static GHOST_DirectManipulationHelper *create(HWND hWnd, uint16_t dpi);
|
|
|
|
~GHOST_DirectManipulationHelper();
|
|
|
|
/*
|
|
* Drives the DirectManipulation context.
|
|
* DirectManipulation's intended use is to tie user input into DirectComposition's compositor
|
|
* scaling and translating. We are not using DirectComposition and therefore must drive
|
|
* DirectManipulation manually.
|
|
*/
|
|
void update();
|
|
|
|
/*
|
|
* Sets pointer in contact with the DirectManipulation context.
|
|
* \param pointerId: ID of the pointer in contact.
|
|
*/
|
|
void onPointerHitTest(UINT32 pointerId);
|
|
|
|
/*
|
|
* Updates DPI information for touchpad scaling.
|
|
* \param dpi: The new DPI.
|
|
*/
|
|
void setDPI(uint16_t dpi);
|
|
|
|
/*
|
|
* Retrieves trackpad input.
|
|
* \return The accumulated trackpad translation and scale since last call.
|
|
*/
|
|
GHOST_TTrackpadInfo getTrackpadInfo();
|
|
|
|
private:
|
|
GHOST_DirectManipulationHelper(
|
|
HWND hWnd,
|
|
Microsoft::WRL::ComPtr<IDirectManipulationManager> directManipulationManager,
|
|
Microsoft::WRL::ComPtr<IDirectManipulationUpdateManager> directManipulationUpdateManager,
|
|
Microsoft::WRL::ComPtr<IDirectManipulationViewport> directManipulationViewport,
|
|
Microsoft::WRL::ComPtr<GHOST_DirectManipulationViewportEventHandler>
|
|
directManipulationEventHandler,
|
|
DWORD directManipulationViewportHandlerCookie,
|
|
bool isScrollDirectionInverted);
|
|
|
|
/*
|
|
* Retrieves the scroll direction from the registry.
|
|
* \return True if scroll direction is inverted.
|
|
*/
|
|
static bool getScrollDirectionFromReg();
|
|
|
|
/*
|
|
* Registers listener for registry scroll direction entry changes.
|
|
*/
|
|
void registerScrollDirectionChangeListener();
|
|
|
|
HWND m_hWnd;
|
|
|
|
HKEY m_scrollDirectionRegKey;
|
|
HANDLE m_scrollDirectionChangeEvent;
|
|
|
|
Microsoft::WRL::ComPtr<IDirectManipulationManager> m_directManipulationManager;
|
|
Microsoft::WRL::ComPtr<IDirectManipulationUpdateManager> m_directManipulationUpdateManager;
|
|
Microsoft::WRL::ComPtr<IDirectManipulationViewport> m_directManipulationViewport;
|
|
Microsoft::WRL::ComPtr<GHOST_DirectManipulationViewportEventHandler>
|
|
m_directManipulationEventHandler;
|
|
DWORD m_directManipulationViewportHandlerCookie;
|
|
|
|
bool m_isScrollDirectionInverted;
|
|
};
|