How can I control a Python script continuously with key inputs? - python

I have created a Python script that can take commands from a pipe (named pipe1). You can find the Script on Pastebin.
I tested the script with this other script:
import sys
fw = open("pipe1", "w" )
fw.write('fd\n')
fw.close()
and it worked.
Now I want to control the script with another Python script, that could write in the pipe if I press w, a, s, d or p and display me the keys, that i press.
In this example I just want to print the keys that I press. I would later add the fw.write commands to write in the pipe, which I tested before:
def key_inp(event):
print 'Key:', event.char
key_press = event.char
sleep_time = 0.030
while True:
try:
if key_press.lower() == 'w':
print "w"
elif key_press.lower() == 's':
print "s"
elif key_press.lower() == 'a':
print "a"
elif key_press.lower() == 'd':
print "d"
elif key_press.lower() == 'q':
print "q"
elif key_press.lower() == 'e':
print "e"
elif key_press.lower() == 'p':
print "stop"
except(KeyboardInterrupt):
print('Finished')
My problem is, that the script that i wrote (and improved with a stackoverflow member) closes immediately when i open it.
Can anyone explain me why, and how i can fix it so that the script stays open the whole time until i interrupt it with Ctrl+c?

EDIT: This answer relies on installing the readchar module. You can install it via pip: pip install readchar.
The code you are trying to use has no functionality: you only define a function, but never call upon it. On top of that, it contains indentation errors.
Something along the lines of what you are trying to achieve, but with a dot as finish key:
import readchar
while True:
key = readchar.readkey()
key = key.lower()
if key in ('wsadqe'):
print 'Key:', key
elif key == 'p':
print "stop"
sleep_time = 0.030
if key == '.':
print "finished"
break

Related

list pop() not printing out correctly

I tried making a text writing program but the text deleting part doesn't seem to work. It should delete the text, but it just replaces the text with my new input. I am new to python so I would appreciate a simple answer. Here is my code:
import os
import msvcrt
lst = []
while True:
userinput = msvcrt.getch()
if userinput == "b'\\x08'": # delete last input
lst.pop()
os.system('cls' if os.name == 'nt' else "printf '\033c'")
print("".join(lst))
elif userinput == "b'\\r'": # enter key
lst.append("\n")
else:
lst.append(userinput.decode("ASCII")) #normal text
os.system('cls' if os.name == 'nt' else "printf '\033c'")
print("".join(lst))
When I input "Hello" it prints:
>Hello
then press Backspace, I expect:
>Hell
but it just stays
>Hello
And when I press a button after that, e.g. "f" then it prints out:
>Hellf
you're comparing against the serialized representation of the bytes. It will never match.
Instead:
if userinput == b'\b': # delete last input
and:
elif userinput == b'\r': # enter key
\b is the same as \x08, but more readable

Python Key logger with msvcrt

