0

所以我正在尝试制作一个可以按住/自动点击键盘键的程序。问题是,程序不理解我给它的变量(从 Tkinter Entry 获得)中按下的键。

当我使用 pynput 按键时,它说我没有给它一个值:

AttributeError: 'str' object has no attribute 'value'

当我使用 pyautogui 按键时,它什么也不做,甚至不返回错误。

部分代码不起作用:

        #Autoclicking keyboard key (using pynput) (not working)
        #hold = whether to autoclick or hold key
        #clkdel = delay between keyboard presses
        #keyprsd = key to be pressed (tk.StringVar)
        #lf7 = listener for when to start/stop
        if int(hold.get()) == 1:
            print('Starting keyboard pressing...')
            while self.run == True:
                print('Pressed')
                master.after(clkdel, keyct.press(keyprsd.get()))
            lf7.stop()

完整代码:

import tkinter as tk
from pynput.keyboard import Key, Listener
from pynput.mouse import Button, Controller
from pynput import keyboard
import pyautogui

class GUI:
   def __init__(self, master):
       #Defining variables
       hold = tk.IntVar()
       keyprsd = tk.StringVar()
       self.run = False
       msbt = tk.IntVar()
       mousect = Controller()
       keyct = Controller()
       #Creating main window
       master = master
       master.title('Key Clicker')
       master.geometry('250x250')
       master.resizable(False, False)
       #Creating radio buttons:
       #Autoclick button
       self.autoclick = tk.Radiobutton(master, text='Autoclick', variable=hold, value=1)
       self.autoclick.grid(row=0, column=0, sticky='en', padx=30, pady=5)
       #Hold button
       self.holdbt = tk.Radiobutton(master, text='Hold', variable=hold, value=2)
       self.holdbt.grid(row=0, column=1, sticky='wn', padx=0, pady=5)
       #Creating keyboard button label
       self.kbtlabel = tk.Label(master, textvariable=keyprsd, width=10, bg='Light Blue')
       self.kbtlabel.grid(row=1, column=0, sticky='wens')
       #Creating keyboard button detection:
       #Functions to detect key to be pressed
       def lforsetkey():
           lst = Listener(on_press=ksetcall)
           lst.start()
       def ksetcall(key):
           print('{} was pressed'.format(key))
           keyprsd.set(key)
           return False
       #Functions to detect when to start and stop autoclicking/holding
       def f7press(key):
           print('{} was pressed'.format(key))
           if key == keyboard.Key.f7:
               self.run = False
           if key == keyboard.Key.f6:
               self.run = True
               stmouse()
           if key == keyboard.Key.f8:
               self.run = True
               stkey()
       def lforf7():
           global lf7
           lf7 = Listener(on_press=f7press)
           lf7.start()
       lforf7()
       #Creating key selection button
       self.kbtsel = tk.Button(master, text='Click and press a key', command=lforsetkey)
       self.kbtsel.grid(row=2, column=0, sticky='wen', padx=0)
       #Creating list for mouse buttons
       self.mslft = tk.Radiobutton(master, text='Left Click', variable=msbt, value=1)
       self.mslft.grid(row=1, column=1, sticky='en', padx=10)
       self.msrft = tk.Radiobutton(master, text='Right Click', variable=msbt, value=2)
       self.msrft.grid(row=2, column=1, sticky='en', padx=10)
       #Creating autoclick frequency label
       self.clklb = tk.Label(master, text='Autoclick frequency (ms)')
       self.clklb.grid(row=3, column=0)
       #Creating autoclick frequency entry
       self.clkent = tk.Entry(master)
       self.clkent.grid(row=3, column=1)
       #Creating mouse autoclick button
       def stmouse():
           self.run = True
           lforf7()
           try:
               clkdel = int(self.clkent.get())
           except ValueError:
               print('Value Error')
           #Autoclicking left button
           if int(msbt.get()) == 1 and int(hold.get()) == 1:
               print('Starting mouse autoclick...')
               while self.run == True:
                   print('Clicked')
                   master.after(clkdel, mousect.click(Button.left))
               lf7.stop()
           #Autoclicking right button
           elif int(msbt.get()) == 2 and int(hold.get()) == 1:
               print('Starting mouse autoclick...')
               while self.run == True:
                   print('Clicked')
                   master.after(clkdel, mousect.click(Button.right))
               lf7.stop()
           #Holding left button
           elif int(msbt.get()) == 1 and int(hold.get()) == 2:
               print('Starting mouse holding...')
               while self.run == True:
                   pyautogui.mouseDown(button='left')
               lf7.stop()
               pyautogui.mouseUp(button='left')
           #Holding right button
           elif int(msbt.get()) == 2 and int(hold.get()) == 2:
               print('Starting mouse holding...')
               while self.run == True:
                   pyautogui.mouseDown(button='right')
               lf7.stop()
               pyautogui.mouseUp(button='right')
           else:
               print('Error')
       self.msbt = tk.Button(master, text='Click to start holding/autoclicking mouse', command=stmouse)
       self.msbt.grid(row=4, column=0, columnspan=2, sticky='swe', pady=5)
       #Creating keyboard button
       def stkey():
           #Setting up variables and starting listener
           self.run = True
           lforf7()
           try:
               clkdel = int(self.clkent.get())
           except ValueError:
               print('Value Error')
           #Autoclicking keyboard key (using pynput) (not working)
           #hold = whether to autoclick or hold key
           #clkdel = delay between keyboard presses
           #keyprsd = key to be pressed (tk.StringVar)
           #lf7 = listener for when to start/stop
           if int(hold.get()) == 1:
               print('Starting keyboard pressing...')
               while self.run == True:
                   print('Pressed')
                   master.after(clkdel, keyct.press(keyprsd.get()))
               lf7.stop()
           #Holding keyboard key (also not working)
           elif int(hold.get()) == 2:
               print('Holding keyboard...')
               while self.run == True:
                   pyautogui.keyDown(keyprsd.get())
               lf7.stop()
               print('Stopping')
               pyautogui.keyUp(keyprsd.get())
           else:
               print('Error')
       self.kbt = tk.Button(master, text='Click to start holding/autoclicking keyboard', command=stkey)
       self.kbt.grid(row=5, column=0, columnspan=2, sticky='swe', pady=5)
