Format controlled input using PyInquirer - python-3.x

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()

Related

Do I need to look for a key down and up event to avoid double occurrence of my else block?

Wondering why its printing my else statement twice in this scenario. In theory it should just execute it once after an incorrect key is read, and loop back.
the out put I am getting after pressing a non 'enter' key How can I avoid this?
import random
import keyboard
#Constant values to assign as a win or loss
_WIN = 1
_LOSE = 0
#Create and store game hand choices
handChoice = ['Spock', 'Lizard', 'Rock', 'Paper', 'Scissors']
print('\nThis is advanced Rock, Paper, Scissors! Press ENTER to start the automated game->')
while True:
if keyboard.read_key() == 'enter':
break
else:
print('Please press ENTER!')
#Hand choices randomly assigned to player 1
player1 = random.choice(handChoice)
print('Player 1 uses ' + player1 + '!\n')
Looking true the docs you could use this:
keyboard.wait('enter')
It will also use less cpu. But you would need the async library with timeout to also give output.
you could also use this:
while True:
if keyboard.read_key() == 'enter':
break
elif event.event_type == keyboard.KEY_DOWN:
print('Please press ENTER!')

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)

pynput - Not seeing capital letters

pynput not seeing cap letters directly.
Using pynput to catch combo keys. Able to read 'h' but not 'H'. Python 3.6, windows 10 machine, tried running as admin. Able to see Key.shift and Key.ctrl_l but not the proper converted key. I hope I'm clear.
Perhaps my code below is missing something or it currently is not able to read combo-keys.
from pynput.keyboard import Key, Listener
def look_for_key(key):
letter = str(key)
letter = letter.replace("'", "")
if letter == 'Key.esc':
return False
print(letter)
with Listener(on_press = look_for_key) as l:
l.join()
From seeing other posts and examples, I should see it print out "H" if that is typed, instead I see "h".
You can detect if the key pressed equals Key.caps_lock and based on that, print or modify the key with the upper() method, but you have to transform the key to string.
Second step, create a global variable 'count' that will save the number of times the caps_lock key is pressed, in order to detect if the caps_lock was turned off. If the count variable is odd the program will print an uppercase key, otherwise, in lowercase.
from pynput.keyboard import Key, Listener
count = 0
def on_press(key):
global count
if key == Key.caps_lock:
count = count + 1
elif count%2!=0:
print(str(key).upper())
else:
print(str(key).lower())
with Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()

How to communicate two python files so one prints just before the other reads though the console (interactive)

what I want is something like this:
The first file just prints as soon as the 2nd has read
# a.py
print('pepe')
# wait till the other had read
print(23)
The second program uses data from the later
# b.py
name = input()
age = int(input())
print('Hi ' + name + ', you are ' str(age))
So I can see in the console:
Hi pepe, you are 23
I want to do this because, I waste a lot of time typing in the console. And I want to do it automatically.
Just in case, I browsed for this thing a long time, but no idea, that is why I decided to ask here.
A couple of different ways.
1) while True:
an infinite loop that requires you to use some sort of
while True:
cmd = input("type something")
if cmd == 'e':
do something
elif cmd == 'f':
do something else
else:
do that last thing
2) input("press enter to continue")
input('press enter to continue')
Hopefully that gets you what you need...
You can also learn more here: How do I make python to wait for a pressed key

How to read keypresses in the background in python

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

Resources