24#if defined( __MINGW32__ )
31std::unique_ptr<KIPLATFORM::UI::TOUCHPAD_GESTURE_HANDLER>
38#include <InteractionContext.h>
62 m_inputWindow( aInputWindow ),
63 m_callback( std::
move( aCallback ) )
68 ~MSW_TOUCHPAD_GESTURE_HANDLER()
override
71 m_registerTouchpadCapableWindow( getHwnd(), FALSE );
74 m_removeWindowSubclass( getHwnd(), windowProc, SUBCLASS_ID );
77 m_destroyInteractionContext( m_context );
80 FreeLibrary( m_ninput );
83 FreeLibrary( m_comctl32 );
86 bool IsActive()
const {
return m_registered && m_subclassed; }
89 using REGISTER_TOUCHPAD_CAPABLE_WINDOW = BOOL( WINAPI* )( HWND, BOOL );
90 using GET_POINTER_FRAME_TOUCHPAD_INFO_HISTORY = BOOL( WINAPI* )( UINT32, UINT32*, UINT32*, POINTER_TOUCH_INFO* );
91 using CREATE_INTERACTION_CONTEXT = HRESULT( WINAPI* )( HINTERACTIONCONTEXT* );
92 using DESTROY_INTERACTION_CONTEXT = HRESULT( WINAPI* )( HINTERACTIONCONTEXT );
93 using REGISTER_OUTPUT_CALLBACK = HRESULT( WINAPI* )( HINTERACTIONCONTEXT, INTERACTION_CONTEXT_OUTPUT_CALLBACK,
95 using SET_INTERACTION_CONFIGURATION = HRESULT( WINAPI* )( HINTERACTIONCONTEXT, UINT32,
96 const INTERACTION_CONTEXT_CONFIGURATION* );
97 using SET_INTERACTION_PROPERTY = HRESULT( WINAPI* )( HINTERACTIONCONTEXT, INTERACTION_CONTEXT_PROPERTY, UINT32 );
98 using PROCESS_POINTER_FRAMES_INTERACTION_CONTEXT2 = HRESULT( WINAPI* )( HINTERACTIONCONTEXT, UINT32, UINT32,
99 const POINTER_TYPE_INFO* );
100 using SET_WINDOW_SUBCLASS = BOOL( WINAPI* )( HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR );
101 using REMOVE_WINDOW_SUBCLASS = BOOL( WINAPI* )( HWND, SUBCLASSPROC, UINT_PTR );
102 using DEF_SUBCLASS_PROC = LRESULT( WINAPI* )( HWND, UINT, WPARAM, LPARAM );
105#pragma warning( push )
106#pragma warning( disable : 4191 )
109 template <
typename T>
110 static T loadNamedProc( HMODULE aModule,
const char* aName )
112 return reinterpret_cast<T>( GetProcAddress( aModule, aName ) );
115 template <
typename T>
116 static T loadOrdinalProc( HMODULE aModule, WORD aOrdinal )
118 return reinterpret_cast<T>( GetProcAddress( aModule, MAKEINTRESOURCEA( aOrdinal ) ) );
122#pragma warning( pop )
125 HWND getHwnd()
const {
return reinterpret_cast<HWND
>( m_inputWindow->GetHandle() ); }
129 HMODULE user32 = GetModuleHandleW(
L"user32.dll" );
130 m_ninput = LoadLibraryExW(
L"ninput.dll",
nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32 );
131 m_comctl32 = LoadLibraryExW(
L"comctl32.dll",
nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32 );
133 if( !user32 || !m_ninput || !m_comctl32 )
136 m_registerTouchpadCapableWindow = loadOrdinalProc<REGISTER_TOUCHPAD_CAPABLE_WINDOW>( user32, 2689 );
137 m_getPointerFrameTouchpadInfoHistory = loadOrdinalProc<GET_POINTER_FRAME_TOUCHPAD_INFO_HISTORY>( user32, 2694 );
138 m_processPointerFramesInteractionContext2 =
139 loadOrdinalProc<PROCESS_POINTER_FRAMES_INTERACTION_CONTEXT2>( m_ninput, 2507 );
140 m_createInteractionContext = loadNamedProc<CREATE_INTERACTION_CONTEXT>( m_ninput,
"CreateInteractionContext" );
141 m_destroyInteractionContext =
142 loadNamedProc<DESTROY_INTERACTION_CONTEXT>( m_ninput,
"DestroyInteractionContext" );
143 m_registerOutputCallback =
144 loadNamedProc<REGISTER_OUTPUT_CALLBACK>( m_ninput,
"RegisterOutputCallbackInteractionContext" );
145 m_setInteractionConfiguration = loadNamedProc<SET_INTERACTION_CONFIGURATION>(
146 m_ninput,
"SetInteractionConfigurationInteractionContext" );
147 m_setInteractionProperty = loadNamedProc<SET_INTERACTION_PROPERTY>( m_ninput,
"SetPropertyInteractionContext" );
148 m_setWindowSubclass = loadNamedProc<SET_WINDOW_SUBCLASS>( m_comctl32,
"SetWindowSubclass" );
149 m_removeWindowSubclass = loadNamedProc<REMOVE_WINDOW_SUBCLASS>( m_comctl32,
"RemoveWindowSubclass" );
150 m_defSubclassProc = loadNamedProc<DEF_SUBCLASS_PROC>( m_comctl32,
"DefSubclassProc" );
152 if( !m_registerTouchpadCapableWindow || !m_getPointerFrameTouchpadInfoHistory
153 || !m_processPointerFramesInteractionContext2 || !m_createInteractionContext || !m_destroyInteractionContext
154 || !m_registerOutputCallback || !m_setInteractionConfiguration || !m_setInteractionProperty
155 || !m_setWindowSubclass || !m_removeWindowSubclass || !m_defSubclassProc )
160 if( FAILED( m_createInteractionContext( &m_context ) ) )
163 if( FAILED( m_registerOutputCallback( m_context, outputCallback,
this ) ) )
166 INTERACTION_CONTEXT_CONFIGURATION configuration = {
167 INTERACTION_ID_MANIPULATION, INTERACTION_CONFIGURATION_FLAG_MANIPULATION
168 | INTERACTION_CONFIGURATION_FLAG_MANIPULATION_TRANSLATION_X
169 | INTERACTION_CONFIGURATION_FLAG_MANIPULATION_TRANSLATION_Y
170 | INTERACTION_CONFIGURATION_FLAG_MANIPULATION_SCALING
171 | INTERACTION_CONFIGURATION_FLAG_MANIPULATION_RAILS_X
172 | INTERACTION_CONFIGURATION_FLAG_MANIPULATION_RAILS_Y
173 | INTERACTION_CONFIGURATION_FLAG_MANIPULATION_MULTIPLE_FINGER_PANNING
176 if( FAILED( m_setInteractionConfiguration( m_context, 1, &configuration ) ) )
181 if( FAILED( m_setInteractionProperty( m_context, INTERACTION_CONTEXT_PROPERTY_MEASUREMENT_UNITS, 0 ) )
182 || FAILED( m_setInteractionProperty( m_context, INTERACTION_CONTEXT_PROPERTY_FILTER_POINTERS, FALSE ) ) )
187 m_registered = m_registerTouchpadCapableWindow( getHwnd(), TRUE ) != FALSE;
192 if( !m_setWindowSubclass( getHwnd(), windowProc, SUBCLASS_ID,
reinterpret_cast<DWORD_PTR
>(
this ) ) )
194 m_registerTouchpadCapableWindow( getHwnd(), FALSE );
195 m_registered =
false;
202 bool handleMessage( UINT aMessage, WPARAM aWParam )
205 || ( aMessage != WM_POINTERDOWN && aMessage != WM_POINTERUPDATE && aMessage != WM_POINTERUP ) )
210 const UINT32 pointerId = GET_POINTERID_WPARAM( aWParam );
211 POINTER_INFO pointerInfo = {};
213 if( !GetPointerInfo( pointerId, &pointerInfo ) || pointerInfo.pointerType != PT_TOUCHPAD )
216 UINT32 frameCount = 0;
217 UINT32 pointerCount = 0;
219 if( !m_getPointerFrameTouchpadInfoHistory( pointerId, &frameCount, &pointerCount,
nullptr ) || frameCount == 0
220 || pointerCount == 0 || frameCount > std::numeric_limits<size_t>::max() / pointerCount )
225 const size_t entryCount =
static_cast<size_t>( frameCount ) * pointerCount;
229 if( entryCount > 65536 )
232 std::vector<POINTER_TOUCH_INFO> touchInfos( entryCount );
234 if( !m_getPointerFrameTouchpadInfoHistory( pointerId, &frameCount, &pointerCount, touchInfos.data() ) )
237 const size_t filledEntryCount =
static_cast<size_t>( frameCount ) * pointerCount;
239 if( filledEntryCount > touchInfos.size() )
242 std::vector<POINTER_TYPE_INFO> typeInfos( filledEntryCount );
244 for(
size_t i = 0; i < filledEntryCount; ++i )
246 typeInfos[i].type = touchInfos[i].pointerInfo.pointerType;
247 typeInfos[i].touchInfo = touchInfos[i];
250 if( FAILED( m_processPointerFramesInteractionContext2( m_context, frameCount, pointerCount,
251 typeInfos.data() ) ) )
257 SkipPointerFrameMessages( pointerId );
261 static LRESULT
CALLBACK windowProc( HWND aHwnd, UINT aMessage, WPARAM aWParam, LPARAM aLParam, UINT_PTR,
262 DWORD_PTR aReferenceData )
264 auto* handler =
reinterpret_cast<MSW_TOUCHPAD_GESTURE_HANDLER*
>( aReferenceData );
268 if( handler && handler->handleMessage( aMessage, aWParam ) )
276 if( handler && handler->m_defSubclassProc )
277 return handler->m_defSubclassProc( aHwnd, aMessage, aWParam, aLParam );
279 return DefWindowProcW( aHwnd, aMessage, aWParam, aLParam );
282 static void CALLBACK outputCallback(
void* aClientData,
const INTERACTION_CONTEXT_OUTPUT* aOutput )
286 static_cast<MSW_TOUCHPAD_GESTURE_HANDLER*
>( aClientData )->onOutput( aOutput );
294 void onOutput(
const INTERACTION_CONTEXT_OUTPUT* aOutput )
296 if( !aOutput || aOutput->interactionId != INTERACTION_ID_MANIPULATION || aOutput->inputType != PT_TOUCHPAD )
301 const wxSize dpi = m_inputWindow->GetDPI();
302 constexpr double HIMETRIC_PER_INCH = 2540.0;
303 const double pixelsPerHimetricX = ( dpi.x > 0 ? dpi.x : 96 ) / HIMETRIC_PER_INCH;
304 const double pixelsPerHimetricY = ( dpi.y > 0 ? dpi.y : 96 ) / HIMETRIC_PER_INCH;
305 const MANIPULATION_TRANSFORM&
delta = aOutput->arguments.manipulation.delta;
307 POINT cursorPosition = {};
309 if( !GetCursorPos( &cursorPosition ) || !ScreenToClient( getHwnd(), &cursorPosition ) )
312 m_callback( {
delta.translationX * pixelsPerHimetricX,
delta.translationY * pixelsPerHimetricY,
delta.scale,
313 wxPoint( cursorPosition.x, cursorPosition.y ) } );
316 static constexpr UINT_PTR SUBCLASS_ID = 1;
318 wxWindow* m_inputWindow =
nullptr;
320 HMODULE m_ninput =
nullptr;
321 HMODULE m_comctl32 =
nullptr;
322 HINTERACTIONCONTEXT m_context =
nullptr;
323 REGISTER_TOUCHPAD_CAPABLE_WINDOW m_registerTouchpadCapableWindow =
nullptr;
324 GET_POINTER_FRAME_TOUCHPAD_INFO_HISTORY m_getPointerFrameTouchpadInfoHistory =
nullptr;
325 CREATE_INTERACTION_CONTEXT m_createInteractionContext =
nullptr;
326 DESTROY_INTERACTION_CONTEXT m_destroyInteractionContext =
nullptr;
327 REGISTER_OUTPUT_CALLBACK m_registerOutputCallback =
nullptr;
328 SET_INTERACTION_CONFIGURATION m_setInteractionConfiguration =
nullptr;
329 SET_INTERACTION_PROPERTY m_setInteractionProperty =
nullptr;
330 PROCESS_POINTER_FRAMES_INTERACTION_CONTEXT2 m_processPointerFramesInteractionContext2 =
nullptr;
331 SET_WINDOW_SUBCLASS m_setWindowSubclass =
nullptr;
332 REMOVE_WINDOW_SUBCLASS m_removeWindowSubclass =
nullptr;
333 DEF_SUBCLASS_PROC m_defSubclassProc =
nullptr;
334 bool m_registered =
false;
335 bool m_subclassed =
false;
342 HMODULE user32 = GetModuleHandleW(
L"user32.dll" );
343 HMODULE ninput = LoadLibraryExW(
L"ninput.dll",
nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32 );
344 HMODULE comctl32 = LoadLibraryExW(
L"comctl32.dll",
nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32 );
346 const bool available =
347 user32 && ninput && comctl32 && GetProcAddress( user32, MAKEINTRESOURCEA( 2689 ) )
348 && GetProcAddress( user32, MAKEINTRESOURCEA( 2694 ) ) && GetProcAddress( ninput, MAKEINTRESOURCEA( 2507 ) )
349 && GetProcAddress( ninput,
"CreateInteractionContext" )
350 && GetProcAddress( ninput,
"DestroyInteractionContext" )
351 && GetProcAddress( ninput,
"RegisterOutputCallbackInteractionContext" )
352 && GetProcAddress( ninput,
"SetInteractionConfigurationInteractionContext" )
353 && GetProcAddress( ninput,
"SetPropertyInteractionContext" )
354 && GetProcAddress( comctl32,
"SetWindowSubclass" ) && GetProcAddress( comctl32,
"RemoveWindowSubclass" )
355 && GetProcAddress( comctl32,
"DefSubclassProc" );
358 FreeLibrary( ninput );
361 FreeLibrary( comctl32 );
367std::unique_ptr<KIPLATFORM::UI::TOUCHPAD_GESTURE_HANDLER>
370 if( !aInputWindow || !aCallback )
373 auto handler = std::make_unique<MSW_TOUCHPAD_GESTURE_HANDLER>( aInputWindow, std::move( aCallback ) );
375 if( !handler->IsActive() )
#define CALLBACK
The default number of points for circle approximation.