How to read keypresses in the background in python - python-3.x

I get that it's a very difficult thing to pick up on in the background, but what I'm looking for is a program that records a keypress, and how much time it takes between keypresses. None of what I have looked into was able to record in the background, or actually work.
EDIT:
import win32con, ctypes, ctypes.wintypes
def esc_pressed():
print("Hotkey hit!")
ctypes.windll.user32.RegisterHotKey(None, 1, 0, 0xDD) # this binds the ']' key
try:
msg = ctypes.wintypes.MSG()
ctypes.windll.user32.GetMessageA
while ctypes.windll.user32.GetMessageA(ctypes.byref(msg), None, 0, 0) != 0:
if msg.message == win32con.WM_HOTKEY:
esc_pressed()
ctypes.windll.user32.TranslateMessage(ctypes.byref(msg))
ctypes.windll.user32.DispatchMessageA(ctypes.byref(msg))
finally:
ctypes.windll.user32.UnregisterHotKey(None, 1)
This allows for the program to work in the background, but it takes the inputted character you bound, instead of picking up on it. I still need to make sure the inputted character gets to the window with focus.

You probably have to catch the key and then simulate the same key press again. Try checking out Python Keyboard module for that.
EDIT: Added code sample.
import keyboard, time
def KeyPressSample(startkey='tab', endkey='esc'):
while True: # making a inifinte loop
try:
if keyboard.is_pressed(startkey):
time.sleep(0.25)
print("%s Key pressed." % startkey)
elif keyboard.is_pressed(endkey):
print("%s Key pressed." % endkey)
break
except KeyboardInterrupt:
print('\nDone Reading input. Keyboard Interupt.')
break
except Exception as e:
print(e)
break

Related

Convert text to speech on mac when button pressed

I am trying to create a script which will read a text file and then speak one line of the file every time I press a button on my keyboard. I am using the system accessibility voice on my Mac as the voice sounds more human than some of the python modules I tried.
So far my script runs and speaks a line but the spoken lines are not in order but rather are just lines spoken at random, whereas I would like each line to be spoken once and in order.
Also, I would rather use another key (not alphanumeric) such as right arrow to invoke the function but not sure how to specify that in my script?
I am just learning to code so any help would be much appreciated.
I am using Python 3.9.1 on Mac OSX 10.15.5
filename = ('file.txt')
with open(filename) as f:
lines = f.readlines()
# for x in lines:
# pass
def say():
while True:
try: # used try so that if any key other than the specified key is pressed an error will not be shown
for x in lines:
if keyboard.is_pressed('l'): # if key 'l' is pressed
subprocess.call(['say', x])
print('You Pressed A Key!')
#break # finishing the loop
except:
break # this should break loop if user presses a key other than the given key but doesn't work
say()
Ok I have now managed to fix the issue of reading from a file and reading each line in sequence (see clode below).
And aparantly you can just specify the key with 'up' or 'right' which works. It does output random characters to the screen so if anyone has a better way of doing this, I'd love to hear it
import keyboard
import subprocess
filename = ('text.txt')
with open(filename) as f:
lines = f.readlines()
def say():
i=0
while i <len(lines):
try: # used try so that if any key other than the specified key is pressed an error will not be shown
if keyboard.is_pressed('up'): # if key 'up' is pressed
subprocess.call(['say', lines[i]])
i += 1
except:
break # this should break loop if user presses a key other than the given key but doesn't work
say()
import keyboard
import subprocess
CURRENT_LINE = 0 #records line to be read out, first line is 0.
def ttsLine(line): #TTS function, uses macs say as per you requested.
try:
k = subprocess.check_output(["say",line.strip()]) #using subprocess, line.strip() to clean each line.
return True #returns true so we know if say command was successful
except:
return False #returns false if exceptions occured.
filename = ('text.txt') #text file with lines to be read.
with open(filename) as f:
lines = f.readlines() #saving lines to array.
while True:
keyboard.wait("up") #Waits until up key is pressed.
if not ttsLine(lines[CURRENT_LINE]): #if ttsLine returned false, something went wrong and script halts.
print("Something went wrong while reading out", lines[CURRENT_LINE])
break
CURRENT_LINE += 1 #else we update line to next one
if CURRENT_LINE == len(lines): #if all lines have been read, script ends.
break

Format controlled input using PyInquirer

