Search code examples
inputtextkeyboardvirtualpysimplegui

Is it Possible to set "Windows On-Screen Keyboard" as an input in sg.InputText field ( PySimpleGUI)?


Dears,

Is it Possible to set "Windows On-Screen Keyboard" as an input in sg.InputText field?

Thanks in advance

enter image description here ==> The Code

enter image description here ==> Desired Output

enter image description here ==> Split Keyboard to lines using "Menu Option"


Solution

  • Here's the demo code for you. Some functions for backspace key not built under PySimpleGUI, so tkinter code is required, like element.widget. The event for button 'OK' not included here. You can replace the keyboard string with yours.

    import PySimpleGUI as sg
    
    keys = ["QWERTYUIOP", "ASDFGHJKL", "ZXCVBNM"]
    chars = ''.join(keys)
    lines = list(map(list, keys))
    lines[0] += ["\u232B", "Esc"]
    col = [[sg.Push()] + [sg.Button(key) for key in line] + [sg.Push()] for line in lines]
    
    layout = [
        [sg.Text("Username"), sg.Push(), sg.Input(key="Username")],
        [sg.Text("Password"), sg.Push(), sg.Input(key="Password")],
        [sg.Push(), sg.Button("OK"), sg.Button("Cancel"),sg.Push(), sg.Button("Keyboard")],
        [sg.pin(sg.Column(col, visible=False, expand_x=True, key='Column', metadata=False), expand_x=True)],
    ]
    
    window = sg.Window('ACCESS', layout)
    
    while True:
    
        event, values = window.read()
    
        if event in (sg.WIN_CLOSED, "Cancel"):
            break
        elif event == "Keyboard":
            visible = window["Column"].metadata = not window["Column"].metadata
            window["Column"].update(visible=visible)
        elif event in chars:
            element = window.find_element_with_focus()
            if isinstance(element, sg.Input):
                if element.widget.select_present():
                    element.widget.delete(sg.tk.SEL_FIRST, sg.tk.SEL_LAST)
                element.widget.insert(sg.tk.INSERT, event)
        elif event == "\u232B":
            element = window.find_element_with_focus()
            if element.widget.select_present():
                element.widget.delete(sg.tk.SEL_FIRST, sg.tk.SEL_LAST)
            else:
                insert = element.widget.index(sg.tk.INSERT)
                if insert > 0:
                    element.widget.delete(insert-1, insert)
    
    window.close()
    

    enter image description here

    With MenuOption element, there's option enable_events, so tkinter call required here. There are three-line different keyboard, so each Column element for each keyboard line.

    import PySimpleGUI as sg
    
    def callback(var, index, mode):
        window.write_event_value("Optionmenu", window['Optionmenu'].TKStringVar.get())
    
    keys = ["QWERTYUIOP", "ASDFGHJKL", "ZXCVBNM"]
    chars = ''.join(keys)
    lines = list(map(list, keys))
    lines[0] += ["\u232B", "Esc"]
    
    layout = [
        [sg.Text("Username"), sg.Push(), sg.Input(key="Username")],
        [sg.Text("Password"), sg.Push(), sg.Input(key="Password")],
        [sg.Push(), sg.Button("OK"), sg.Button("Cancel"),sg.Push(), sg.OptionMenu([f"Keyboard Line {i+1}" for i in range(3)], key='Optionmenu')],
        [sg.Column([[sg.Push()] + [sg.Button(key) for key in line] + [sg.Push()]], key=f"Keyboard Line {i+1}", expand_x=True, visible=False) for i, line in enumerate(lines)],
    ]
    
    window = sg.Window('ACCESS', layout, finalize=True)
    window['Optionmenu'].TKStringVar.trace("w", callback)   # enable events
    keyboard = None
    
    while True:
    
        event, values = window.read()
    
        if event in (sg.WIN_CLOSED, "Cancel"):
            break
        elif event == "Optionmenu":
            if keyboard is not None:
                window[keyboard].update(visible=False)
            keyboard = values["Optionmenu"]
            window[keyboard].update(visible=True)
        elif event in chars:
            element = window.find_element_with_focus()
            if isinstance(element, sg.Input):
                if element.widget.select_present():
                    element.widget.delete(sg.tk.SEL_FIRST, sg.tk.SEL_LAST)
                element.widget.insert(sg.tk.INSERT, event)
        elif event == "\u232B":
            element = window.find_element_with_focus()
            if element.widget.select_present():
                element.widget.delete(sg.tk.SEL_FIRST, sg.tk.SEL_LAST)
            else:
                insert = element.widget.index(sg.tk.INSERT)
                if insert > 0:
                    element.widget.delete(insert-1, insert)
    
    window.close()
    

    enter image description here