I am trying to create a python Keylistener for a self driving car using the msvcrt module. But it doesn't capture the Keys I press. Here's the Code:
if msvcrt.getwch() == 'w':
keypresses.append(1)
elif msvcrt.getwch() == 's':
keypresses.append(2)
elif msvcrt.getwch() == 'd':
keypresses.append(3)
elif msvcrt.getwch() == 'a':
keypresses.append(4)
elif msvcrt.getwch() == 'w'and'a':
keypresses.append(5)
elif msvcrt.getwch() == 'w'and'd':
keypresses.append(6)
elif msvcrt.getwch() == 's'and'a':
keypresses.append(7)
elif msvcrt.getwch() == 's'and'd':
keypresses.append(8)
else:
keypresses.append(0)
Can someone tell me what is wrong with my code?
The main problem with your code is that you are checking for a new keypress in each if statement, rather than saving the keypress once and checking what that result is.
To save the keypress once, you should do this:
keypress = msvcrt.getwch()
and then check the value of keypress. i.e.:
if keypress == "a":
print("The 'a' key has been pressed')

Python Windows `msvcrt.getch()` only detects every 3rd keypress?

My code is below:
import msvcrt
while True:
if msvcrt.getch() == 'q':
print "Q was pressed"
elif msvcrt.getch() == 'x':
sys.exit()
else:
print "Key Pressed:" + str(msvcrt.getch()
This code is based on this question; I was using it to acquaint myself with getch.
I've noticed that it takes 3 pressing the key 3 times to output the text once. Why is this? I'm trying to use it as an event loop, and that's too much of a lag...
Even if I type 3 different keys, it only outputs the 3rd keypress.
How can I force it to go faster? Is there a better way to achieve what I'm trying to achieve?
Thanks!
evamvid
you call the function 3 times in your loop. try calling it only once like this:
import msvcrt
while True:
pressedKey = msvcrt.getch()
if pressedKey == 'q':
print "Q was pressed"
elif pressedKey == 'x':
sys.exit()
else:
print "Key Pressed:" + str(pressedKey)
You can optimize things a little bit by also using themsvcrt.kbhit function which will allow you callmsvcrt.getch()only as much as is necessary:
while True:
if msvcrt.kbhit():
ch = msvcrt.getch()
if ch in '\x00\xe0': # arrow or function key prefix?
ch = msvcrt.getch() # second call returns the scan code
if ch == 'q':
print "Q was pressed"
elif ch == 'x':
sys.exit()
else:
print "Key Pressed:", ch
Note that theKey Pressedvalue printed won't make sense for things like function keys. That's because it those cases it's really the Windows scan code for the key, not a regular key code for the character.

Python method for reading keypress?

I'm new to Python, and I just made a game and a menu in Python.
Question is, that using (raw_)input() requires me to press enter after every keypress, I'd like to make it so that pressing down-arrow will instantly select the next menu item, or move down in the game. At the moment, it requires me to like type "down" and then hit enter. I also did quite a lot of research, but I would prefer not to download huge modules (e.g. pygame) just to achieve a single keyDown() method. So are there any easier ways, which I just couldn't find?
Edit:
Just found out that msvcrt.getch() would do the trick. It's not keyDown(), but it works. However, I'm not sure how to use it either, it seems quite weird, any help here? This is what I got at the moment:
from msvcrt import getch
while True:
key = getch()
print(key)
However, it keeps giving me all these nonsense bytes, for example, down-arrow is this:
b'\xe0'
b'P'
And I have no idea how to use them, I've tried to compare with chr() and even use ord() but can't really do any comparisons. What I'm trying to do is basically this:
from msvcrt import getch
while True:
key = getch()
if key == escape:
break
elif key == downarrow:
movedown()
elif key == 'a':
...
And so on... Any help?
Figured it out by testing all the stuff by myself.
Couldn't find any topics about it tho, so I'll just leave the solution here. This might not be the only or even the best solution, but it works for my purposes (within getch's limits) and is better than nothing.
Note: proper keyDown() which would recognize all the keys and actual key presses, is still valued.
Solution: using ord()-function to first turn the getch() into an integer (I guess they're virtual key codes, but not too sure) works fine, and then comparing the result to the actual number representing the wanted key. Also, if I needed to, I could add an extra chr() around the number returned so that it would convert it to a character. However, I'm using mostly down arrow, esc, etc. so converting those to a character would be stupid. Here's the final code:
from msvcrt import getch
while True:
key = ord(getch())
if key == 27: #ESC
break
elif key == 13: #Enter
select()
elif key == 224: #Special keys (arrows, f keys, ins, del, etc.)
key = ord(getch())
if key == 80: #Down arrow
moveDown()
elif key == 72: #Up arrow
moveUp()
Also if someone else needs to, you can easily find out the keycodes from google, or by using python and just pressing the key:
from msvcrt import getch
while True:
print(ord(getch()))
See the MSDN getch docs. Specifically:
The _getch and_getwch functions read a single character from the console without echoing the character. None of these functions can be used to read CTRL+C. When reading a function key or an arrow key, each function must be called twice; the first call returns 0 or 0xE0, and the second call returns the actual key code.
The Python function returns a character. you can use ord() to get an integer value you can test, for example keycode = ord(msvcrt.getch()).
So if you read an 0x00 or 0xE0, read it a second time to get the key code for an arrow or function key. From experimentation, 0x00 precedes F1-F10 (0x3B-0x44) and 0xE0 precedes arrow keys and Ins/Del/Home/End/PageUp/PageDown.
I really did not want to post this as a comment because I would need to comment all answers and the original question.
All of the answers seem to rely on MSVCRT Microsoft Visual C Runtime.
If you would like to avoid that dependency :
In case you want cross platform support, using the library here:
https://pypi.org/project/getkey/#files
https://github.com/kcsaff/getkey
Can allow for a more elegant solution.
Code example:
from getkey import getkey, keys
key = getkey()
if key == keys.UP:
... # Handle the UP key
elif key == keys.DOWN:
... # Handle the DOWN key
elif key == 'a':
... # Handle the `a` key
elif key == 'Y':
... # Handle `shift-y`
else:
# Handle other text characters
buffer += key
print(buffer)
from msvcrt import getch
pos = [0, 0]
def fright():
global pos
pos[0] += 1
def fleft():
global pos
pos[0] -= 1
def fup():
global pos
pos[1] += 1
def fdown():
global pos
pos[1] -= 1
while True:
print'Distance from zero: ', pos
key = ord(getch())
if key == 27: #ESC
break
elif key == 13: #Enter
print('selected')
elif key == 32: #Space
print('jump')
elif key == 224: #Special keys (arrows, f keys, ins, del, etc.)
key = ord(getch())
if key == 80: #Down arrow
print('down')
fdown
elif key == 72: #Up arrow
print('up')
fup()
elif key == 75: #Left arrow
print('left')
fleft()
elif key == 77: #Right arrow
print('right')
fright()
I was also trying to achieve this. From above codes, what I understood was that you can call getch() function multiple times in order to get both bytes getting from the function. So the ord() function is not necessary if you are just looking to use with byte objects.
while True :
if m.kbhit() :
k = m.getch()
if b'\r' == k :
break
elif k == b'\x08'or k == b'\x1b':
# b'\x08' => BACKSPACE
# b'\x1b' => ESC
pass
elif k == b'\xe0' or k == b'\x00':
k = m.getch()
if k in [b'H',b'M',b'K',b'P',b'S',b'\x08']:
# b'H' => UP ARROW
# b'M' => RIGHT ARROW
# b'K' => LEFT ARROW
# b'P' => DOWN ARROW
# b'S' => DELETE
pass
else:
print(k.decode(),end='')
else:
print(k.decode(),end='')
This code will work print any key until enter key is pressed in CMD or IDE
(I was using VS CODE)
You can customize inside the if for specific keys if needed
It's really late now but I made a quick script which works for Windows, Mac and Linux, simply by using each command line:
import os, platform
def close():
if platform.system() == "Windows":
print("Press any key to exit . . .")
os.system("pause>nul")
exit()
elif platform.system() == "Linux":
os.system("read -n1 -r -p \"Press any key to exit . . .\" key")
exit()
elif platform.system() == "Darwin":
print("Press any key to exit . . .")
os.system("read -n 1 -s -p \"\"")
exit()
else:
exit()
It uses only inbuilt functions, and should work for all three (although I've only tested Windows and Linux...).
I suggest keyboard module by BoppreH. This example shows how to detect keypresses outside of python console in a non blocking way. When you press the f key it calls a function that prints some text . To end the execution of the script press the q key. For more info and special key codes click here
import keyboard
def my_function():
print("button pressed")
def my_quit():
global mybool
mybool = False
keyboard.add_hotkey('f', my_function)
keyboard.add_hotkey('q', my_quit)
mybool = True
while mybool:
keyboard.read_key()
If you want to pause the execution of the script intsead of add_hotkey() use keyboard.wait('esc')

Exploring a maze (using python 2.7)

I have done everything on my homework except a one step.
I did it in a different way, but it gave kind of right answer somehow.
Anyway, I have to explore a maz, so I went all the way through and got everything completely right, except part (Q COMMAND) of this task.
I need to use string method .upper()
2.2.6 The Top-Level Interface
interact() is the top-level function that denes the text-base user interface
as described in the introduction.
Note that when either the user quits or
when the finish square is found, the interact function should exit.
def interact():
mazefile = raw_input('Maze File: ')
maze = load_maze(mazefile)
position = (1, 1)
poshis = [position]
while True:
#print poshis, len(poshis)
print 'You are at position', position
command = raw_input('Command: ')
#print command
if command == '?':
print HELP
elif command == 'N' or command == 'E' or command == 'S'or command == 'W':
mov = move(maze, position, command)
if mov[0] == False: #invalid direction
print "You can't go in that direction"
elif mov[1] == True:#finished
print 'Congratulations - you made it!'
break
else: #can move, but not finished
position = mov[2]
poshis.append(position)
elif command == 'R': # reseting the maze to the first pos
position = (1, 1)
poshis = [position]
elif command == 'B': # back one move
if len(poshis) > 1:
poshis.pop()
position = poshis[-1]
elif command == 'L': # listing all possible leg dir
toggle = 0
result = ''
leg_list = get_legal_directions(maze, poshis[-1])
for Legal in leg_list:
if toggle:
result += ', '
result += Legal
else:
result += Legal
if not toggle:
toggle = 1
print result
elif command == 'Q': #quiting
m = raw_input('Are you sure you want to quit? [y] or n: ')
if m == 'y':
break
#print 'Are you sure you want to quit? [y] or n: '
#if raw_input == 'y':
# break
else: #invalid input
print 'Invalid Command:', command
Your question isn't particularly clear, but I'm guessing that the 'problem' is that if a user were to answer "Y" instead of "y" when asked if they are sure they want to quit, then the loop will continue.
If that is the problem, you should merely replace the line:
if m == 'y':
break
with:
if m.upper() == 'Y':
break
Because regardless of whether the user types "y" or "Y", the loop will still be broken out of.

Categories