Search code examples
pythonkeyboardbarcode

Keyboard library event blocks execution


I am trying to transfer data from a barcode scanner to a machine through socket messaging. At this point the scanner plays no role in the script. It should works with keyboard only.

In the main function, I'm waiting for keyboard inputs. If there were some, and a certain amount of time passed (timeout_duration=0.5), the script should pass on the data with the process_barcode() function. But it never gets to that to that point, even though it reaches the time limit. Am I too clouded to figure out the syntax issue here?

import socket
import keyboard
import time

# TCP/IP server details
server_ip = "10.10.0.0"
server_port = 5200

# Timeout for barcode input in seconds
timeout_duration = 0.5

def send_data(data):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((server_ip, server_port))
        s.sendall(data.encode())

def process_barcode(barcode):
    if ';' in barcode:
        forwarded_data = f"{barcode};1"
    else:
        forwarded_data = f"test;{barcode};1"
    
    send_data(forwarded_data)

def main():
    barcode = ""
    last_key_time = time.time()
    
    print("Waiting for barcode scanner input...")
    
    while True:
        event = keyboard.read_event(suppress=True)
        
        if event.event_type == keyboard.KEY_DOWN:
            print(time.time() - last_key_time)
            barcode += event.name
            print(barcode)
            last_key_time = time.time()
        
        # Check for timeout
        if (time.time() - last_key_time > timeout_duration) and barcode:
            # Process the received barcode
            print("success")
            process_barcode(barcode)
            barcode = ""
        


if __name__ == "__main__":
    main()

Solution

  • Your problem is with this line here:

    event = keyboard.read_event(suppress=True)
    

    The read_event method blocks execution so the following conditionals will only execute when a new key press occurs. Meaning this conditional:

    if (time.time() - last_key_time > timeout_duration) and barcode:
    

    Is only checked after a new key press so last_key_time is overwritten before every check and thus you never have a great enough difference between time.time() and last_key_time to trigger the code following the conditional. You can test this by printing time.time() - last_key_time.

    You need to rewrite the code. I refactored your main function to something like this that appears to function as desired:

    def main():
        barcode = ""
        last_key_time = time.time()
        
        print("Waiting for barcode scanner input...")
        
        keyboard.start_recording()
        old_keys_pressed = []
        while True:
            new_keys_pressed = keyboard.stop_recording()
            keyboard.start_recording()
    
            if new_keys_pressed != old_keys_pressed:
                print(time.time() - last_key_time)
                barcode += "".join([str(x) for x in new_keys_pressed])
                print(barcode)
                last_key_time = time.time()
            
            # Check for timeout
            if (time.time() - last_key_time > timeout_duration) and barcode:
                # Process the received barcode
                print("success")
                process_barcode(barcode)
                barcode = ""