Typing Tool

Typing Tool
Python June 15, 2026 2 Views

import pygame
import pyttsx3
import keyboard  # To block system-level keys
import threading
import queue  # For managing speech tasks

# Initialize text-to-speech engine
engine = pyttsx3.init()

# Queue for speech tasks
speech_queue = queue.Queue()

# Function to set the female voice and adjust settings
def set_female_voice():
   voices = engine.getProperty('voices')
   female_voice = None
   for voice in voices:
       if 'female' in voice.name.lower():
           female_voice = voice
           break
   if female_voice:
       engine.setProperty('voice', female_voice.id)
   else:
       print("No female voice found. Using default voice.")
   engine.setProperty('rate', 200)  # Speaking speed
   engine.setProperty('volume', 1.0)  # Set volume to max

set_female_voice()

# Background thread to process speech from the queue
def speech_worker():
   while True:
       key = speech_queue.get()  # Get the next key from the queue
       if key is None:  # Sentinel to stop the thread
           break
       engine.say(key)
       engine.runAndWait()
       speech_queue.task_done()

# Start the speech worker thread
speech_thread = threading.Thread(target=speech_worker, daemon=True)
speech_thread.start()

# Function to enqueue speech tasks
def speak_key_async(key):
   speech_queue.put(key)

# Initialize Pygame
pygame.init()

# Set up the screen for full-screen mode
screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
pygame.display.set_caption("Kid's Alphabet and Numbers Typing")

# Set the font and size for larger text
font_size = 420
font = pygame.font.Font(None, font_size)

# Text wrapping settings
margin = 50
line_height = font_size * 1.2

# Allowed keys (a-z, A-Z, 0-9)
allowed_keys_lower = [chr(i) for i in range(97, 123)]
allowed_keys_upper = [chr(i) for i in range(65, 91)]
allowed_keys_numbers = [str(i) for i in range(10)]

# Block system-level keys
keyboard.block_key('windows')
keyboard.block_key('alt')
keyboard.block_key('tab')

# Initialize text content and scroll variables
text = ""
caps_lock = False
scroll_y = 0
max_scroll = 0

def wrap_text(text, font, max_width):
   lines = []
   current_line = ""

   for char in text:
       test_line = current_line + char
       text_surface = font.render(test_line, True, (0, 0, 0))

       if text_surface.get_width() > max_width - 2 * margin:
           if current_line:
               lines.append(current_line)
           current_line = char
       else:
           current_line = test_line

   if current_line:
       lines.append(current_line)

   return lines

def update_max_scroll_and_scroll(num_lines, screen_height):
   global max_scroll, scroll_y
   total_text_height = num_lines * line_height
   max_scroll = max(0, total_text_height - screen_height)
   scroll_y = max_scroll

# Main loop
running = True
while running:
   screen.fill((255, 255, 255))
   updated = False

   for event in pygame.event.get():
       if event.type == pygame.QUIT:
           running = False

       if event.type == pygame.KEYDOWN:
           key_name = pygame.key.name(event.key)

           if event.key == pygame.K_CAPSLOCK:
               caps_lock = not caps_lock

           if key_name in allowed_keys_lower or key_name in allowed_keys_upper:
               if caps_lock or pygame.key.get_mods() & pygame.KMOD_SHIFT:
                   text += key_name.upper()
                   speak_key_async(key_name.upper())
               else:
                   text += key_name.lower()
                   speak_key_async(key_name.lower())
               updated = True
           elif key_name in allowed_keys_numbers:
               text += key_name
               speak_key_async(key_name)
               updated = True
           elif event.key == pygame.K_BACKSPACE:
               text = text[:-1]
               updated = True
           elif event.key == pygame.K_F12:
               running = False

   if updated:
       screen.fill((255, 255, 255))
       lines = wrap_text(text, font, screen.get_width())
       update_max_scroll_and_scroll(len(lines), screen.get_height())

       visible_lines = lines[int(scroll_y // line_height):]

       if len(visible_lines) * line_height > screen.get_height():
           scroll_y += line_height

       for i, line in enumerate(visible_lines):
           text_surface = font.render(line, True, (0, 0, 0))
           screen.blit(text_surface, (margin, margin + i * line_height - (scroll_y % line_height)))

       pygame.display.flip()

# Stop the speech thread gracefully
speech_queue.put(None)
speech_thread.join()

keyboard.unblock_key('windows')
keyboard.unblock_key('alt')
keyboard.unblock_key('tab')

pygame.quit()
 

Leave a Comment