moses-palmer / pynput

Sends virtual input commands
GNU Lesser General Public License v3.0
1.79k stars 248 forks source link

pyperclip.paste() doesnt work on mouse is pressed #360

Closed bf-malefiz closed 3 years ago

bf-malefiz commented 3 years ago

I'm trying to copy data on mousepress and execute some code before it gets released with pynput and pyperclip. Sadly I can't make it work. The clipboard is never up to date.

It is getting copied but I can't access it before my mouse gets released. Is it Threads not being handled well by me? Can I somehow synchronize them or supress the release of the mouse to avoid getting data to late? Thanks for your help.

from pynput.keyboard import Key, Controller as KeyController
from pynput.mouse import Controller as MouseController
from pynput.mouse import Listener
from PyQt5.QtWidgets import QApplication, QWidget
import pyperclip
import sys

class Controller():

    def __init__(self):
        self.keyboard = KeyController()
        self.mouse = MouseController()
        self.listener = None

    def activate_listener(self, active):

        def on_click(x, y, button, pressed): 
            if pressed: 
               print(self.copy_clipboard()) # prints empty clipboard
            else:
               print(self.copy_clipboard()) # prints clipboard

        if active:
            self.listener = Listener(on_click=on_click)
            self.listener.start()
        else:
            self.listener.stop()

    def copy_clipboard(self):
        self.keyboard.press(Key.ctrl)
        self.keyboard.press('c')
        self.keyboard.release(Key.ctrl)
        self.keyboard.release('c')
        return pyperclip.paste()

if __name__ == '__main__':
    app = QApplication([]) 
    ex = QWidget()
    ex.show() 
    c = Controller()
    c.activate_listener(True)
    sys.exit(app.exec_())
moses-palmer commented 3 years ago

Thank you for your report.

As to the reason for your issues, I can only speculate. It seems plausible that the clipboard has not yet been updated following self.keyboard.release('c') when you invoke pyperclip; I doubt there is any synchronisation between the system fake event consumer and the system clipboard.

To test this hypothesis, have you tried applying a small delay before calling pyperclip.paste()?

bf-malefiz commented 3 years ago

A time.sleep(0.2) kinda fixed the issue. I am now able to get the data before the mouse gets released but it feels realy inconsistent and I guess I have to adjust the sleep parameter if I want to implement functions with longer runtimes. And obviously it feels kinda clunky ^^

Is there a way to simply flag the mouse and block inputs depending on the flag when the mouse is pressed? Or maybe apply some sync. I guess I have to take Winapi in consideration, right?

moses-palmer commented 3 years ago

I'm afraid that I don't know. If possible, you would have to dive rather deep into the win32 API.

In any case, this is out of scope for this library, so I will close this issue.