Emulate Touch Event in Windows 8 using Python
Question:
I am trying to write a sort of driver using python for windows 8. I will be receiving touch coordinates via serial which I then want to use to make it appear as though someone touched those coordinates on the screen (emulate a touch).
My first question is:
Is a touch event in Windows 8 different from just a mouse click at the area? (I know they revamped everything for touch events but am unsure of what that involved — possibly like an area of effect thing to make it more touch screen friendly?)
Secondly:
If so, is there a library for python to emulate a ‘touch’ at a coordinate instead of a ‘click’?
UPDATE:
Using ctypes and the page linked in the comments, I have created this:
from ctypes import *
#Constants
#For touchMask
TOUCH_MASK_NONE= 0x00000000 #Default
TOUCH_MASK_CONTACTAREA= 0x00000001
TOUCH_MASK_ORIENTATION= 0x00000002
TOUCH_MASK_PRESSURE= 0x00000004
TOUCH_MASK_ALL= 0x00000007
#For touchFlag
TOUCH_FLAG_NONE= 0x00000000
#For pointerType
PT_POINTER= 0x00000001#All
PT_TOUCH= 0x00000002
PT_PEN= 0x00000003
PT_MOUSE= 0x00000004
#For pointerFlags
POINTER_FLAG_NONE= 0x00000000#Default
POINTER_FLAG_NEW= 0x00000001
POINTER_FLAG_INRANGE= 0x00000002
POINTER_FLAG_INCONTACT= 0x00000004
POINTER_FLAG_FIRSTBUTTON= 0x00000010
POINTER_FLAG_SECONDBUTTON=0x00000020
POINTER_FLAG_THIRDBUTTON= 0x00000040
POINTER_FLAG_FOURTHBUTTON=0x00000080
POINTER_FLAG_FIFTHBUTTON= 0x00000100
POINTER_FLAG_PRIMARY= 0x00002000
POINTER_FLAG_CONFIDENCE= 0x00004000
POINTER_FLAG_CANCELED= 0x00008000
POINTER_FLAG_DOWN= 0x00010000
POINTER_FLAG_UPDATE= 0x00020000
POINTER_FLAG_UP= 0x00040000
POINTER_FLAG_WHEEL= 0x00080000
POINTER_FLAG_HWHEEL= 0x00100000
POINTER_FLAG_CAPTURECHANGED=0x00200000
#Structs Needed
class POINT(Structure):
_fields_=[("x", c_long),
("y", c_long)]
class POINTER_INFO(Structure):
_fields_=[("pointerType",c_int32),
("pointerId",c_uint32),
("frameId",c_uint32),
("pointerFlags",c_int),
("sourceDevice",c_uint32),
("hwndTarget",c_uint32),
("ptPixelLocation",POINT),
("ptHimetricLocation",POINT),
("ptPixelLocationRaw",POINT),
("ptHimetricLocationRaw",POINT),
("dwTime",c_uint32),
("historyCount",c_uint32),
("inputData",c_int32),
("dwKeyStates",c_uint32),
("PerformanceCount",c_uint64),
("ButtonChangeType",c_int)
]
class RECT(Structure):
_fields_=[("left",c_long),
("top",c_long),
("right",c_long),
("bottom",c_long)]
class POINTER_TOUCH_INFO(Structure):
_fields_=[("pointerInfo",POINTER_INFO),
("touchFlags",c_int),
("touchMask",c_int),
("rcContact", RECT),
("rcContactRaw",RECT),
("orientation", c_uint32),
("pressure", c_uint32)]
#Initialize Touch Injection
pointerInfo=POINTER_INFO(pointerType=PT_TOUCH,
pointerId=0,
ptPixelLocation=POINT(950,540))
touchInfo=POINTER_TOUCH_INFO(pointerInfo=pointerInfo,
touchFlags=TOUCH_FLAG_NONE,
touchMask=TOUCH_MASK_ALL,
rcContact=RECT(pointerInfo.ptPixelLocation.x-5,
pointerInfo.ptPixelLocation.y-5,
pointerInfo.ptPixelLocation.x+5,
pointerInfo.ptPixelLocation.y+5),
orientation=90,
pressure=32000)
if (windll.user32.InitializeTouchInjection(1,1) != 0):
print "Initialized Touch Injection"
#Press Down
touchInfo.pointerInfo.pointerFlags=(POINTER_FLAG_DOWN|
POINTER_FLAG_INRANGE|
POINTER_FLAG_INCONTACT)
if (windll.user32.InjectTouchInput(1, byref(touchInfo))==0):
print "Failed with Error: "+ FormatError()
else:
print "Touch Down Succeeded!"
#Pull Up
touchInfo.pointerInfo.pointerFlags=POINTER_FLAG_UP
if (windll.user32.InjectTouchInput(1,byref(touchInfo))==0):
print "Failed with Error: "+FormatError()
else:
print "Pull Up Succeeded!"
Fails everytime with error about the input parameters.
I’ve gone through every reference and can’t find a type that seems incorrect. Does anyone see something obvious?
Thanks
Answers:
Thanks to Eryksum and Xyroid, I was able to get it working. Thanks for putting up with my C-type / Windows ignorance. Here is the final script with the touch emulation packaged as a function (extra constants as well):
from ctypes import *
from ctypes.wintypes import *
#Constants
#For touchMask
TOUCH_MASK_NONE= 0x00000000 #Default
TOUCH_MASK_CONTACTAREA= 0x00000001
TOUCH_MASK_ORIENTATION= 0x00000002
TOUCH_MASK_PRESSURE= 0x00000004
TOUCH_MASK_ALL= 0x00000007
#For touchFlag
TOUCH_FLAG_NONE= 0x00000000
#For pointerType
PT_POINTER= 0x00000001#All
PT_TOUCH= 0x00000002
PT_PEN= 0x00000003
PT_MOUSE= 0x00000004
#For pointerFlags
POINTER_FLAG_NONE= 0x00000000#Default
POINTER_FLAG_NEW= 0x00000001
POINTER_FLAG_INRANGE= 0x00000002
POINTER_FLAG_INCONTACT= 0x00000004
POINTER_FLAG_FIRSTBUTTON= 0x00000010
POINTER_FLAG_SECONDBUTTON=0x00000020
POINTER_FLAG_THIRDBUTTON= 0x00000040
POINTER_FLAG_FOURTHBUTTON=0x00000080
POINTER_FLAG_FIFTHBUTTON= 0x00000100
POINTER_FLAG_PRIMARY= 0x00002000
POINTER_FLAG_CONFIDENCE= 0x00004000
POINTER_FLAG_CANCELED= 0x00008000
POINTER_FLAG_DOWN= 0x00010000
POINTER_FLAG_UPDATE= 0x00020000
POINTER_FLAG_UP= 0x00040000
POINTER_FLAG_WHEEL= 0x00080000
POINTER_FLAG_HWHEEL= 0x00100000
POINTER_FLAG_CAPTURECHANGED=0x00200000
#Structs Needed
class POINTER_INFO(Structure):
_fields_=[("pointerType",c_uint32),
("pointerId",c_uint32),
("frameId",c_uint32),
("pointerFlags",c_int),
("sourceDevice",HANDLE),
("hwndTarget",HWND),
("ptPixelLocation",POINT),
("ptHimetricLocation",POINT),
("ptPixelLocationRaw",POINT),
("ptHimetricLocationRaw",POINT),
("dwTime",DWORD),
("historyCount",c_uint32),
("inputData",c_int32),
("dwKeyStates",DWORD),
("PerformanceCount",c_uint64),
("ButtonChangeType",c_int)
]
class POINTER_TOUCH_INFO(Structure):
_fields_=[("pointerInfo",POINTER_INFO),
("touchFlags",c_int),
("touchMask",c_int),
("rcContact", RECT),
("rcContactRaw",RECT),
("orientation", c_uint32),
("pressure", c_uint32)]
#Initialize Pointer and Touch info
pointerInfo=POINTER_INFO(pointerType=PT_TOUCH,
pointerId=0,
ptPixelLocation=POINT(950,540))
touchInfo=POINTER_TOUCH_INFO(pointerInfo=pointerInfo,
touchFlags=TOUCH_FLAG_NONE,
touchMask=TOUCH_MASK_ALL,
rcContact=RECT(pointerInfo.ptPixelLocation.x-5,
pointerInfo.ptPixelLocation.y-5,
pointerInfo.ptPixelLocation.x+5,
pointerInfo.ptPixelLocation.y+5),
orientation=90,
pressure=32000)
def makeTouch(x,y,fingerRadius):
touchInfo.pointerInfo.ptPixelLocation.x=x
touchInfo.pointerInfo.ptPixelLocation.y=y
touchInfo.rcContact.left=x-fingerRadius
touchInfo.rcContact.right=x+fingerRadius
touchInfo.rcContact.top=y-fingerRadius
touchInfo.rcContact.bottom=y+fingerRadius
#Initialize Touch Injection
if (windll.user32.InitializeTouchInjection(1,1) != 0):
print "Initialized Touch Injection"
#Press Down
touchInfo.pointerInfo.pointerFlags=(POINTER_FLAG_DOWN|
POINTER_FLAG_INRANGE|
POINTER_FLAG_INCONTACT)
if (windll.user32.InjectTouchInput(1, byref(touchInfo))==0):
print "Failed with Error: "+ FormatError()
else:
print "Touch Down Succeeded!"
#Pull Up
touchInfo.pointerInfo.pointerFlags=POINTER_FLAG_UP
if (windll.user32.InjectTouchInput(1,byref(touchInfo))==0):
print "Failed with Error: "+FormatError()
else:
print "Pull Up Succeeded!"
return
#Ex:
#makeTouch(950,270,5)
For future multitouch travelers, the above example needs some significant massaging to create multiple touch events with a proper lifetime.
This includes maintaining persistent POINTER_TOUCH_INFO
arrays, setting their ID’s appropriately, and properly calling DOWN
, UPDATE
, and UP
events as needed.
Hopefully this addition to the example script will save others time:
from ctypes import *
from ctypes.wintypes import *
# Constants
# For touchMask
TOUCH_MASK_NONE= 0x00000000 # Default
TOUCH_MASK_CONTACTAREA= 0x00000001
TOUCH_MASK_ORIENTATION= 0x00000002
TOUCH_MASK_PRESSURE= 0x00000004
TOUCH_MASK_ALL= 0x00000007
# For touchFlag
TOUCH_FLAG_NONE= 0x00000000
# For pointerType
PT_POINTER= 0x00000001 # All
PT_TOUCH= 0x00000002
PT_PEN= 0x00000003
PT_MOUSE= 0x00000004
#For pointerFlags
POINTER_FLAG_NONE= 0x00000000 # Default
POINTER_FLAG_NEW= 0x00000001
POINTER_FLAG_INRANGE= 0x00000002
POINTER_FLAG_INCONTACT= 0x00000004
POINTER_FLAG_FIRSTBUTTON= 0x00000010
POINTER_FLAG_SECONDBUTTON=0x00000020
POINTER_FLAG_THIRDBUTTON= 0x00000040
POINTER_FLAG_FOURTHBUTTON=0x00000080
POINTER_FLAG_FIFTHBUTTON= 0x00000100
POINTER_FLAG_PRIMARY= 0x00002000
POINTER_FLAG_CONFIDENCE= 0x00004000
POINTER_FLAG_CANCELED= 0x00008000
POINTER_FLAG_DOWN= 0x00010000
POINTER_FLAG_UPDATE= 0x00020000
POINTER_FLAG_UP= 0x00040000
POINTER_FLAG_WHEEL= 0x00080000
POINTER_FLAG_HWHEEL= 0x00100000
POINTER_FLAG_CAPTURECHANGED=0x00200000
# Structs Needed
class POINTER_INFO(Structure):
_fields_=[("pointerType",c_uint32),
("pointerId",c_uint32),
("frameId",c_uint32),
("pointerFlags",c_int),
("sourceDevice",HANDLE),
("hwndTarget",HWND),
("ptPixelLocation",POINT),
("ptHimetricLocation",POINT),
("ptPixelLocationRaw",POINT),
("ptHimetricLocationRaw",POINT),
("dwTime",DWORD),
("historyCount",c_uint32),
("inputData",c_int32),
("dwKeyStates",DWORD),
("PerformanceCount",c_uint64),
("ButtonChangeType",c_int)
]
class POINTER_TOUCH_INFO(Structure):
_fields_=[("pointerInfo",POINTER_INFO),
("touchFlags",c_int),
("touchMask",c_int),
("rcContact", RECT),
("rcContactRaw",RECT),
("orientation", c_uint32),
("pressure", c_uint32)]
# Initialize Pointer and Touch info
def initialize(maxtouches=10, dwmode=1):
global touches
touches = (POINTER_TOUCH_INFO * maxtouches)()
for ind in range(maxtouches):
pointerInfo=POINTER_INFO(pointerType = PT_TOUCH,
pointerId = ind,
ptPixelLocation = POINT(950,540),
pointerFlags = POINTER_FLAG_NEW)
touchInfo=POINTER_TOUCH_INFO(pointerInfo = pointerInfo,
touchFlags = TOUCH_FLAG_NONE,
touchMask = TOUCH_MASK_ALL,
rcContact = RECT(pointerInfo.ptPixelLocation.x-5,
pointerInfo.ptPixelLocation.y-5,
pointerInfo.ptPixelLocation.x+5,
pointerInfo.ptPixelLocation.y+5),
orientation = 90,
pressure = 32000)
touches[ind] = touchInfo
if (windll.user32.InitializeTouchInjection(len(touches), 1) != 0):
print("Initialized Touch Injection")
ids_to_update = 0
currently_down = None
def updateTouchInfo(id, down, x = 0, y = 0, fingerRadius=1, orientation = 90, pressure = 32000):
global currently_down, ids_to_update
if currently_down == None or len(currently_down) != len(touches):
currently_down = [False] * len(touches)
if down:
touches[id].pointerInfo.pointerFlags = (((POINTER_FLAG_DOWN) if not currently_down[id] else POINTER_FLAG_UPDATE)|
POINTER_FLAG_INRANGE |
POINTER_FLAG_INCONTACT)
touches[id].orientation = orientation
touches[id].pressure = pressure
touches[id].pointerInfo.ptPixelLocation.x = x
touches[id].pointerInfo.ptPixelLocation.y = y
touches[id].rcContact.left = x - fingerRadius
touches[id].rcContact.right = x + fingerRadius
touches[id].rcContact.top = y - fingerRadius
touches[id].rcContact.bottom = y + fingerRadius
else:
touches[id].pointerInfo.pointerFlags = POINTER_FLAG_UP #if currently_down[id] else POINTER_FLAG_UPDATE #if currently_down[id] else POINTER_FLAG_UPDATE
ids_to_update += 1 if down or currently_down[id] else 0
currently_down[id] = down
def applyTouches():
global ids_to_update
if ids_to_update > 0:
if (windll.user32.InjectTouchInput(int(ids_to_update), byref(touches[0])) == 0):
print("Failed trying to update", ids_to_update, "points with Error:", FormatError())
ids_to_update = 0
# Use like:
#import multitouch # Call once
#multitouch.initialize() # Call once
#for i in range(10): # Call every frame
# if i < len(keypoints):
# multitouch.updateTouchInfo(i, True,
# int(keypoints[i].pt[0] * 3),
# int(keypoints[i].pt[1] * 3),
# int(keypoints[i].size / 2))
# else:
# multitouch.updateTouchInfo(i, False)
#multitouch.applyTouches()
I am trying to write a sort of driver using python for windows 8. I will be receiving touch coordinates via serial which I then want to use to make it appear as though someone touched those coordinates on the screen (emulate a touch).
My first question is:
Is a touch event in Windows 8 different from just a mouse click at the area? (I know they revamped everything for touch events but am unsure of what that involved — possibly like an area of effect thing to make it more touch screen friendly?)
Secondly:
If so, is there a library for python to emulate a ‘touch’ at a coordinate instead of a ‘click’?
UPDATE:
Using ctypes and the page linked in the comments, I have created this:
from ctypes import *
#Constants
#For touchMask
TOUCH_MASK_NONE= 0x00000000 #Default
TOUCH_MASK_CONTACTAREA= 0x00000001
TOUCH_MASK_ORIENTATION= 0x00000002
TOUCH_MASK_PRESSURE= 0x00000004
TOUCH_MASK_ALL= 0x00000007
#For touchFlag
TOUCH_FLAG_NONE= 0x00000000
#For pointerType
PT_POINTER= 0x00000001#All
PT_TOUCH= 0x00000002
PT_PEN= 0x00000003
PT_MOUSE= 0x00000004
#For pointerFlags
POINTER_FLAG_NONE= 0x00000000#Default
POINTER_FLAG_NEW= 0x00000001
POINTER_FLAG_INRANGE= 0x00000002
POINTER_FLAG_INCONTACT= 0x00000004
POINTER_FLAG_FIRSTBUTTON= 0x00000010
POINTER_FLAG_SECONDBUTTON=0x00000020
POINTER_FLAG_THIRDBUTTON= 0x00000040
POINTER_FLAG_FOURTHBUTTON=0x00000080
POINTER_FLAG_FIFTHBUTTON= 0x00000100
POINTER_FLAG_PRIMARY= 0x00002000
POINTER_FLAG_CONFIDENCE= 0x00004000
POINTER_FLAG_CANCELED= 0x00008000
POINTER_FLAG_DOWN= 0x00010000
POINTER_FLAG_UPDATE= 0x00020000
POINTER_FLAG_UP= 0x00040000
POINTER_FLAG_WHEEL= 0x00080000
POINTER_FLAG_HWHEEL= 0x00100000
POINTER_FLAG_CAPTURECHANGED=0x00200000
#Structs Needed
class POINT(Structure):
_fields_=[("x", c_long),
("y", c_long)]
class POINTER_INFO(Structure):
_fields_=[("pointerType",c_int32),
("pointerId",c_uint32),
("frameId",c_uint32),
("pointerFlags",c_int),
("sourceDevice",c_uint32),
("hwndTarget",c_uint32),
("ptPixelLocation",POINT),
("ptHimetricLocation",POINT),
("ptPixelLocationRaw",POINT),
("ptHimetricLocationRaw",POINT),
("dwTime",c_uint32),
("historyCount",c_uint32),
("inputData",c_int32),
("dwKeyStates",c_uint32),
("PerformanceCount",c_uint64),
("ButtonChangeType",c_int)
]
class RECT(Structure):
_fields_=[("left",c_long),
("top",c_long),
("right",c_long),
("bottom",c_long)]
class POINTER_TOUCH_INFO(Structure):
_fields_=[("pointerInfo",POINTER_INFO),
("touchFlags",c_int),
("touchMask",c_int),
("rcContact", RECT),
("rcContactRaw",RECT),
("orientation", c_uint32),
("pressure", c_uint32)]
#Initialize Touch Injection
pointerInfo=POINTER_INFO(pointerType=PT_TOUCH,
pointerId=0,
ptPixelLocation=POINT(950,540))
touchInfo=POINTER_TOUCH_INFO(pointerInfo=pointerInfo,
touchFlags=TOUCH_FLAG_NONE,
touchMask=TOUCH_MASK_ALL,
rcContact=RECT(pointerInfo.ptPixelLocation.x-5,
pointerInfo.ptPixelLocation.y-5,
pointerInfo.ptPixelLocation.x+5,
pointerInfo.ptPixelLocation.y+5),
orientation=90,
pressure=32000)
if (windll.user32.InitializeTouchInjection(1,1) != 0):
print "Initialized Touch Injection"
#Press Down
touchInfo.pointerInfo.pointerFlags=(POINTER_FLAG_DOWN|
POINTER_FLAG_INRANGE|
POINTER_FLAG_INCONTACT)
if (windll.user32.InjectTouchInput(1, byref(touchInfo))==0):
print "Failed with Error: "+ FormatError()
else:
print "Touch Down Succeeded!"
#Pull Up
touchInfo.pointerInfo.pointerFlags=POINTER_FLAG_UP
if (windll.user32.InjectTouchInput(1,byref(touchInfo))==0):
print "Failed with Error: "+FormatError()
else:
print "Pull Up Succeeded!"
Fails everytime with error about the input parameters.
I’ve gone through every reference and can’t find a type that seems incorrect. Does anyone see something obvious?
Thanks
Thanks to Eryksum and Xyroid, I was able to get it working. Thanks for putting up with my C-type / Windows ignorance. Here is the final script with the touch emulation packaged as a function (extra constants as well):
from ctypes import *
from ctypes.wintypes import *
#Constants
#For touchMask
TOUCH_MASK_NONE= 0x00000000 #Default
TOUCH_MASK_CONTACTAREA= 0x00000001
TOUCH_MASK_ORIENTATION= 0x00000002
TOUCH_MASK_PRESSURE= 0x00000004
TOUCH_MASK_ALL= 0x00000007
#For touchFlag
TOUCH_FLAG_NONE= 0x00000000
#For pointerType
PT_POINTER= 0x00000001#All
PT_TOUCH= 0x00000002
PT_PEN= 0x00000003
PT_MOUSE= 0x00000004
#For pointerFlags
POINTER_FLAG_NONE= 0x00000000#Default
POINTER_FLAG_NEW= 0x00000001
POINTER_FLAG_INRANGE= 0x00000002
POINTER_FLAG_INCONTACT= 0x00000004
POINTER_FLAG_FIRSTBUTTON= 0x00000010
POINTER_FLAG_SECONDBUTTON=0x00000020
POINTER_FLAG_THIRDBUTTON= 0x00000040
POINTER_FLAG_FOURTHBUTTON=0x00000080
POINTER_FLAG_FIFTHBUTTON= 0x00000100
POINTER_FLAG_PRIMARY= 0x00002000
POINTER_FLAG_CONFIDENCE= 0x00004000
POINTER_FLAG_CANCELED= 0x00008000
POINTER_FLAG_DOWN= 0x00010000
POINTER_FLAG_UPDATE= 0x00020000
POINTER_FLAG_UP= 0x00040000
POINTER_FLAG_WHEEL= 0x00080000
POINTER_FLAG_HWHEEL= 0x00100000
POINTER_FLAG_CAPTURECHANGED=0x00200000
#Structs Needed
class POINTER_INFO(Structure):
_fields_=[("pointerType",c_uint32),
("pointerId",c_uint32),
("frameId",c_uint32),
("pointerFlags",c_int),
("sourceDevice",HANDLE),
("hwndTarget",HWND),
("ptPixelLocation",POINT),
("ptHimetricLocation",POINT),
("ptPixelLocationRaw",POINT),
("ptHimetricLocationRaw",POINT),
("dwTime",DWORD),
("historyCount",c_uint32),
("inputData",c_int32),
("dwKeyStates",DWORD),
("PerformanceCount",c_uint64),
("ButtonChangeType",c_int)
]
class POINTER_TOUCH_INFO(Structure):
_fields_=[("pointerInfo",POINTER_INFO),
("touchFlags",c_int),
("touchMask",c_int),
("rcContact", RECT),
("rcContactRaw",RECT),
("orientation", c_uint32),
("pressure", c_uint32)]
#Initialize Pointer and Touch info
pointerInfo=POINTER_INFO(pointerType=PT_TOUCH,
pointerId=0,
ptPixelLocation=POINT(950,540))
touchInfo=POINTER_TOUCH_INFO(pointerInfo=pointerInfo,
touchFlags=TOUCH_FLAG_NONE,
touchMask=TOUCH_MASK_ALL,
rcContact=RECT(pointerInfo.ptPixelLocation.x-5,
pointerInfo.ptPixelLocation.y-5,
pointerInfo.ptPixelLocation.x+5,
pointerInfo.ptPixelLocation.y+5),
orientation=90,
pressure=32000)
def makeTouch(x,y,fingerRadius):
touchInfo.pointerInfo.ptPixelLocation.x=x
touchInfo.pointerInfo.ptPixelLocation.y=y
touchInfo.rcContact.left=x-fingerRadius
touchInfo.rcContact.right=x+fingerRadius
touchInfo.rcContact.top=y-fingerRadius
touchInfo.rcContact.bottom=y+fingerRadius
#Initialize Touch Injection
if (windll.user32.InitializeTouchInjection(1,1) != 0):
print "Initialized Touch Injection"
#Press Down
touchInfo.pointerInfo.pointerFlags=(POINTER_FLAG_DOWN|
POINTER_FLAG_INRANGE|
POINTER_FLAG_INCONTACT)
if (windll.user32.InjectTouchInput(1, byref(touchInfo))==0):
print "Failed with Error: "+ FormatError()
else:
print "Touch Down Succeeded!"
#Pull Up
touchInfo.pointerInfo.pointerFlags=POINTER_FLAG_UP
if (windll.user32.InjectTouchInput(1,byref(touchInfo))==0):
print "Failed with Error: "+FormatError()
else:
print "Pull Up Succeeded!"
return
#Ex:
#makeTouch(950,270,5)
For future multitouch travelers, the above example needs some significant massaging to create multiple touch events with a proper lifetime.
This includes maintaining persistent POINTER_TOUCH_INFO
arrays, setting their ID’s appropriately, and properly calling DOWN
, UPDATE
, and UP
events as needed.
Hopefully this addition to the example script will save others time:
from ctypes import *
from ctypes.wintypes import *
# Constants
# For touchMask
TOUCH_MASK_NONE= 0x00000000 # Default
TOUCH_MASK_CONTACTAREA= 0x00000001
TOUCH_MASK_ORIENTATION= 0x00000002
TOUCH_MASK_PRESSURE= 0x00000004
TOUCH_MASK_ALL= 0x00000007
# For touchFlag
TOUCH_FLAG_NONE= 0x00000000
# For pointerType
PT_POINTER= 0x00000001 # All
PT_TOUCH= 0x00000002
PT_PEN= 0x00000003
PT_MOUSE= 0x00000004
#For pointerFlags
POINTER_FLAG_NONE= 0x00000000 # Default
POINTER_FLAG_NEW= 0x00000001
POINTER_FLAG_INRANGE= 0x00000002
POINTER_FLAG_INCONTACT= 0x00000004
POINTER_FLAG_FIRSTBUTTON= 0x00000010
POINTER_FLAG_SECONDBUTTON=0x00000020
POINTER_FLAG_THIRDBUTTON= 0x00000040
POINTER_FLAG_FOURTHBUTTON=0x00000080
POINTER_FLAG_FIFTHBUTTON= 0x00000100
POINTER_FLAG_PRIMARY= 0x00002000
POINTER_FLAG_CONFIDENCE= 0x00004000
POINTER_FLAG_CANCELED= 0x00008000
POINTER_FLAG_DOWN= 0x00010000
POINTER_FLAG_UPDATE= 0x00020000
POINTER_FLAG_UP= 0x00040000
POINTER_FLAG_WHEEL= 0x00080000
POINTER_FLAG_HWHEEL= 0x00100000
POINTER_FLAG_CAPTURECHANGED=0x00200000
# Structs Needed
class POINTER_INFO(Structure):
_fields_=[("pointerType",c_uint32),
("pointerId",c_uint32),
("frameId",c_uint32),
("pointerFlags",c_int),
("sourceDevice",HANDLE),
("hwndTarget",HWND),
("ptPixelLocation",POINT),
("ptHimetricLocation",POINT),
("ptPixelLocationRaw",POINT),
("ptHimetricLocationRaw",POINT),
("dwTime",DWORD),
("historyCount",c_uint32),
("inputData",c_int32),
("dwKeyStates",DWORD),
("PerformanceCount",c_uint64),
("ButtonChangeType",c_int)
]
class POINTER_TOUCH_INFO(Structure):
_fields_=[("pointerInfo",POINTER_INFO),
("touchFlags",c_int),
("touchMask",c_int),
("rcContact", RECT),
("rcContactRaw",RECT),
("orientation", c_uint32),
("pressure", c_uint32)]
# Initialize Pointer and Touch info
def initialize(maxtouches=10, dwmode=1):
global touches
touches = (POINTER_TOUCH_INFO * maxtouches)()
for ind in range(maxtouches):
pointerInfo=POINTER_INFO(pointerType = PT_TOUCH,
pointerId = ind,
ptPixelLocation = POINT(950,540),
pointerFlags = POINTER_FLAG_NEW)
touchInfo=POINTER_TOUCH_INFO(pointerInfo = pointerInfo,
touchFlags = TOUCH_FLAG_NONE,
touchMask = TOUCH_MASK_ALL,
rcContact = RECT(pointerInfo.ptPixelLocation.x-5,
pointerInfo.ptPixelLocation.y-5,
pointerInfo.ptPixelLocation.x+5,
pointerInfo.ptPixelLocation.y+5),
orientation = 90,
pressure = 32000)
touches[ind] = touchInfo
if (windll.user32.InitializeTouchInjection(len(touches), 1) != 0):
print("Initialized Touch Injection")
ids_to_update = 0
currently_down = None
def updateTouchInfo(id, down, x = 0, y = 0, fingerRadius=1, orientation = 90, pressure = 32000):
global currently_down, ids_to_update
if currently_down == None or len(currently_down) != len(touches):
currently_down = [False] * len(touches)
if down:
touches[id].pointerInfo.pointerFlags = (((POINTER_FLAG_DOWN) if not currently_down[id] else POINTER_FLAG_UPDATE)|
POINTER_FLAG_INRANGE |
POINTER_FLAG_INCONTACT)
touches[id].orientation = orientation
touches[id].pressure = pressure
touches[id].pointerInfo.ptPixelLocation.x = x
touches[id].pointerInfo.ptPixelLocation.y = y
touches[id].rcContact.left = x - fingerRadius
touches[id].rcContact.right = x + fingerRadius
touches[id].rcContact.top = y - fingerRadius
touches[id].rcContact.bottom = y + fingerRadius
else:
touches[id].pointerInfo.pointerFlags = POINTER_FLAG_UP #if currently_down[id] else POINTER_FLAG_UPDATE #if currently_down[id] else POINTER_FLAG_UPDATE
ids_to_update += 1 if down or currently_down[id] else 0
currently_down[id] = down
def applyTouches():
global ids_to_update
if ids_to_update > 0:
if (windll.user32.InjectTouchInput(int(ids_to_update), byref(touches[0])) == 0):
print("Failed trying to update", ids_to_update, "points with Error:", FormatError())
ids_to_update = 0
# Use like:
#import multitouch # Call once
#multitouch.initialize() # Call once
#for i in range(10): # Call every frame
# if i < len(keypoints):
# multitouch.updateTouchInfo(i, True,
# int(keypoints[i].pt[0] * 3),
# int(keypoints[i].pt[1] * 3),
# int(keypoints[i].size / 2))
# else:
# multitouch.updateTouchInfo(i, False)
#multitouch.applyTouches()