Невозможно получить клавишу клавиатуры из переменной - PullRequest
0 голосов
/ 11 июля 2020

Итак, я пытаюсь сделать программу, которая может удерживать / автоматически нажимать клавиши клавиатуры. Проблема в том, что программа не понимает клавишу для нажатия из переменной (полученной из Tkinter Entry), которую я даю.

Когда я использую pynput для нажатия клавиши, он говорит, что я не дал это значение:

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

Когда я использую pyauto gui для нажатия клавиши, он ничего не делает, он даже не возвращает ошибку.

Часть код не работает:

        #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()

1 Ответ

1 голос
/ 11 июля 2020

Основная проблема заключается в том, что вы импортируете только контроллер мыши

   from pynput.mouse import Button, Controller

и используете его для мыши и клавиатуры

   mousect = Controller()
   keyct = Controller()

, но у них разные контроллеры, которые работают по-разному.

Контроллер клавиатуры может получать строку, но контроллер мыши ожидает объект с .value

Вы должны использовать разные enet контроллеры

   from pynput import mouse
   from pynput import keyboard

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

, и это решает основную проблему.

Но есть другая проблема - after() (аналогично command= и bind()) ожидает имя функции без аргументов, и вы можете использовать lambda (например, command= или bind()), или вам нужно используйте аргументы после имени функции

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

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

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

Кстати: другая проблема в том, что ваш код не читается. Вы должны переместить вложенную функцию за пределы класса или создать метод класса, и тогда вам не понадобится global, а self.. Вы также можете использовать более удобочитаемые имена - ie. key_controller более читабельно, чем keyct.

См .: PEP 8 - Руководство по стилю для Python Код

EDIT:

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())

...