Python Forum
[Tkinter] Virtual keyboard
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] Virtual keyboard
#1
Hi everyone,

I'm trying to make a virtual keyboard in python (like Microsoft's on-screen keyboard) however
am experiencing a couple of glitches.

Code (unfinished however the letters are in):
from tkinter import *
from pynput.keyboard import Key, Controller
import string
from tkinter.ttk import *

letters = list(string.ascii_uppercase)
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

keyboard = Tk()
keyboard.title("Virtual Keyboard")
keyboard.focus_force()
keyboard.attributes("-topmost", True)

style = Style()
style.configure("W.TButton", font = ("calibri", 10, "bold"), foreground = "red", background = "black")

typer = Controller()

class Keyboard:
    def __init__(self):
        keyboard.config(bg = "black")

    @classmethod
    def type_key(cls, key):
        global typer
        print(str(key)) #test line
        typer.type(str(key))

class Interface:
    def __init__(self):
        main_funcs = Keyboard()
        x = 0
        y = 0
        abc_item = 0
        num_item = 0
        let = 0
        num = 0
        
        for item in letters:
            Button(keyboard, text = letters[abc_item], width = 5, style = "W.TButton", command = lambda: Keyboard.type_key(letters[let - 1])).grid(row = x, column = y)
            
            if x < 4.33333333 - 2:
                x += 1
            else:
                y += 1
                x = 0  

            abc_item += 1
            let += 1
            
load = Interface()
keyboard.mainloop()     
Glitches:
1. In the test line (next to comment), this should print the key clicked. However, it always
prints 'Z'

2. On-screen keyboard window always takes focus, therefore keys cannot be typed into another window

I would be grateful if anyone could help.
Reply
#2
I used a partial instead of lambda, but should be able to use either way. Why are you using indices into letters when you are iterating through letters? Here's my version:
class Interface:
    def __init__(self):
        for i, item in enumerate(letters):
            Button(keyboard, text = item, width = 5, style = "W.TButton", \
                   command = partial(Keyboard.type_key, item)) \
                   .grid(row = i // 7, column = i % 7)
As for hogging the keyboard, that is what that pynput.Controller() does. Read through the documentation and see if you can temporarily turn that on and off. You only need to control the keyboard for a brief moment after you press one of your virtual keyboard buttons.
Reply
#3
So what do I do?
Reply
#4
You read about the pynput package you are using to learn how it works. Maybe they have an example for making the keyboard type one key.
Reply
#5
from pynput.keyboard import, Key, Controller
keyboard = Controller()
keyboard.type("Hello World!")
This works!

Didn't mean the comma after import. Accident.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020