-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0241d0f
commit 84151a1
Showing
4 changed files
with
214 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,54 +1,116 @@ | ||
from pynput.mouse import Button, Controller, Listener | ||
from threading import Event | ||
from threading import Event, Thread | ||
from time import sleep | ||
from PyQt5.QtWidgets import QApplication, QLabel | ||
from PyQt5.QtCore import Qt, pyqtSignal | ||
from PyQt5.QtSvg import QSvgWidget | ||
from PyQt5.QtGui import QPixmap | ||
from pathlib import Path | ||
import sys | ||
|
||
def on_move(x, y): | ||
global pos, scroll_mode, direction, interval, DELAY, DEAD_AREA | ||
if scroll_mode.is_set(): | ||
delta = pos[1] - y | ||
if abs(delta) <= DEAD_AREA: | ||
direction = 0 | ||
elif delta > 0: | ||
direction = 1 | ||
elif delta < 0: | ||
direction = -1 | ||
if abs(delta) <= DEAD_AREA + DELAY * 2: | ||
interval = 0.5 | ||
else: | ||
interval = DELAY / (abs(delta) - DEAD_AREA) | ||
class AutoscrollIconSvg(QSvgWidget): | ||
scroll_mode_entered = pyqtSignal() | ||
scroll_mode_exited = pyqtSignal() | ||
|
||
def __init__(self, path, size): | ||
super().__init__(path) | ||
self.size = size | ||
self.renderer().setAspectRatioMode(Qt.KeepAspectRatio) | ||
self.resize(self.size, self.size) | ||
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint | Qt.X11BypassWindowManagerHint) | ||
self.setAttribute(Qt.WA_TranslucentBackground) | ||
self.scroll_mode_entered.connect(self.show) | ||
self.scroll_mode_exited.connect(self.close) | ||
|
||
def show(self): | ||
x = self.pos[0] - self.size // 2 | ||
y = self.pos[1] - self.size // 2 | ||
self.move(x, y) | ||
super().show() | ||
|
||
def on_click(x, y, button, pressed): | ||
global pos, scroll_mode, direction, interval, BUTTON_START, BUTTON_STOP | ||
if button == BUTTON_START and pressed and not scroll_mode.is_set(): | ||
pos = (x, y) | ||
direction = 0 | ||
interval = 0 | ||
scroll_mode.set() | ||
elif button == BUTTON_STOP and pressed and scroll_mode.is_set(): | ||
scroll_mode.clear() | ||
class AutoscrollIconRaster(QLabel): | ||
scroll_mode_entered = pyqtSignal() | ||
scroll_mode_exited = pyqtSignal() | ||
|
||
def __init__(self, path, size): | ||
super().__init__() | ||
self.size = size | ||
self.resize(self.size, self.size) | ||
self.img = QPixmap(path).scaled(self.size, self.size, Qt.KeepAspectRatio) | ||
self.setPixmap(self.img) | ||
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint | Qt.X11BypassWindowManagerHint) | ||
self.setAttribute(Qt.WA_TranslucentBackground) | ||
self.scroll_mode_entered.connect(self.show) | ||
self.scroll_mode_exited.connect(self.close) | ||
|
||
def autoscroll(): | ||
global mouse, scroll_mode, direction, interval | ||
while True: | ||
scroll_mode.wait() | ||
sleep(interval) | ||
mouse.scroll(0, direction) | ||
def show(self): | ||
x = self.pos[0] - self.size // 2 | ||
y = self.pos[1] - self.size // 2 | ||
self.move(x, y) | ||
super().show() | ||
|
||
mouse = Controller() | ||
listener = Listener(on_move = on_move, on_click = on_click) | ||
scroll_mode = Event() | ||
pos = mouse.position | ||
direction = 0 | ||
interval = 0 | ||
class Autoscroll(): | ||
def __init__(self): | ||
# modify this to adjust the speed of scrolling | ||
self.DELAY = 5 | ||
# modify this to change the button used for entering the scroll mode | ||
self.BUTTON_START = Button.middle | ||
# modify this to change the button used for exiting the scroll mode | ||
self.BUTTON_STOP = Button.middle | ||
# modify this to change the size (in px) of the area below and above the starting point where scrolling is paused | ||
self.DEAD_AREA = 30 | ||
# modify this to change the scroll mode icon | ||
# supported formats: svg, png, jpg, jpeg, gif, bmp, pbm, pgm, ppm, xbm, xpm | ||
# the path MUST be absolute | ||
self.ICON_PATH = str(Path(__file__).parent.resolve()) + "/icon.svg" | ||
# modify this to change the size (in px) of the icon | ||
# note that only svg images can be resized without loss of quality | ||
self.ICON_SIZE = 30 | ||
|
||
if self.ICON_PATH[-4:] == ".svg": | ||
self.icon = AutoscrollIconSvg(self.ICON_PATH, self.ICON_SIZE) | ||
else: | ||
self.icon = AutoscrollIconRaster(self.ICON_PATH, self.ICON_SIZE) | ||
|
||
self.mouse = Controller() | ||
self.scroll_mode = Event() | ||
self.listener = Listener(on_move=self.on_move, on_click=self.on_click) | ||
self.listener.start() | ||
self.looper = Thread(target=self.loop) | ||
self.looper.start() | ||
|
||
def on_move(self, x, y): | ||
if self.scroll_mode.is_set(): | ||
delta = self.icon.pos[1] - y | ||
if abs(delta) <= self.DEAD_AREA: | ||
self.direction = 0 | ||
elif delta > 0: | ||
self.direction = 1 | ||
elif delta < 0: | ||
self.direction = -1 | ||
if abs(delta) <= self.DEAD_AREA + self.DELAY * 2: | ||
self.interval = 0.5 | ||
else: | ||
self.interval = self.DELAY / (abs(delta) - self.DEAD_AREA) | ||
|
||
# modify this to adjust the speed of scrolling | ||
DELAY = 5 | ||
# modify this to change the button used for entering the scroll mode | ||
BUTTON_START = Button.middle | ||
# modify this to change the button used for exiting the scroll mode | ||
BUTTON_STOP = Button.middle | ||
# modify this to change the size (in px) of the area below and above the starting point where the scrolling is paused | ||
DEAD_AREA = 30 | ||
def on_click(self, x, y, button, pressed): | ||
if button == self.BUTTON_START and pressed and not self.scroll_mode.is_set(): | ||
self.icon.pos = (x, y) | ||
self.direction = 0 | ||
self.interval = 0.5 | ||
self.scroll_mode.set() | ||
self.icon.scroll_mode_entered.emit() | ||
elif button == self.BUTTON_STOP and pressed and self.scroll_mode.is_set(): | ||
self.scroll_mode.clear() | ||
self.icon.scroll_mode_exited.emit() | ||
|
||
def loop(self): | ||
while True: | ||
self.scroll_mode.wait() | ||
sleep(self.interval) | ||
self.mouse.scroll(0, self.direction) | ||
|
||
listener.start() | ||
autoscroll() | ||
app = QApplication(sys.argv) | ||
app.setQuitOnLastWindowClosed(False) | ||
autoscroll = Autoscroll() | ||
sys.exit(app.exec()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
from pynput.mouse import Button, Controller, Listener | ||
from threading import Event | ||
from time import sleep | ||
|
||
class Autoscroll(): | ||
def __init__(self): | ||
# modify this to adjust the speed of scrolling | ||
self.DELAY = 5 | ||
# modify this to change the button used for entering the scroll mode | ||
self.BUTTON_START = Button.middle | ||
# modify this to change the button used for exiting the scroll mode | ||
self.BUTTON_STOP = Button.middle | ||
# modify this to change the size (in px) of the area below and above the starting point where scrolling is paused | ||
self.DEAD_AREA = 30 | ||
|
||
self.mouse = Controller() | ||
self.scroll_mode = Event() | ||
self.listener = Listener(on_move=self.on_move, on_click=self.on_click) | ||
self.listener.start() | ||
|
||
def on_move(self, x, y): | ||
if self.scroll_mode.is_set(): | ||
delta = self.pos[1] - y | ||
if abs(delta) <= self.DEAD_AREA: | ||
self.direction = 0 | ||
elif delta > 0: | ||
self.direction = 1 | ||
elif delta < 0: | ||
self.direction = -1 | ||
if abs(delta) <= self.DEAD_AREA + self.DELAY * 2: | ||
self.interval = 0.5 | ||
else: | ||
self.interval = self.DELAY / (abs(delta) - self.DEAD_AREA) | ||
|
||
def on_click(self, x, y, button, pressed): | ||
if button == self.BUTTON_START and pressed and not self.scroll_mode.is_set(): | ||
self.pos = (x, y) | ||
self.direction = 0 | ||
self.interval = 0.5 | ||
self.scroll_mode.set() | ||
elif button == self.BUTTON_STOP and pressed and self.scroll_mode.is_set(): | ||
self.scroll_mode.clear() | ||
|
||
def start(self): | ||
while True: | ||
self.scroll_mode.wait() | ||
sleep(self.interval) | ||
self.mouse.scroll(0, self.direction) | ||
|
||
autoscroll = Autoscroll() | ||
autoscroll.start() |