123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- # -*- coding: utf-8 -*-
- import time as _time
- import platform as _platform
- if _platform.system() == 'Windows':
- from. import _winmouse as _os_mouse
- elif _platform.system() == 'Linux':
- from. import _nixmouse as _os_mouse
- elif _platform.system() == 'Darwin':
- from. import _darwinmouse as _os_mouse
- else:
- raise OSError("Unsupported platform '{}'".format(_platform.system()))
- from ._mouse_event import ButtonEvent, MoveEvent, WheelEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN, DOUBLE
- from ._generic import GenericListener as _GenericListener
- _pressed_events = set()
- class _MouseListener(_GenericListener):
- def init(self):
- _os_mouse.init()
- def pre_process_event(self, event):
- if isinstance(event, ButtonEvent):
- if event.event_type in (UP, DOUBLE):
- _pressed_events.discard(event.button)
- else:
- _pressed_events.add(event.button)
- return True
- def listen(self):
- _os_mouse.listen(self.queue)
- _listener = _MouseListener()
- def is_pressed(button=LEFT):
- """ Returns True if the given button is currently pressed. """
- _listener.start_if_necessary()
- return button in _pressed_events
- def press(button=LEFT):
- """ Presses the given button (but doesn't release). """
- _os_mouse.press(button)
- def release(button=LEFT):
- """ Releases the given button. """
- _os_mouse.release(button)
- def click(button=LEFT):
- """ Sends a click with the given button. """
- _os_mouse.press(button)
- _os_mouse.release(button)
- def double_click(button=LEFT):
- """ Sends a double click with the given button. """
- click(button)
- click(button)
- def right_click():
- """ Sends a right click with the given button. """
- click(RIGHT)
- def wheel(delta=1):
- """ Scrolls the wheel `delta` clicks. Sign indicates direction. """
- _os_mouse.wheel(delta)
- def move(x, y, absolute=True, duration=0):
- """
- Moves the mouse. If `absolute`, to position (x, y), otherwise move relative
- to the current position. If `duration` is non-zero, animates the movement.
- """
- x = int(x)
- y = int(y)
- # Requires an extra system call on Linux, but `move_relative` is measured
- # in millimiters so we would lose precision.
- position_x, position_y = get_position()
- if not absolute:
- x = position_x + x
- y = position_y + y
- if duration:
- start_x = position_x
- start_y = position_y
- dx = x - start_x
- dy = y - start_y
- if dx == 0 and dy == 0:
- _time.sleep(duration)
- else:
- # 120 movements per second.
- # Round and keep float to ensure float division in Python 2
- steps = max(1.0, float(int(duration * 120.0)))
- for i in range(int(steps)+1):
- move(start_x + dx*i/steps, start_y + dy*i/steps)
- _time.sleep(duration/steps)
- else:
- _os_mouse.move_to(x, y)
- def drag(start_x, start_y, end_x, end_y, absolute=True, duration=0):
- """
- Holds the left mouse button, moving from start to end position, then
- releases. `absolute` and `duration` are parameters regarding the mouse
- movement.
- """
- if is_pressed():
- release()
- move(start_x, start_y, absolute, 0)
- press()
- move(end_x, end_y, absolute, duration)
- release()
- def on_button(callback, args=(), buttons=(LEFT, MIDDLE, RIGHT, X, X2), types=(UP, DOWN, DOUBLE)):
- """ Invokes `callback` with `args` when the specified event happens. """
- if not isinstance(buttons, (tuple, list)):
- buttons = (buttons,)
- if not isinstance(types, (tuple, list)):
- types = (types,)
- def handler(event):
- if isinstance(event, ButtonEvent):
- if event.event_type in types and event.button in buttons:
- callback(*args)
- _listener.add_handler(handler)
- return handler
- def on_click(callback, args=()):
- """ Invokes `callback` with `args` when the left button is clicked. """
- return on_button(callback, args, [LEFT], [UP])
- def on_double_click(callback, args=()):
- """
- Invokes `callback` with `args` when the left button is double clicked.
- """
- return on_button(callback, args, [LEFT], [DOUBLE])
- def on_right_click(callback, args=()):
- """ Invokes `callback` with `args` when the right button is clicked. """
- return on_button(callback, args, [RIGHT], [UP])
- def on_middle_click(callback, args=()):
- """ Invokes `callback` with `args` when the middle button is clicked. """
- return on_button(callback, args, [MIDDLE], [UP])
- def wait(button=LEFT, target_types=(UP, DOWN, DOUBLE)):
- """
- Blocks program execution until the given button performs an event.
- """
- from threading import Lock
- lock = Lock()
- lock.acquire()
- handler = on_button(lock.release, (), [button], target_types)
- lock.acquire()
- _listener.remove_handler(handler)
- def get_position():
- """ Returns the (x, y) mouse position. """
- return _os_mouse.get_position()
- def hook(callback):
- """
- Installs a global listener on all available mouses, invoking `callback`
- each time it is moved, a key status changes or the wheel is spun. A mouse
- event is passed as argument, with type either `mouse.ButtonEvent`,
- `mouse.WheelEvent` or `mouse.MoveEvent`.
-
- Returns the given callback for easier development.
- """
- _listener.add_handler(callback)
- return callback
- def unhook(callback):
- """
- Removes a previously installed hook.
- """
- _listener.remove_handler(callback)
- def unhook_all():
- """
- Removes all hooks registered by this application. Note this may include
- hooks installed by high level functions, such as `record`.
- """
- del _listener.handlers[:]
- def record(button=RIGHT, target_types=(DOWN,)):
- """
- Records all mouse events until the user presses the given button.
- Then returns the list of events recorded. Pairs well with `play(events)`.
- Note: this is a blocking function.
- Note: for more details on the mouse hook and events see `hook`.
- """
- recorded = []
- hook(recorded.append)
- wait(button=button, target_types=target_types)
- unhook(recorded.append)
- return recorded
- def play(events, speed_factor=1.0, include_clicks=True, include_moves=True, include_wheel=True):
- """
- Plays a sequence of recorded events, maintaining the relative time
- intervals. If speed_factor is <= 0 then the actions are replayed as fast
- as the OS allows. Pairs well with `record()`.
- The parameters `include_*` define if events of that type should be inluded
- in the replay or ignored.
- """
- last_time = None
- for event in events:
- if speed_factor > 0 and last_time is not None:
- _time.sleep((event.time - last_time) / speed_factor)
- last_time = event.time
- if isinstance(event, ButtonEvent) and include_clicks:
- if event.event_type == UP:
- _os_mouse.release(event.button)
- else:
- _os_mouse.press(event.button)
- elif isinstance(event, MoveEvent) and include_moves:
- _os_mouse.move_to(event.x, event.y)
- elif isinstance(event, WheelEvent) and include_wheel:
- _os_mouse.wheel(event.delta)
- replay = play
- hold = press
- if __name__ == '__main__':
- print('Recording... Double click to stop and replay.')
- play(record())
|