I want to create a script that uses a time input from the user. At the moment I am using PyInquirer because it looks cool but I am not sure if it is capable of doing what I need.
The first prompt asks the user to choose Duration or Time like so:
If the user then chooses Time the next prompt looks as follows:
Here the input must only have the default format of HH:MM [AM/PM] where values can only be selected by using the up and down arrows or typed. The cursor must ignore and skip the ':'.
Therefore, the HH and MM may be typed or spinned using the up and down arrow keys and the AM/PM are spinned as well. If typing the HH and MM the cursor must automatically skip the colon.
Here is my code so far:
from PyInquirer import prompt, print_json
typeQ = [
{
'type' : 'list',
'name' : 'type',
'message' : 'Duration or Time based?',
'choices' : [
'Duration',
'Time'
]
}
]
time = [
{
'type' : 'input',
'name' : 'time',
'message' : 'Specify time:'
}
]
typeA = prompt(typeQ)
if (typeA == 'Duration'):
pass
else:
time = prompt(time)
This is an example how to use pythons curses library with arrows as key input in a while loop. The mytime() method is only accessed via the arrow key strokes. Some additional keys are also added such you can play with it. See "#" for inline comments.
Please post next time your example code and what you've tried fist which is behind the screens you show in the question. Its sailing a little blind without code. If included it would make life easier to anticipate on what structure you use. It also helps up-voting your question instead of people down-voting it due to so-called lack of effort.
Now you have what I've posted and possibly you have to retrofit it to work for your own code. It was a fun morning exercise. Enjoy.
import curses, sys, time, re
screen = curses.initscr()
curses.curs_set(0)
screen.keypad(True)
curses.noecho()
regex_time = re.compile('[0-9][0-9][:][0-9][0-9]') # time expression selection key.
def mytime():
screen.addstr("\nTime entry please + [enter]. Input format is [HH:mm].\n")
event = screen.getstr(5) # use (0, 0, 15) for location of input string top left in cmd window.
if regex_time.match(event.decode()):
screen.addstr("\n You entry = %s h.\n\n >> Add code to do something else here << \n\n" % event.decode())
screen.refresh()
time.sleep(2)
# do something else goes here.
else:
screen.addstr('\nDid not receive time\nTry again next round.\n')
screen.refresh()
time.sleep(2)
# do something else goes here.
while True:
try:
screen.addstr("Press a key\n")
curses.echo()
event = screen.getch() # get single character
screen.refresh()
if event == curses.KEY_LEFT:
screen.addstr("Left Arrow Key pressed\n")
screen.refresh()
time.sleep(0.5)
mytime()
elif event == curses.KEY_RIGHT:
screen.addstr("Right Arrow Key pressed\n")
screen.refresh()
time.sleep(2)
elif event == 81: # 'Q' for quite program.
curses.echo() # shows which char you pressed.
screen.addstr('\nThe Quite key "%s" was pressed\n' % (event))
screen.refresh()
time.sleep(3)
break
else:
# keystroke identification except for above and regular expression that are comform time annotation.
curses.echo() # shows which char you pressed.
screen.addstr('\nThe key "%s" was pressed\n' % (event))
time.sleep(2)
screen.refresh()
except Exception as err:
# continue
print (err)
# below code could replace the break in the quite elif statement.
screen.addstr("\nExit program.\n")
screen.refresh()
time.sleep(3)
curses.endwin()

Try-except bug in a while

I ran into a particularly infamous problem: I'm creating a sort of console program on Python 3.6, but when I write a command that is not 'exit' or 'shutdown', if this command is incorrect, the console enters the loop and keeps trying to execute the incorrect command by spamming in the console the error message defined with the 'except' instruction.
I tried to delete the 'try' and 'except' statement, but in this way, if the command is incorrect, the program is interrupted and the closing command is not executed.
P.S. I forgot to write that with the 'try-except' instruction, if i press enter without writing anything, the bug leaves the same.
Machine code - Start
import os
print("$ ", end="") #No end-line
console_standard_input = input()
while console_standard_input != ".shutdown":
if (console_standard_input == "exit"):
print("Shutting down machine...")
sys.exit(-1)
try:
machine_exec_script_path_complete = "Disk\{0}".format(console_standard_input)
os.system(machine_exec_script_path_complete)
except:
print("Unable to exec this function - Error")
print("")
print("$ ", end="")
#Machine code - Stop
I haven't been able to find a solution yet.
I'm not very good at Python, so I wanted to ask the help of an expert.
Try:
import os
print("$ ", end="") #No end-line
console_standard_input = input()
while console_standard_input != ".shutdown":
if(console_standard_input == "exit"):
print("Shutting down machine...")
sys.exit(-1)
try:
machine_exec_script_path_complete = "Disk\{0}".format(console_standard_input)
os.system(machine_exec_script_path_complete)
except:
print("Unable to exec this function - Error")
print("")
print("$ ", end="")
console_standard_input = input()
Explanation - if you wish to keep evaluating input - you have to put input there explicitly. Assigning input() to a variable assigns only it's value (user input), not the whole operation i.e. it doesn't force it to repeat, whenever the variable is reevaluated...