root = tk.Tk()
GUI(root)
root.mainloop()
4

1 回答 1

2

你的主要问题是你只导入鼠标控制器

   from pynput.mouse import Button, Controller

你用它来做鼠标和键盘

   mousect = Controller()
   keyct = Controller()

但他们有不同的控制器,它们以不同的方式工作。

键盘控制器可以获取字符串,但鼠标控制器需要对象.value

你应该使用不同的控制器

   from pynput import mouse
   from pynput import keyboard

   mousect = mouse.Controller()
   keyct = keyboard.Controller()

这解决了主要问题。


但是还有其他问题 - after()(类似于command=and bind())需要没有参数的函数名,你可以使用lambda(比如 in command=or bind())或者你必须在函数名之后使用参数

   master.after(clkdel, keyct.press, keyprsd.get())

   master.after(clkdel, mousect.click, Button.left)

   master.after(clkdel, mousect.click, Button.right)

顺便说一句:另一个问题是您的代码不可读。global您应该将嵌套函数移到类外或创建类方法,然后就不需要了self.。您还可以使用更具可读性的名称 - 即。key_controller那么更具可读性keyct

请参阅:PEP 8 -- Python 代码样式指南


编辑:

Listener提供带有密钥信息的特殊对象,然后将其StringVar作为字符串放入,然后从字符串中获取它StringVar并在其中使用该字符串press()-它可以用于普通键,但不适用于特殊键。

您必须保留原始对象并将此对象press()用于所有键(普通和特殊)。IE。

   def ksetcall(key):

       self.key = key   # keep original object 

       print('{} was pressed'.format(key))
       keyprsd.set(key)
       return False

然后

 keyct.press(self.key)

代替keyct.press(keyprsd.get())

于 2020-07-11T16:46:46.407 回答