first commit
This commit is contained in:
184
myenv/lib/python3.10/site-packages/pynput/mouse/_xorg.py
Normal file
184
myenv/lib/python3.10/site-packages/pynput/mouse/_xorg.py
Normal file
@@ -0,0 +1,184 @@
|
||||
# coding=utf-8
|
||||
# pynput
|
||||
# Copyright (C) 2015-2024 Moses Palmér
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
The keyboard implementation for *Xorg*.
|
||||
"""
|
||||
|
||||
# pylint: disable=C0111
|
||||
# The documentation is extracted from the base classes
|
||||
|
||||
|
||||
# pylint: disable=E1101,E1102
|
||||
# We dynamically generate the Button class
|
||||
|
||||
# pylint: disable=R0903
|
||||
# We implement stubs
|
||||
|
||||
# pylint: disable=W0611
|
||||
try:
|
||||
import pynput._util.xorg
|
||||
except Exception as e:
|
||||
raise ImportError('failed to acquire X connection: {}'.format(str(e)), e)
|
||||
# pylint: enable=W0611
|
||||
|
||||
import enum
|
||||
import Xlib.display
|
||||
import Xlib.ext
|
||||
import Xlib.ext.xtest
|
||||
import Xlib.X
|
||||
import Xlib.protocol
|
||||
|
||||
from pynput._util.xorg import (
|
||||
display_manager,
|
||||
ListenerMixin)
|
||||
from . import _base
|
||||
|
||||
|
||||
# pylint: disable=C0103
|
||||
Button = enum.Enum(
|
||||
'Button',
|
||||
module=__name__,
|
||||
names=[
|
||||
('unknown', None),
|
||||
('left', 1),
|
||||
('middle', 2),
|
||||
('right', 3),
|
||||
('scroll_up', 4),
|
||||
('scroll_down', 5),
|
||||
('scroll_left', 6),
|
||||
('scroll_right', 7)] + [
|
||||
('button%d' % i, i)
|
||||
for i in range(8, 31)])
|
||||
# pylint: enable=C0103
|
||||
|
||||
|
||||
class Controller(_base.Controller):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Controller, self).__init__(*args, **kwargs)
|
||||
self._display = Xlib.display.Display()
|
||||
|
||||
def __del__(self):
|
||||
if hasattr(self, '_display'):
|
||||
self._display.close()
|
||||
|
||||
def _position_get(self):
|
||||
with display_manager(self._display) as dm:
|
||||
qp = dm.screen().root.query_pointer()
|
||||
return (qp.root_x, qp.root_y)
|
||||
|
||||
def _position_set(self, pos):
|
||||
px, py = self._check_bounds(*pos)
|
||||
with display_manager(self._display) as dm:
|
||||
Xlib.ext.xtest.fake_input(dm, Xlib.X.MotionNotify, x=px, y=py)
|
||||
|
||||
def _scroll(self, dx, dy):
|
||||
dx, dy = self._check_bounds(dx, dy)
|
||||
if dy:
|
||||
self.click(
|
||||
button=Button.scroll_up if dy > 0 else Button.scroll_down,
|
||||
count=abs(dy))
|
||||
|
||||
if dx:
|
||||
self.click(
|
||||
button=Button.scroll_right if dx > 0 else Button.scroll_left,
|
||||
count=abs(dx))
|
||||
|
||||
def _press(self, button):
|
||||
with display_manager(self._display) as dm:
|
||||
Xlib.ext.xtest.fake_input(dm, Xlib.X.ButtonPress, button.value)
|
||||
|
||||
def _release(self, button):
|
||||
with display_manager(self._display) as dm:
|
||||
Xlib.ext.xtest.fake_input(dm, Xlib.X.ButtonRelease, button.value)
|
||||
|
||||
def _check_bounds(self, *args):
|
||||
"""Checks the arguments and makes sure they are within the bounds of a
|
||||
short integer.
|
||||
|
||||
:param args: The values to verify.
|
||||
"""
|
||||
if not all(
|
||||
(-0x7fff - 1) <= number <= 0x7fff
|
||||
for number in args):
|
||||
raise ValueError(args)
|
||||
else:
|
||||
return tuple(int(p) for p in args)
|
||||
|
||||
|
||||
class Listener(ListenerMixin, _base.Listener):
|
||||
#: A mapping from button values to scroll directions
|
||||
_SCROLL_BUTTONS = {
|
||||
Button.scroll_up.value: (0, 1),
|
||||
Button.scroll_down.value: (0, -1),
|
||||
Button.scroll_right.value: (1, 0),
|
||||
Button.scroll_left.value: (-1, 0)}
|
||||
|
||||
_EVENTS = (
|
||||
Xlib.X.ButtonPressMask,
|
||||
Xlib.X.ButtonReleaseMask)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Listener, self).__init__(*args, **kwargs)
|
||||
|
||||
def _handle_message(self, dummy_display, event, injected):
|
||||
px = event.root_x
|
||||
py = event.root_y
|
||||
|
||||
if event.type == Xlib.X.ButtonPress:
|
||||
# Scroll events are sent as button presses with the scroll
|
||||
# button codes
|
||||
scroll = self._SCROLL_BUTTONS.get(event.detail, None)
|
||||
if scroll:
|
||||
self.on_scroll(
|
||||
px, py, scroll[0], scroll[1], injected)
|
||||
else:
|
||||
self.on_click(
|
||||
px, py, self._button(event.detail), True, injected)
|
||||
|
||||
elif event.type == Xlib.X.ButtonRelease:
|
||||
# Send an event only if this was not a scroll event
|
||||
if event.detail not in self._SCROLL_BUTTONS:
|
||||
self.on_click(
|
||||
px, py, self._button(event.detail), False, injected)
|
||||
|
||||
else:
|
||||
self.on_move(px, py, injected)
|
||||
|
||||
|
||||
def _suppress_start(self, display):
|
||||
display.screen().root.grab_pointer(
|
||||
True, self._event_mask, Xlib.X.GrabModeAsync, Xlib.X.GrabModeAsync,
|
||||
0, 0, Xlib.X.CurrentTime)
|
||||
|
||||
def _suppress_stop(self, display):
|
||||
display.ungrab_pointer(Xlib.X.CurrentTime)
|
||||
|
||||
# pylint: disable=R0201
|
||||
def _button(self, detail):
|
||||
"""Creates a mouse button from an event detail.
|
||||
|
||||
If the button is unknown, :attr:`Button.unknown` is returned.
|
||||
|
||||
:param detail: The event detail.
|
||||
|
||||
:return: a button
|
||||
"""
|
||||
try:
|
||||
return Button(detail)
|
||||
except ValueError:
|
||||
return Button.unknown
|
||||
# pylint: enable=R0201
|
||||
Reference in New Issue
Block a user