I came across a couple posts with some sample code for simulating a single touch mouse click that were derived from some technet docs for doing it in C++. Some others had tried getting the zoom functions to work but were unable and I saw that they weren't building or passing the finger contact parameters properly. These were all very old threads that I didn't want to necro but I've hacked this script together (in 1.3 .. for some reason 2.0 is being cranky but no errors) and it visually shows the gesture registering on the screen however it doesn't actually perform the gesture.
Wondering if anyone has any insight on what might be missing to get it to register. Or if it truly is a lost cause without a touch screen or touchpad.
Note: in it's current state, if you try to perform the action too quickly, the gesture indicators will continue to get stuck on the screen and you''ll have to reload Explorer or reboot to remove them.
Moderator note: DO NOT RUN the following code. It is for reference only. It may affect your desktop in ways that are not easily reversed.
Code: Select all
#Requires AutoHotkey v1.1.33+
^WheelUp::
{
; https://web.archive.org/web/20210531202629/https://www.autohotkey.com/boards/viewtopic.php?f=13&t=2474
; https://web.archive.org/web/20210531202618/https://social.technet.microsoft.com/wiki/contents/articles/6460.simulating-touch-input-in-windows-8-using-touch-injection-api.aspx
; Simulating Tap
; By Tap we mean that it has simply touched any portion of screen. In this use case actor takes two action
; * Touch down on screen co-ordinate input
; * Lifts Up Touch input
; x86 | x64
; 136 | 144 sizeof POINTER_TOUCH_INFO
; 0 | 0 UInt pointerInfo.pointerType
; 4 | 4 UInt pointerInfo.pointerId
; 8 | 8 UInt pointerInfo.frameId
; 12 | 12 UInt pointerInfo.pointerFlags
; 16 | 16 Ptr pointerInfo.sourceDevice
; 20 | 24 Ptr pointerInfo.hwndTarget
; 24 | 32 Int pointerInfo.ptPixelLocation.x
; 28 | 36 Int pointerInfo.ptPixelLocation.y
; 32 | 40 Int pointerInfo.ptHimetricLocation.x
; 36 | 44 Int pointerInfo.ptHimetricLocation.y
; 40 | 48 Int pointerInfo.ptPixelLocationRaw.x
; 44 | 52 Int pointerInfo.ptPixelLocationRaw.y
; 48 | 56 Int pointerInfo.ptHimetricLocationRaw.x
; 52 | 60 Int pointerInfo.ptHimetricLocationRaw.y
; 56 | 64 UInt pointerInfo.dwTime
; 60 | 68 UInt pointerInfo.historyCount
; 64 | 72 Int pointerInfo.InputData
; 68 | 76 UInt pointerInfo.dwKeyStates
; 72 | 80 UInt64 pointerInfo.PerformanceCount
; 80 | 88 Int pointerInfo.ButtonChangeType
; 88 | 96 UInt touchFlags
; 92 | 100 UInt touchMask
; 96 | 104 Int rcContact.left
; 100 | 108 Int rcContact.top
; 104 | 112 Int rcContact.right
; 108 | 116 Int rcContact.bottom
; 112 | 120 Int rcContactRaw.left
; 116 | 124 Int rcContactRaw.top
; 120 | 128 Int rcContactRaw.right
; 124 | 132 Int rcContactRaw.bottom
; 128 | 136 UInt orientation
; 132 | 140 UInt pressure
; enum tagPOINTER_INPUT_TYPE {
; PT_POINTER = 1, // Generic pointer
; PT_TOUCH = 2, // Touch
; PT_PEN = 3, // Pen
; PT_MOUSE = 4, // Mouse
; #if(WINVER >= 0x0603)
; PT_TOUCHPAD = 5, // Touchpad
; #endif /* WINVER >= 0x0603 */
; };
; #define TOUCH_FLAG_NONE 0x00000000 // Default
; #define TOUCH_MASK_NONE 0x00000000 // Default - none of the optional fields are valid
; #define TOUCH_MASK_CONTACTAREA 0x00000001 // The rcContact field is valid
; #define TOUCH_MASK_ORIENTATION 0x00000002 // The orientation field is valid
; #define TOUCH_MASK_PRESSURE 0x00000004 // The pressure field is valid
; #define POINTER_FLAG_NONE 0x00000000 // Default
; #define POINTER_FLAG_NEW 0x00000001 // New pointer
; #define POINTER_FLAG_INRANGE 0x00000002 // Pointer has not departed
; #define POINTER_FLAG_INCONTACT 0x00000004 // Pointer is in contact
; #define POINTER_FLAG_FIRSTBUTTON 0x00000010 // Primary action
; #define POINTER_FLAG_SECONDBUTTON 0x00000020 // Secondary action
; #define POINTER_FLAG_THIRDBUTTON 0x00000040 // Third button
; #define POINTER_FLAG_FOURTHBUTTON 0x00000080 // Fourth button
; #define POINTER_FLAG_FIFTHBUTTON 0x00000100 // Fifth button
; #define POINTER_FLAG_PRIMARY 0x00002000 // Pointer is primary
; #define POINTER_FLAG_CONFIDENCE 0x00004000 // Pointer is considered unlikely to be accidental
; #define POINTER_FLAG_CANCELED 0x00008000 // Pointer is departing in an abnormal manner
; #define POINTER_FLAG_DOWN 0x00010000 // Pointer transitioned to down state (made contact)
; #define POINTER_FLAG_UPDATE 0x00020000 // Pointer update
; #define POINTER_FLAG_UP 0x00040000 // Pointer transitioned from down state (broke contact)
; #define POINTER_FLAG_WHEEL 0x00080000 // Vertical wheel
; #define POINTER_FLAG_HWHEEL 0x00100000 // Horizontal wheel
; #define POINTER_FLAG_CAPTURECHANGED 0x00200000 // Lost capture
; #define POINTER_FLAG_HASTRANSFORM 0x00400000 // Input has a transform associated with it
; WinAPI Constants
; =========================================================================================================================================
PT_TOUCH := 2
PT_TOUCHPAD := 5
TOUCH_FEEDBACK_DEFAULT := 0x1
TOUCH_FEEDBACK_INDIRECT := 0x2
TOUCH_FEEDBACK_NONE := 0x3
TOUCH_FLAG_NONE := 0x00000000
TOUCH_MASK_CONTACTAREA := 0x00000001
TOUCH_MASK_ORIENTATION := 0x00000002
TOUCH_MASK_PRESSURE := 0x00000004
POINTER_FLAG_DOWN := 0x00010000
POINTER_FLAG_INRANGE := 0x00000002
POINTER_FLAG_INCONTACT := 0x00000004
POINTER_FLAG_UPDATE := 0x00020000
POINTER_FLAG_UP := 0x00040000
; =========================================================================================================================================
CONTACTS := 2
PT_MODE := PT_TOUCH
; Array to contain each contact (144 bytes each)
VarSetCapacity(contact, 144*2, 0)
; Center pinch/zoom on current cursor position
MouseGetPos, xpos, ypos
xpos1 := xpos
ypos1 := ypos
xpos2 := xpos1 - 60
xpos1 += 60
ypos2 := ypos1
DllCall("InitializeTouchInjection", "UInt", CONTACTS, "UInt", TOUCH_FEEDBACK_DEFAULT)
; Init first finger - 0 byte offset
; =========================================================================================================================================
NumPut(PT_MODE, contact, 0+0, "UInt")
NumPut(0, contact, 0+4, "UInt")
NumPut(x := xpos1, contact, 0+32, "Int")
NumPut(y := ypos1, contact, 0+36, "Int")
NumPut(TOUCH_FLAG_NONE, contact, 0+96, "UInt")
NumPut(TOUCH_MASK_CONTACTAREA | TOUCH_MASK_ORIENTATION | TOUCH_MASK_PRESSURE, contact, 0+100, "UInt")
NumPut(90, contact, 0+136, "UInt")
NumPut(32000, contact, 0+140, "UInt")
NumPut(x - 2, contact, 0+104, "Int")
NumPut(y - 2, contact, 0+108, "Int")
NumPut(x + 2, contact, 0+112, "Int")
NumPut(y + 2, contact, 0+116, "Int")
NumPut(POINTER_FLAG_DOWN | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT, contact, 0+12, "UInt")
; Init second finger - 144 byte offset
; =========================================================================================================================================
NumPut(PT_MODE, contact, 144+0, "UInt")
NumPut(1, contact, 144+4, "UInt")
NumPut(x := xpos2, contact, 144+32, "Int")
NumPut(y := ypos2, contact, 144+36, "Int")
NumPut(TOUCH_FLAG_NONE, contact, 144+96, "UInt")
NumPut(TOUCH_MASK_CONTACTAREA | TOUCH_MASK_ORIENTATION | TOUCH_MASK_PRESSURE, contact, 144+100, "UInt")
NumPut(90, contact, 144+136, "UInt")
NumPut(32000, contact, 144+140, "UInt")
NumPut(x - 2, contact, 144+104, "Int")
NumPut(y - 2, contact, 144+108, "Int")
NumPut(x + 2, contact, 144+112, "Int")
NumPut(y + 2, contact, 144+116, "Int")
NumPut(POINTER_FLAG_DOWN | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT, contact, 144+12, "UInt")
; Register both fingers touching
; =========================================================================================================================================
DllCall("InjectTouchInput", "UInt", CONTACTS, "Ptr", &contact)
; Mimic fingers spreading to zoom in on X axis
; =========================================================================================================================================
NumPut(POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT, contact, 0+12, "UInt")
NumPut(POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT, contact, 144+12, "UInt")
; Some delays to better see the gesture, loop to simulate fingers moving
Sleep, 100
Loop 50 {
; Trying different directions / speeds of movement.
x1 := xpos1 + (1*A_Index)
x2 := xpos2 - (1*A_Index)
;y1 := ypos1 - (10*A_Index)
;y2 := ypos2 - (10*A_Index)
NumPut(x1, contact, 0+32, "Int")
NumPut(x2, contact, 144+32, "Int")
;NumPut(y1, contact, 0+36, "Int")
;NumPut(y2, contact, 144+36, "Int")
DllCall("InjectTouchInput", "UInt", CONTACTS, "Ptr", &contact)
Sleep, 1
}
; Fingers Up
; =========================================================================================================================================
NumPut(POINTER_FLAG_UP, contact, 0+12, "UInt")
NumPut(POINTER_FLAG_UP, contact, 144+12, "UInt")
DllCall("InjectTouchInput", "UInt", CONTACTS, "Ptr", &contact)
; Return cursor to original position
MouseMove, xpos, ypos
}