Python: Printing data and receiving user input simultaneously

I want to be able to receive user input and print stuff simultaneously, without them interfering. Ideally, that would be printing regularly and having the user type input to the bottom of the terminal window, for example:
printed line
printed line
printed line
printed line
printed line
(this is where the next print would happen)
Enter Input: writing a new input...
This should look like a chat app or something of that sort.
If there is no good way to do that, any way to print above the input line would be amazing too.
Thanks!
Sadly it is not very feasible to both take input and give output in python, without importing modules to directly interact with the OS.
But you can can get pretty close to it with this code:
import curses
import random # for random messages
#this should be async
def get_message():
message = [str(random.randint(0,9)) for i in range(15)]
return "".join(message)
def handle_command(cmd): # handle commands
if cmd=="exit":
exit(0)
def handle_message(msg): # send a message
raise NotImplementedError
def draw_menu(stdscr):
stdscr.erase()
stdscr.refresh()
curses.raw()
k = 0
typed=""
while True:
# Initialization
stdscr.erase()
height, width = stdscr.getmaxyx()
stdscr.addstr(0, 0, "Welcome to chat app")
msg = get_message()
if msg: # add a message if it exists
stdscr.addstr(1, 0, msg)
if k==ord("\n"): # submit on enter
if typed.startswith("/"): # execute a command
typed = typed[1:]
handle_command(typed)
elif typed.startswith("./"): # bypass commands with a dot
typed = typed[1:]
handle_message(typed)
else:
handle_message(typed) # send the message
typed = ""
elif k==263: # Backspace
typed = typed[:-1] # erase last character
stdscr.addstr(height-1, 0, typed)
elif k==3: # Ctr+C
typed="" # Delete the whole string
stdscr.addstr(height-1, 0, typed)
elif k!=0:
typed += chr(k) # add the char to the string
stdscr.addstr(height-1, 0, typed)
stdscr.refresh() # refresh
# Wait for next input
k = stdscr.getch()
def main():
curses.wrapper(draw_menu)
if __name__ == "__main__": # dont import
main()
the only thing that is to do to update the messages is to type a new char.
And I do not recommend you to build a chat in the terminal for anything other then educational value (trust me I tried it).
It would be better if you tried it using a web platform (e.g. Tauri or Electron)
Also the code cannot:
insert automatic line breaks (it errors)
send any messages (must implement yourself)
show any user names (must implement yourself)

How to do computing until s is pressed?

How can I do a computing program in Python 3 such that it does computing while program is running, shows the computing status when one presses s and quits the program when one presses ctrl+c? I know I can use try-catch but how can I read when user presses s? I know input but it stops the computing when waits the key press. I'm using Ubuntu 17.04 on bash command line.
I tried
n = 0
try:
while True:
n += 1
except KeyboardInterrupt:
print("Stopping")
Since you are on Linux you can use the curses module to do that.
The way curses works is simple. We set curses to "monitor" the compute() function (the keypress variable works as an event handler and you can call it as you wish - I chose to call it keypress).
As you can also read in the documentation here, the most common way to get input to a window is to use its getch() method, but getch() pauses and waits for the user to hit a key. To change this behavior we use the method nodelay(1). By using nodelay(1), getch() for the window becomes non-blocking and returns curses.ERR (a value of -1) when no input is ready.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import curses
def compute(keypress):
keypress.nodelay(1)
n = 0
try:
while True:
n += 1
key = keypress.getch()
if key != -1 and key==115: # ord('s')=115
keypress.addstr(str(n) +'\n')
except KeyboardInterrupt:
sys.exit(0)
if __name__ == '__main__':
curses.wrapper(compute)

Resources