Hi Tim, et al, I am testing the ctypes technique to intercept messages for my process, as Tim pointed out I need to do using the SetWindowsLongPtr function.
I am seeing slightly unexpected results. My goal was to make a pass-through implementation, so my callback does not disrupt the application. I wanted to print to the shell to show my callback was involved. I am seeing print statements, but the behavior of the application is slightly different. Reverse mouse wheel seems to behave differently in the application. Also, sometimes I see an exception in the shell (OSError: exception...access violation reading 0xblahblah). Does anyone see an error with the way I am calling the "oldWndProc" or the print statement in the code below? Maybe the way I have defined the return argument for SetWindowLongPtrW is incorrect? Thanks for any help, John from ctypes import * import ctypes import ctypes.wintypes from ctypes import c_long, c_int # some shortcut definitions GetActiveWindow = windll.user32.GetActiveWindow GetActiveWindow.restype = ctypes.wintypes.HWND LRESULT = ctypes.wintypes.LPARAM WNDPROC = WINFUNCTYPE(LRESULT, ctypes.wintypes.HWND, ctypes.wintypes.UINT, ctypes.wintypes.WPARAM, ctypes.wintypes.LPARAM) SetWindowLongPtrW = ctypes.windll.user32.SetWindowLongPtrW SetWindowLongPtrW.restype = WNDPROC CallWindowProc = ctypes.windll.user32.CallWindowProcW CallWindowProc.restype = LRESULT #proc type GWL_WNDPROC = int(-4) #msg types in case we need them WM_DESTROY = int('0x0002', 16) WM_KEYDOWN = int('0x0100', 16) WM_SIZE = int('0x0005', 16) WM_CLOSE = int('0x0010', 16) WM_GESTURE = int('0x0119', 16) WM_TOUCH = int('0x0240', 16) WM_GESTURENOTIFY = int('0x011A', 16) WM_TIMER = int('0x0113', 16) WM_MOUSEMOVE = int('0x0200', 16) WM_MOUSEWHEEL = int('0x020A', 16) WM_KEYUP = int('0x0101', 16) WM_KEYDOWN = int('0x0101', 16) # middle mouse button from GetAsyncKeyState() VK_MBUTTON = int('0x04',16) # ---- Multi Touch Support Class --- # # you should have only one instance of this class per OS window, # because it adds a member function as the Windows message handler for the hWnd passed. class MTHandler(object): def __init__(self, hWnd): self.mHWND = hWnd self.newWndProc = WNDPROC(self.MyWndProc) self.oldWndProc = SetWindowLongPtrW(self.mHWND, GWL_WNDPROC, self.newWndProc) self.inControl = True def _mouse_handler(self, msg, wParam, lParam): print('hello mouse move') def _gesture_handler(msg, wParam, lParam): print('hello gesture') def _touch_handler(msg, wParam, lParam): print('hello touch') def MyWndProc(self, hWnd, msg, wParam, lParam): print('hello wndproc', msg, wParam, lParam) #if (msg == WM_MOUSEMOVE) or (msg==WM_MOUSEWHEEL): # _mouse_handler(msg, wParam, lParam) #elif msg == WM_GESTURE: # _gesture_handler(msg, wParam, lParam) #elif msg == WM_TOUCH: # _touch_handler(msg, wParam, lParam) # source: # http://wiki.wxpython.org/HookingTheWndProc # # Restore the old WndProc. Notice the use of wxin32api # instead of win32gui here. This is to avoid an error due to # not passing a callable object. if msg == WM_CLOSE: if self.inControl: self.cleanup() if msg == WM_DESTROY: if self.inControl: self.cleanup() return CallWindowProc(self.oldWndProc, self.mHWND, msg, wParam, lParam) def cleanup(self): SetWindowLongPtrW(self.mHWND, GWL_WNDPROC, self.oldWndProc) self.inControl = False def __del__(self): if self.inControl: self.cleanup() # ---- end Multi Touch Support Class --- # On Thu, May 9, 2013 at 1:52 PM, John Grant <cyr...@gmail.com> wrote: > I believe found access to the HWND. > mHWND = ctypes.windll.user32.GetActiveWindow() > > > > On Thu, May 9, 2013 at 11:13 AM, John Grant <cyr...@gmail.com> wrote: > >> Hi Tim, >> >> Thanks for the great explanations. >> >> Yes, you are right, I am trying to intercept gestures in a window within >> the same process. The Blender application framework has a WndProc in C, and >> Blender supports extending itself with user-supplied Python scripts. I am >> trying to add gesture support with Python so I can avoid modifying the >> Blender C code. >> >> I'm reading through the wxPython article. It looks like a perfect fit for >> my problem. It shows everything I need to do, and using ctypes! Thanks! >> >> Although, I am stuck trying to get the HWND from Blender. It seems they >> have not exposed the handle yet. I'm looking for win32 API that might >> provide it to me, or a list of windows associated with the process. >> >> I guess I have to remove my callback as soon as the WM_DESTROY message is >> emitted, and reinstantiate the oldWndProc. That makes sense. I'm glad that >> is shown in the article. >> >> I just browsed the Blender C source code and they also use >> "SetWindowLongPtr" for GWLP_USERDATA, but not for GWLP_WNDPROC. I think >> everything will work out fine when I find the HWND. >> >> Thanks for the expert help. >> John >> >> >> On Thu, May 9, 2013 at 9:46 AM, Tim Roberts <t...@probo.com> wrote: >> >>> John Grant wrote: >>> > >>> > I would like to obtain multi-touch events in my Python code (running >>> > inside Blender's python environment). I have looked around the web for >>> > a python module that works with py 3.3 (others work with py 2.x), but >>> > I have not found one. So, I'm trying to build one. >>> > >>> > I believe I can use the 'ctypes' to call the function I need, >>> > GetGestureInfo. >>> >>> That gets you gestures, but not multitouch. If all you need is the >>> zoom, pan and rotate gestures and a two-finger tap, this will do it. >>> For more complicated gestures, most solutions are custom right now. >>> >>> >>> > This function requires 2 parameters as input, the lParam from WndProc >>> > and a pointer to the GESTUREINFO structure. >>> > >>> > * I hope I can use 'ctypes' to declare the GESTUREINFO structure in my >>> > python code.* >>> > I see it is possible to pass structures as pointers using ctypes as >>> well. >>> >>> The structure doesn't have any pointers, so this should be >>> straightforward. >>> >>> >>> > *** The problem seems to be obtaining the lParam from WndProc. *** >>> > >>> > My idea is to provide a callback function (again using ctypes to >>> > declare this callback) and use the SetWindowsHookEx function, passing >>> > my callback and the WH_CALLWNDPROC hook ID. >>> > >>> > Does this sound like it will work? >>> >>> No, a Windows hook is the wrong answer. That lets you intercept >>> messages from other processes (which is why hooks need to be in a DLL -- >>> the DLL actually gets copied and injected into the processes being >>> hooked). In your case, I assume you're trying to intercept gestures in >>> a window within your own process. Is that right? As long as you have >>> the window handle, all you need to do is subclass the window. That >>> means you make yourself the wndproc for that window, so you get first >>> shot at all the messages. >>> >>> Here's an example that shows how to do this in wxPython, but you can >>> eliminate the wxPython part of it. The key point is using >>> win32gui.SetWindowLong to load your own function in >>> win32con.GWL_WNDPROC, and remembering the return value so you can call >>> the original function. >>> http://wiki.wxpython.org/HookingTheWndProc >>> >>> -- >>> Tim Roberts, t...@probo.com >>> Providenza & Boekelheide, Inc. >>> >>> _______________________________________________ >>> python-win32 mailing list >>> python-win32@python.org >>> http://mail.python.org/mailman/listinfo/python-win32 >>> >> >> >
_______________________________________________ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32