Python: keyboard input and loop - python

I am trying to build a locker with Raspberry Pi. I have a code that when entering a correct CODE = '1234' with USB keyboard it opens a servo.
Basically it works, but need to loop it somehow so, if I put wrong PIN, I am asked again to put correct.
for event in dev.read_loop():
if event.type == ecodes.EV_KEY:
e = categorize(event)
if e.keystate == e.key_down:
klawisz = e.keycode[4:]
if klawisz != "ESC":
kod = (kod + klawisz)
print(kod)
else:
break
if kod == '1234':
for event in dev.read_loop():
if event.type == ecodes.EV_KEY:
d = categorize(event)
if d.keystate == d.key_down:
klawisz = d.keycode[4:]
if klawisz == "ESC":
print('ITS OPEN')
break
else:
break
else:
print('Wrong PIN')
I tried with while loop at the beginning, but it doesn't work :(
while kod == '1234'
Hope you could you guide me to correct solution, as I am still learning Python. Thanks.

You can use while loop to repeatedly perform some operations (reading users password in your example) if some condition stays true:
def read_password():
kod = ""
for event in dev.read_loop():
if event.type == ecodes.EV_KEY:
e = categorize(event)
if e.keystate == e.key_down:
klawisz = e.keycode[4:]
if klawisz != "ESC":
kod = (kod + klawisz)
print(kod)
else:
break
return kod
while read_password() != '1234':
print('Wrong PIN, try again')
In this case you're reading password as long as it doesn't match '1234'.

Use an infinite while loop and break out of it only if the code matches.
while True:
code = input('Enter code: ')
if code == '1234':
print('Code accepted.')
break
print('Wrong code, try again.')
You can easily add an additional security feature to reduce the amount of attempts per time.
import time
attempts = 0
while True:
code = input('Enter code: ')
if code == '1234':
print('Code accepted.')
break
print('Wrong code, try again.')
attempts = attempts + 1
if attempts > 9:
print('Too many failed attempts. Please wait.')
time.sleep(600)
attempts = 0
You can run all examples above on your regular computer to test them. They use Python's built-in input function. You use the RETURN key to finalize your input instead of the ESC key in your code. You said that you read the user input with a USB keyboard, so input might even work for you with your Raspberry Pi, too.

Related

Detect a key pressed within a while Python

I want to detect a key pressed in python without using "with", because I want it to show a text in a while
all this with the pynput library:
import time
from pynput import keyboard
i = 0
while True:
if event.key == keyboard.Key.esc:
break
else:
if a == "hello":
print("y")
else:
print("n")
if i % 2 = 0:
a = "hello"
else
a = "good bye"
i += 1
print(a)
time.sleep(2)
pynput's Events blocks by default. You can .get to limit how long it blocks for:
from pynput import keyboard
import time
i = 0
a = "start"
while True:
if a == "hello":
print("y")
else:
print("n")
if i % 2 == 0:
a = "hello"
else:
a = "good bye"
i += 1
print(a)
# Not needed anymore, we're going to block waiting for key events for 2 seconds
# time.sleep(2)
with keyboard.Events() as events:
# Block at most for two seconds
event = events.get(2.0)
if event is not None:
if event.key == keyboard.Key.esc:
break
This won't necessarily always block for two seconds if the user presses some other key. You can either add code to check for that condition and keep calling events.get till enough time has passed, or use keyboard.Listener to react to events in real time.

Python secret santa-ish draw

Sometimes it works fine, sometimes throws an error. Cannot figure it out. No matter how many inputs.
Thats the error. Is it the order of the code or something else?
give_gift.remove(reciever)
ValueError: list.remove(x): x not in list
Code:
import random
import os
import time
random.seed()
buy_gift = []
give_gift = []
names = True
print('Add name, then press ENTER. To finish type "end".')
while names is True:
name = input()
if name == "end":
if len(buy_gift) < 2:
print("Go play with your own gift. Goodbye!")
print()
os.system("PAUSE")
quit()
else:
names = False
else:
buy_gift.append(name)
give_gift.append(name)
exchange = len(give_gift)
os.system("cls")
time.sleep(1)
print("Drawing pairs...")
print()
time.sleep(1)
while exchange > 0:
giver = random.choice(buy_gift)
reciever = random.choice(give_gift)
while giver == reciever:
reciever = random.choice(buy_gift)
print(giver,"buys gift for",reciever)
time.sleep(0.25)
buy_gift.remove(giver)
give_gift.remove(reciever)
exchange -= 1
print()
os.system("PAUSE")
There is an issue with this line:
while giver == reciever:
reciever = random.choice(buy_gift)
It should be:
reciever = random.choice(give_gift)

Python 3 Game Bug: Holding down the enter key

