I want to make it so that the game will print and ask to type a certain letter, and if I don't then I lose
What I want it to be like:
Press E:
(if you don't type it after 5 seconds, you lose. If you DO type it, the game will continue)
Update: I have been told that this is a bad answer, so I decided to improve it, but I left in my old reply for you to still see
Old reply:
Check out the keyboard library, and probably the time library too. I think the easiest way to do this is to create some sort of clock, save a "start time" (what time the prompt came up) and then enter a loop, exiting only when you have either pressed the key, or 5 seconds from the start time has elapsed. Make sure you keep track of which one actually happened.
My updated response, including a code example:
Okay so we're going to be using the time and keyboard libraries.
Note: In order to use most functions in keyboard, you need to run your script on root. You'll have to look up instructions if you're running a different OS, but what I did on my linux machine was just first installing keyboard on root (idk why it needed to be installed seprately but it did) with sudo pip install keyboard, and then running my code as sudo python3 filename.py
.
Our code is going to be running all within a while loop. Here's the basic idea:
play = True
while play:
play = runGame('e')
where runGame() is a func that plays 1 "round" of the game, and returns True if you win, False if you lose.
First, let's look at a way to actually tell if we pressed some desired key (like 'e') We'll be using keyboard.on_press_key() We'll be passing 2 arguments into it, key (what key will trigger it) and callback (a function to call when that key gets pressed) see the docs for more info.
So something like this:
import keyboard
def keyIsPressed(x):
global buttonPress
buttonPress = True
# calls keyIsPressed() when we press targetKey
keyboard.on_press_key(targetKey, keyIsPressed)
i added the unused x argument in the function because on_press_key wants to return some data into the function when you use it. Feel free to print(x) to get a look at what that data is. I just did that as an easy way to deal with an error.
Okay, so let's put everything together finally:
import keyboard
import time
#func called by on_press_key when our targetKey is pressed
def keyIsPressed(x):
global buttonPress
buttonPress = True
def runGame(targetKey):
# variable to tell if we have pressed the targetKey yet
global buttonPress
# always start the round false
buttonPress = False
# calls keyIsPressed() when we press targetKey
keyboard.on_press_key(targetKey, keyIsPressed)
#start time
st = time.time()
while True:
#current time
ct = time.time()
# if 5 seconds or more has passed between start time and current time
if ct >= (st + 5):
print("you took too long!")
return buttonPress #False
#if you have pressed the button
elif buttonPress:
#unhook the key now that you're done with it
keyboard.unhook_key(targetKey)
print("\n\nwow u did it good job!\n\n")
return buttonPress #True
# Run
buttonPress = False
play = True
# you don't have to use a list, but I'm doing so for my prototype
letters = ['e', 'f', 'g']
#the amount of times you've played
loops = 0
while play:
# play the game, use 'e', then 'f', then 'g'
# outside of a prototype, you'll need to update the list or use a different
# method to avoid errors after 3 rounds
play = runGame(letters[loops])
#up loop counter
loops += 1
#remove all key hooks when you are done playing
keyboard.unhook_all()
Hopefully that's comprehensive enough without being too wordy. I really wasn't expecting this to be as difficult as it was, but all of the intuitive solutions that I thought of actually ran into issues either with dropping inputs, or freezing the loop. So this is the simplest implementation I could come up with.
Related
I'm trying to write a small script with Autokey (not regular Python) on Linux Mint which presses a single key and stops after I press another specific key but I can't get it to stop the loop after I press this specific key.
I got the loop working but I can't make it stop.
import time
a = True
b = keyboard.press_key('s')
keyboard.release_key('s')
while a:
keyboard.send_key("a", repeat=5)
time.sleep(2)
if b:
break
So this outputs the letter "a" indefinitely and after I press "s" it doesn't stop and I don't know what I'm doing wrong
I read about the while function and break but all the examples I found were with a loop stopping after it reached a certain number and these examples with numbers are different than what I try to achieve with this kind of script so I hope someone can help me to figure this out.
You will have to use the keyboard module for this, because press_key is used to "press" the keys not to detect.
If you haven't already installed keyboard you can do it by going to cmd,
pip install keyboard
after that you can add the code in python as follows, pressing "q" will print "a" 5 times and pressing "s" will stop the program.
import keyboard
while True:
if keyboard.is_pressed('q'): # pressing q will print a 5 times
for i in range(5):
print("a")
break
elif keyboard.is_pressed('s'): # pressing s will stop the program
break
You can check if a key is pressed with evdev
Check your InputDevice by looking at python -m evdev.evtest
Then to check if the s key is pressed :
import evdev
from evdev import ecodes as e
device = evdev.InputDevice('/dev/input/event7')
if e.KEY_S in device.active_keys():
do_something()
At first glance your problem is that you never update the value of b and it is only assigned before the loop. You should probably try something like this:
import time
a = True
keyboard.release_key('s')
while a:
keyboard.send_key("a", repeat=5)
b = keyboard.press_key('s')
time.sleep(2)
if b:
break
I don't know how "b = keyboard.press_key('s')" affects the code, if it stops it.
I need to make on auto clicker that, when the mouse is clicked once (using the 'mouse' module), presses another 5 times. However, I also need to make sure that only the clicks done by the user activate it. Currently (because I don't need an unstoppable mouse as I've already had), it only prints "clicking". This is what I have so far.
jack = 0
import keyboard
import mouse
import sys
from time import sleep
def spamClick(f, jeff):
if jeff <= 0:
jeff = jeff+1
for i in range(f):
#mouse.click()
print ("Clicking")
sleep(0.1)
jeff = 0
mouse.on_click(spamClick, args=(5, jack))
#keyboard.add_hotkey('ctrl+g', spamClick)
keyboard.add_hotkey('ctrl+#', mouse.unhook_all)
keyboard.add_hotkey('ctrl+#', sys.exit)
Thank you in advance.
An easy fix for this is having a top level variable keeping track of the state.
The issue is that you have a function that does an action that starts itself again.
It's functionally the same as
def examplecode():
print("Do stuff")
examplecode()
This is the same as an infinite loop, in your case even worse because you call the function multiple times every time (5 times per action).
So your options to prevent that are as follows:
Have two different ways of clicks, one that triggers the "onclick" event, and one that doesn't.
Use a helper function that keeps track of the "state" of your program. Instead of calling "spamClick()" as your onclick event add the following to your program:
A top level variable that is True when you want it to accept clicks: isUser=True
A function you call instead of "spamclick" that checks the state of the global Var and only then triggers the code:
def examplefunc(num,var):
if isUser:
isUser=False
spamClick(num,var)
isUser=True
I still don't get how your program just "clicks endlessly" instead of crashing due to hitting max recursion depth, but this should work (while being very hacky)
Edit: You should use better naming for variables instead of "jeff", it will make your life worse if you don't down the line. For example "isUser" indicates that it's a boolean (because "isWhatever" indicates it holds a state as a boolean) and states if the input is by a user. Alternatively you could use isFunctionRunning=False that states if the function is on. You would have to switch all the True and False assignments in my example of course to still make sense.
I used the curses library in Python to divide the screen into two part, the first half to print a set of strings and the second half to get the user input by using getstr() , but when the user enters the ipnut curses interrupt the entry and clear the user's entries
def main(stdscr):
curses.curs_set(0)
stdscr.nodelay(1)
stdscr.timeout(100)
i = 0
while 1 :
i = i+1
stdscr.addstr(0,0,"frame"+str(i))
curses.echo()
user_input = stdscr.getstr(5,0)
stdscr.addstr(7,0,user_input)
curses.wrapper(main)
getstr won't help with this. If you want to concurrently update the screen and get input, you'll have to make a function like getstr, using getch, and allowing the getch calls to time-out (to do the addstr calls periodically).
The nodelay function can help with this, though using that tends to use too much processing time. It's usually preferable to use timeout, e.g., 10-20 milliseconds.
I am trying to control OMXplayer during playback of a video using a Python script. I am new to Dbus on Python, and am hopefully just missing something simple.
Eventually I want to do this with a motion sensor using the GPIO pins, but first I am just trying to get control over the player. What I need to do is loop a section of the video once a certain time passes, and then jump forward to the 'second' section when the passage is interrupted. I am testing this using a key entry.
My problem is that the 'if' statement within the code does not loop unless there is an interruption from a key being inputted, or any other signal. Any key will cause an interruption, but I want the time-specific 'if' statement in the loop to trigger without any input being entered. I hope what I am saying is clear in the below code, but if not please ask any question and I'll be happy to try to clarify.
I am using Will Price's OMXplayer wrapper: https://github.com/willprice/python-omxplayer-wrapper/
My hardware is a Raspberry Pi 3B+
I have looked at similar questions including those below, but have not found the answer:
How to open and close omxplayer (Python/Raspberry Pi) while playing video?
https://www.raspberrypi.org/forums/viewtopic.php?p=533160
I have cleaned out unnecessary parts of the code so this is a basic functioning version.
from omxplayer.player import OMXPlayer #runs from the popcornmix omxplayer wrapper at https://github.com/popcornmix/omxplayerhttps://github.com/popcornmix/omxplayer and https://python-omxplayer-wrapper.readthedocs.io/en/latest/)
from pathlib import Path
import time
import RPi.GPIO as GPIO #for taking signal from GPIO
import subprocess
import logging
logging.basicConfig(level=logging.INFO)
VIDEO_PATH = Path("VIDEO.m4v")
player_log = logging.getLogger("Player 1")
player = OMXPlayer(VIDEO_PATH, dbus_name='org.mpris.MediaPlayer2.omxplayer1')
player.playEvent += lambda _: player_log.info("Play")
player.pauseEvent += lambda _: player_log.info("Pause")
player.stopEvent += lambda _: player_log.info("Stop")
positionEvent = 12
flyin = 3
flyaway = 15
'''
THE ERROR OCCURS IN THE BELOW FUNCTION!!!
the following function does not run each time
the 'while' loop below is playing, but does run
when there is a key pressed as an 'input'
I want to add a chck so that each time a certain
amount of time passes, the video jumps back
'''
def checktime():
currtime = player.position()
print("current time is " + str(currtime))
if(currtime > 3):
print("currtime is greater than 3")
try:
player.play()
print (" Ready")
while True:
'''
Below is the call for the function 'checktime'
This runs once when the video starts, and only
runs again when a key is entered.
I want this to run on a continuous loop
and call each time the video loops
'''
checktime()
key = input()
if key == 'd': #works perfectly
currtime = player.position()
player.seek(flyin-currtime)
print("player position is" + str(player.position()))
if key == 'a': #works perfectly
currtime = player.position()
player.seek(flyaway-currtime)
if key == 's': #works perfectly
player.play()
'''
in addition to the key inputs above, entering any key
and pressing return will run the checktime()
function. I understand that this is receiving an
input, therefore 'waking' the program up,
but I don't understand why the loop is not working
continuously
'''
# Wait for 10 milliseconds
time.sleep(.01)
except KeyboardInterrupt:
print (" Quit")
# Reset GPIO settings
GPIO.cleanup()
The video is controlled using the 's', 'a' and 'd' keys as inputs, and this works perfectly. However, the 'checktime()' function does not call each time the while loop goes around. My guess is that this is because once the video is playing, it is not looking for anything from the Python program until it receives another input.
I am not sure if I am using DBus correctly. Ideally, I wanted to use the seek_absolute function of omxplayer-wrapper, but I haven't been able to understand this. I have been ploughing ahead on this project and have gotten a better understanding since posting an earlier question (see here: OMXplayer-wrapper and Python - jump to a specific point in video) but I am a bit stumped here.
If anyone can help I would appreciate any suggestions!
Warning: my English sucks and also I'm really new to python
So I'm making a program that requires a specific Key Press (e.g. space bar) to continue the loop, like:
for i in *some sort of list*:
print(something)
*waits for a key*
and my method for the last line is the keyboard module (not from pynput), which has the functionis_pressed. When I pressed a key, I got the output:
*something*
*something*
*something*
*repeats for several times*
I know that the function detects key press instead of press and release, so this output stops as soon as I release it. But that not how my program works. It should respond every time I release that key. Unfortunately I couldn't find a function called is_released or something, and module pynput can't get the key I pressed using Listener. At least I can't.
Also, is there a way to have both keyboard and pynput importable in a computer? My VS Code ignores keyboard when pynput is installed.
Edit: this is my solution for the problem, but it's super dumb:
while True:
if keyboard.is_pressed('space'):
while True:
if not keyboard.is_pressed('space'):
break
break
Is there a function that does the same thing?
Since it detects keypress only, use flags. I think something like this can do it:
1. Make a bool variable to detect a single key press
2. If key is pressed, the bool will be set to true
3. If bool is true and not key.is_pressed: do your thing
4. Set bool to false after operation
For example, in code, that will be like this:
keypress = False
key = 'space'
while True:
if keypress and not keyboard.is_pressed(key):
'''DO YOUR THING'''
#beak out of while loop?
keypress = False
break
elif keyboard.is_pressed(key) and not keypress:
keypress = True
Dont know if this is how you'll do it, but I guess you can get my drift from this. Good luck!