Hello everyone,
I have created multi-touch support using Pygame for my own Blender addon.
This is sample code for anyone trying to do the same. You will need to install the pygame dependency inside blenders python.
To do that, check out this link:
https://blender.stackexchange.com/questions/168448/bundling-python-library-with-addon
This code creates a small window that you can touch with multiple fingers.
The console will display many prints with the finger ID and position in relation to the small window.
import os
import pygame as pg
from mathutils import Vector
import win32gui
import win32con
import win32api
import winxpgui
import bpy
# This makes the touchpad be usable as a multi touch device.
os.environ['SDL_MOUSE_TOUCH_EVENTS'] = '1'
def get_window_rect(hwnd):
rect = win32gui.GetWindowRect(hwnd)
x = rect[0]
y = rect[1]
w = rect[2] - x
h = rect[3] - y
return x,y,w,h
class TOUCH_OT_example(bpy.types.Operator):
"example of Multi Touch in Blemder"
bl_idname = "touch.example"
bl_label = "multi touch example"
_timer = None
def modal(self, context, event):
pg.init()
width, height = (640, 480)
screen = pg.display.set_mode((width, height))
# this is windows gui stuff to make the pygame window transparent
# stays always on top and inactive so it is not blocking key input
#region winows gui
hwnd_touch = pg.display.get_wm_info()["window"]
alpha = 100
x,y,w,h = get_window_rect(hwnd_touch)
win32gui.SetWindowLong (hwnd_touch, win32con.GWL_EXSTYLE, win32gui.GetWindowLong (hwnd_touch, win32con.GWL_EXSTYLE ) | win32con.WS_EX_LAYERED )
winxpgui.SetLayeredWindowAttributes(hwnd_touch, win32api.RGB(0,0,0), alpha, win32con.LWA_ALPHA)
win32gui.SetWindowPos(hwnd_touch, win32con.HWND_TOP, x, y, w, h, win32con.SWP_NOACTIVATE)
#endregion
caption = 'Touch'
pg.display.set_caption(caption)
pg.event.set_grab(False)
pg.mouse.set_visible(True)
if event.type == 'TIMER':
for e in pg.event.get():
# We look for finger down, finger motion, and then finger up.
if e.type == pg.FINGERDOWN:
touch_pos = Vector((int(width * e.x), int(height-(height * e.y))))
print(f" Touch Id: {e.finger_id} Down at pos {touch_pos}")
elif e.type == pg.FINGERMOTION:
touch_pos = Vector((int(width * e.x), int(height-(height * e.y))))
print(f" Touch Id: {e.finger_id} Moved at pos {touch_pos}")
elif e.type == pg.FINGERUP:
touch_pos = Vector((int(width * e.x), int(height-(height * e.y))))
print(f" Touch Id: {e.finger_id} UP at pos {touch_pos}")
pg.display.flip()
if event.type in {'RIGHTMOUSE', 'ESC'}:
pg.quit()
self.cancel(context)
return {'CANCELLED'}
return {'PASS_THROUGH'}
def execute(self, context):
wm = context.window_manager
self._timer = wm.event_timer_add(0.01, window=context.window) # Update timer every 0.01 s the touch input gets updated
wm.modal_handler_add(self)
return {'RUNNING_MODAL'}
def cancel(self, context):
wm = context.window_manager
wm.event_timer_remove(self._timer)
def register():
bpy.utils.register_class(TOUCH_OT_example)
def unregister():
bpy.utils.unregister_class(TOUCH_OT_example)
if __name__ == "__main__":
register()
# test call
bpy.ops.touch.example()