I have another question related to this game, here it is:
https://stackoverflow.com/questions/28545444/python-3-game-bug-message-repeating
I made a game thats a knock off of Cookie Clicker (just for coding practice!). And I ran into a problem where the user can hold down the enter key, and get coins really fast. I'd like to prevent that. here is my code:
coin = 0
keepgoing = True
while keepgoing == True:
print('You have ' + str(coin) + ' cmd-coins' )
response = input('Press enter to get a coin!')
if response == 'q':
keepgoing = False
print('Thanks for playing!')
coin = coin + 1
I wrote a rather "gimmicky" solution to your problem, which works to an extent but definitely isn't flawless. Based on your compiler you may have to change the conditional value for start-end such that it is a value which allows you to static press as fast as humanly possible without breaking but not allow the user to hold the enter key. For me in WingIde, 0.03 is the optimal value.
Were you to import a module such as Pygame you would find this sort of game much easier to make.
import time
coins = 0
keepgoing = True
end = -1
while keepgoing:
print('You have ' + str(coins) + ' cmd-coins' )
response = input('Press enter to get a coin!')
start = time.time()
if start-end < 0.03:
print ("Don't hold down the Enter key you cheater!")
keepgoing = False
if response == 'q':
print('Thanks for Playing!')
keepgoing = False
coins = coins + 1
end = time.time()
NOTE: This solution is for Python 3, for < Python 3 you'll have to substitute raw_input() for input(). Also, I wouldn't advise trying to use it on an online compiler.
G Force dog,
You could change your game a bit by making a few changes till someone or I figure out a good solution(Mom gave orders to go to bed). Till we don't find a solution, use this code which isn't exactly a solution.
coins = 0
real = 0
while real == 0:
if True:
print('You have ' + str(coins) + ' cmd-coins' )
response = input('Press c to get a coin, then press ENTER!')
if response == 'c' or response == 'C':
coins = coins + 1
if response == 'q':
print('Thanks for playing!')
real = 1
And 2 things:-
Nice answer Yeniaul! Good try!
Elizion, nice try but your method isn't working. But it is a good idea.
I have used time too, but it seems that when one presses ENTER key for a long time, it just comes out on the screen all together.
I think I do have somewhat of an idea forming... if we make another while loop, after importing 'time', with a condition which makes the loop active every 2 seconds by assigning a variable 'time.clock()' and when its value is a multiple of 2, it activates!
Got it? I know what to do, but can't seem to put it in code. See if you can, reader(especially Elizion and Yeniaul)
Try using time.sleep(seconds of delay) for slowdown
So you could do
coin = 0
keepgoing = True
while keepgoing == True:
time.sleep(0.25)
print('You have ' + str(coin) + ' cmd-coins' )
response = input('Press enter to get a coin!')
if response == 'q':
keepgoing = False
print('Thanks for playing!')
coin = coin + 1
This would make it a quarter-second delay before they could get another coin.

Pause and resume a running script in Python 3.42 in Windows

I'm new to Python and have been googling for a couple of days and read all I can find on this forum. Might be that I don't understand it all but I haven't found a solution to my problem yet. Ask for forgiveness already if there's an answer already to my problem, then I haven't understood it.
I want to make a Pause function for my program Tennismatch. The program will when it's being run print the score of a tennis match like this: "15-0, 15-15 etc ongoing till the match ends. It will print the score line by line.
I want the user to be able to pause after x number of balls, games, etc. So I don't know when the user wants to pause and after the user has paused I want the user to be able to resume the tennismatch where it was.
Have seen the time.sleep() but as I have understood it you must know when you want to pause to use this and it also ain't an indefinetie pause like I want. With input() it's the same.
Am going to make a GUI later on when the code is finished. Happy for anything that leads me to solving my problem.
I use Windows and Python 3.42 and run the program in Shell.
A piece of the code (haven't written it all yet, it's more of a general situation when something is being printed line after line for some time and want to be able do pause in the CIL:
#self.__points = [0,0]
def playGame(self):
if self.server == True: #self.server is either True or False when someone calls playGame()
server = self.player_1.get_win_serve() #self.player_1 = an object of a class Player():
else:
server = self.player_2.get_win_serve() #get_win_serve() method returns the probability to win his serv (1-0)
while (0 < self.__points[0] - self.__points[1] >= 2 or 0 < self.__points[1] - self.__points[0] >= 2) and (self.__points[1] >= 4 or self.__points[0] >= 4):
x = random.uniform(0,1)
if x > 0 and x < server:
self.__points[0] += 1
else:
self.__points[1] += 1
# print('The score, by calling a score() function that I haven't written yet')
For dealing with events in main loop you need to make a separated thread which capture input or any other event.
import sys
from sys import stdin
from time import sleep
from threading import Thread
from Queue import Queue, Empty
def do_something():
sleep(1)
print 42
def enqueue_output(queue):
while True:
# reading line from stdin and pushing to shared queue
input = stdin.readline()
print "got input ", input
queue.put(input)
queue = Queue()
t = Thread(target=enqueue_output, args=(queue,))
t.daemon = True
t.start()
pause = False
try:
while True:
try:
command = queue.get_nowait().strip()
print 'got from queue ', command
except Empty:
print "queue is empty"
command = None
if command:
if command == 'p':
pause = True
if command == 'u':
pause = False
if not pause:
print pause
do_something()
except KeyboardInterrupt:
sys.exit(0)
I came up with the following.
while True:
try:
## Keep doing something here
## your regular code
print '.',
except KeyboardInterrupt:
## write or call pause function which could be time.sleep()
print '\nPausing... (Hit ENTER to continue, type quit to exit.)'
try:
response = raw_input()
if response.lower() == 'quit':
break
print 'Quitting...'
except KeyboardInterrupt:
print 'Resuming...'
continue
The Event loop might as well be the code I wrote with.
I don't see any user input so I assume that x emulates it. To pause the game if x < 0.1 and to unpause(/resume) it if x > 0.9, you could:
while your_condition(self.__points):
x = random.random()
if x < 0.1: # pause
self.pause()
elif x > 0.9: # resume
self.resume()
if self.is_paused:
continue # do nothing else only wait for input (`x`)
# assume your_condition() has no side-effects
# here's what the resumed version does:
print("...")
# change self.__points, etc
where pause(), resume(), is_paused() methods could be implemented as:
def __init__(self):
self.is_paused = False
def pause(self):
self.is_paused = True
def resume(self):
self.is_paused = False
as you can see the implementation is very simple.

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.

Categories