diff --git a/pymouse/__init__.py b/pymouse/__init__.py index 0d8d6dd..7049bcc 100644 --- a/pymouse/__init__.py +++ b/pymouse/__init__.py @@ -34,3 +34,4 @@ else: from unix import PyMouse, PyMouseEvent +from base import MouseButtons diff --git a/pymouse/base.py b/pymouse/base.py index 492e57f..a542fe0 100644 --- a/pymouse/base.py +++ b/pymouse/base.py @@ -22,6 +22,22 @@ from threading import Thread + +class MouseButtons: + + BUTTON_LEFT = 1 + BUTTON_MIDDLE = 2 + BUTTON_RIGHT = 3 + BUTTON_SCROLL_UP = 4 + BUTTON_SCROLL_DOWN = 5 + BUTTON_SCROLL_LEFT = 6 + BUTTON_SCROLL_RIGHT = 7 + BUTTON_THUMB_BACK = 8 + BUTTON_THUMB_FORWARD = 9 + + + + class PyMouseMeta(object): def press(self, x, y, button = 1): diff --git a/pymouse/mac.py b/pymouse/mac.py index e4b5ba4..a85a950 100644 --- a/pymouse/mac.py +++ b/pymouse/mac.py @@ -16,18 +16,66 @@ from Quartz import * from AppKit import NSEvent -from base import PyMouseMeta, PyMouseEventMeta +from base import PyMouseMeta, PyMouseEventMeta, MouseButtons pressID = [None, kCGEventLeftMouseDown, kCGEventRightMouseDown, kCGEventOtherMouseDown] releaseID = [None, kCGEventLeftMouseUp, kCGEventRightMouseUp, kCGEventOtherMouseUp] + + +def get_button_code(event_message): + """ Platform specific ! """ + + + if event_message == kCGEventLeftMouseDown: + code = MouseButtons.BUTTON_LEFT + state = True + elif event_message == kCGEventLeftMouseUp: + code = MouseButtons.BUTTON_LEFT + state = False + elif event_message == kCGEventRightMouseDown: + code = MouseButtons.BUTTON_RIGHT + state = True + elif event_message == kCGEventRightMouseUp: + code = MouseButtons.BUTTON_RIGHT + state = False + elif event_message == kCGEventOtherMouseDown: + code = MouseButtons.BUTTON_MIDDLE + state = True + elif event_message == kCGEventOtherMouseUp: + code = MouseButtons.BUTTON_MIDDLE + state = False + else: + code = None + state = False + + return (code, state) + + +def get_event_code(button_code, state): + """ Platform specific ! """ + + # Mac only supports Left, Middle and Right buttons + if button_code not in (1, 2, 3): + raise ValueError("Button not supported") + + + if state: + code = pressID[button_code] + else: + code = releaseID[button_code] + + return code + + + class PyMouse(PyMouseMeta): - def press(self, x, y, button = 1): - event = CGEventCreateMouseEvent(None, pressID[button], (x, y), button - 1) + def press(self, x, y, button=1): + event = CGEventCreateMouseEvent(None, get_event_code(button, True), (x, y), button - 1) CGEventPost(kCGHIDEventTap, event) - def release(self, x, y, button = 1): - event = CGEventCreateMouseEvent(None, releaseID[button], (x, y), button - 1) + def release(self, x, y, button=1): + event = CGEventCreateMouseEvent(None, get_event_code(button, False), (x, y), button - 1) CGEventPost(kCGHIDEventTap, event) def move(self, x, y): @@ -48,12 +96,12 @@ def run(self): kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, - CGEventMaskBit(kCGEventMouseMoved) | - CGEventMaskBit(kCGEventLeftMouseDown) | - CGEventMaskBit(kCGEventLeftMouseUp) | - CGEventMaskBit(kCGEventRightMouseDown) | - CGEventMaskBit(kCGEventRightMouseUp) | - CGEventMaskBit(kCGEventOtherMouseDown) | + CGEventMaskBit(kCGEventMouseMoved) | + CGEventMaskBit(kCGEventLeftMouseDown) | + CGEventMaskBit(kCGEventLeftMouseUp) | + CGEventMaskBit(kCGEventRightMouseDown) | + CGEventMaskBit(kCGEventRightMouseUp) | + CGEventMaskBit(kCGEventOtherMouseDown) | CGEventMaskBit(kCGEventOtherMouseUp), self.handler, None) @@ -68,10 +116,11 @@ def run(self): def handler(self, proxy, type, event, refcon): (x, y) = CGEventGetLocation(event) - if type in pressID: - self.click(x, y, pressID.index(type), True) - elif type in releaseID: - self.click(x, y, releaseID.index(type), False) + + (code, state) = get_button_code(type) + + if code is not None: + self.click(x, y, code, state) else: self.move(x, y) diff --git a/pymouse/unix.py b/pymouse/unix.py index d2eadc9..98f148b 100644 --- a/pymouse/unix.py +++ b/pymouse/unix.py @@ -20,8 +20,36 @@ from Xlib.ext import record from Xlib.protocol import rq -from base import PyMouseMeta, PyMouseEventMeta - +from base import PyMouseMeta, PyMouseEventMeta, MouseButtons + + +def get_button_code(event_message): + """ Platform specific ! """ + + try: + code = (None, + MouseButtons.BUTTON_LEFT, + MouseButtons.BUTTON_MIDDLE, + MouseButtons.BUTTON_RIGHT, + MouseButtons.BUTTON_SCROLL_UP, + MouseButtons.BUTTON_SCROLL_DOWN, + MouseButtons.BUTTON_SCROLL_LEFT, + MouseButtons.BUTTON_SCROLL_RIGHT, + MouseButtons.BUTTON_THUMB_BACK, + MouseButtons.BUTTON_THUMB_FORWARD)[event_message] + + except IndexError: + raise ValueError("Button not supported") + + return code + + +def get_event_code(button_code): + """ Platform specific ! """ + + return button_code + + class PyMouse(PyMouseMeta): def __init__(self): @@ -31,12 +59,12 @@ def __init__(self): def press(self, x, y, button = 1): self.move(x, y) - fake_input(self.display, X.ButtonPress, [None, 1, 3, 2, 4, 5][button]) + fake_input(self.display, X.ButtonPress, get_event_code(button)) self.display.sync() def release(self, x, y, button = 1): self.move(x, y) - fake_input(self.display, X.ButtonRelease, [None, 1, 3, 2, 4, 5][button]) + fake_input(self.display, X.ButtonRelease, get_event_code(button)) self.display.sync() def move(self, x, y): @@ -92,10 +120,12 @@ def handler(self, reply): while len(data): event, data = rq.EventField(None).parse_binary_value(data, self.display.display, None, None) + + if event.type == X.ButtonPress: - self.click(event.root_x, event.root_y, (None, 1, 3, 2, 3, 3, 3)[event.detail], True) + self.click(event.root_x, event.root_y, get_button_code(event.detail), True) elif event.type == X.ButtonRelease: - self.click(event.root_x, event.root_y, (None, 1, 3, 2, 3, 3, 3)[event.detail], False) + self.click(event.root_x, event.root_y, get_button_code(event.detail), False) else: self.move(event.root_x, event.root_y) diff --git a/pymouse/windows.py b/pymouse/windows.py index 88809b5..5d07303 100644 --- a/pymouse/windows.py +++ b/pymouse/windows.py @@ -15,11 +15,59 @@ # limitations under the License. from ctypes import * -import win32api,win32con -from base import PyMouseMeta, PyMouseEventMeta +import win32api, win32con +from base import PyMouseMeta, PyMouseEventMeta, MouseButtons import pythoncom, pyHook from time import sleep + +def get_button_code(event_message): + """ Platform specific ! """ + + try: + if event_message == pyHook.HookConstants.WM_LBUTTONDOWN: + code = (MouseButtons.BUTTON_LEFT, True) + elif event_message == pyHook.HookConstants.WM_LBUTTONUP: + code = (MouseButtons.BUTTON_LEFT, False) + elif event_message == pyHook.HookConstants.WM_RBUTTONDOWN: + code = (MouseButtons.BUTTON_RIGHT, True) + elif event_message == pyHook.HookConstants.WM_RBUTTONUP: + code = (MouseButtons.BUTTON_RIGHT, False) + elif event_message == pyHook.HookConstants.WM_MBUTTONDOWN: + code = (MouseButtons.BUTTON_MIDDLE, True) + elif event_message == pyHook.HookConstants.WM_MBUTTONUP: + code = (MouseButtons.BUTTON_MIDDLE, False) + + except IndexError: + code = (None, False) + + return code + + +def get_event_code(button_code, state): + """ Platform specific ! """ + + # Windows only supports Left, Middle and Right buttons + if button_code not in (1, 2, 3): + raise ValueError("Button not supported") + + # swap button 2 and 3, because Windows uses 3 for middle button and 2 for right button + if button_code == 2: + button_code = 3 + elif button_code == 3: + button_code = 2 + + if state: + code = 2 ** ((2 * button_code) - 1) + else: + code = 2 ** ((2 * button_code)) + + + return code + + + + class POINT(Structure): _fields_ = [("x", c_ulong), ("y", c_ulong)] @@ -27,14 +75,14 @@ class POINT(Structure): class PyMouse(PyMouseMeta): """MOUSEEVENTF_(button and action) constants are defined at win32con, buttonAction is that value""" - def press(self, x, y, button = 1): - buttonAction = 2**((2*button)-1) - self.move(x,y) + def press(self, x, y, button=1): + buttonAction = get_event_code(button, True) + self.move(x, y) win32api.mouse_event(buttonAction, x, y) - def release(self, x, y, button = 1): - buttonAction = 2**((2*button)) - self.move(x,y) + def release(self, x, y, button=1): + buttonAction = get_event_code(button, False) + self.move(x, y) win32api.mouse_event(buttonAction, x, y) def move(self, x, y): @@ -68,23 +116,16 @@ def stop(self): self.state = False def _click(self, event): - x,y = event.Position - - if event.Message == pyHook.HookConstants.WM_LBUTTONDOWN: - self.click(x, y, 1, True) - elif event.Message == pyHook.HookConstants.WM_LBUTTONUP: - self.click(x, y, 1, False) - elif event.Message == pyHook.HookConstants.WM_RBUTTONDOWN: - self.click(x, y, 2, True) - elif event.Message == pyHook.HookConstants.WM_RBUTTONUP: - self.click(x, y, 2, False) - elif event.Message == pyHook.HookConstants.WM_MBUTTONDOWN: - self.click(x, y, 3, True) - elif event.Message == pyHook.HookConstants.WM_MBUTTONUP: - self.click(x, y, 3, False) + x, y = event.Position + + (button, state) = get_button_code(event.Message) + + if button is not None: + self.click(x, y, button, state) + return not self.capture def _move(self, event): - x,y = event.Position + x, y = event.Position self.move(x, y) return not self.captureMove