Is there anyway to use pygame to get input from the console, rather than having to display a separate window to get input? I'm using pygame to track how long the keys on the keyboard are pressed.
The following code doesn't work (this is just a minimal example, it doesn't actually keep track of time elapsed):
pygame.init()
while 1:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
print event.key, 'pressed'
It doesn't look like any pygame event is being raised. If I add
screen = pygame.display.set_mode((640, 480))
After pygame.init()
then the event is raised, but I have that ghastly window I don't want to deal with.
To explain why I don't want the window, I envision this application being a command-line utility, so I can't have that. Is there any functional reason preventing pygame from running on the command-line?
Thanks!
EDIT: I speculated that the problem was pygame.init(), and that I only needed to initialize the key and event modules. According to http://www.pygame.org/docs/tut/ImportInit.html I should have been able to call pygame.key.init()pygame.event.init() but it didn't work.
Pygame is designed for making (graphical) games, so it only captures key presses when there is a window displayed. As Ignacio said in his answer, reading from the command line and from another window are very different things.
If you want to create a command line application, try curses:
http://docs.python.org/library/curses.html
Unfortunately, it only works on Linux and Mac OS X.
Console input comes in via stdin, which pygame is not prepared to handle. There is no reliable way to get press/release events via stdin since it's dependent on the terminal sending it keypresses.
If you just make the window really small using
screen = pygame.display.set_mode((1, 1))
you can't see it. So you are clicked into the window but you don't notice.
If you click anywhere of course it stops working. You have to click on the pygame window icon for it to work again.
If you just plain don't want a window of any kind at all, you can use PyHook. If you just want a console application, get user input with the built-in Python command "raw_input(...)".
Try pygame.display.iconify().
This will hide the pygame screen, and you will still be able to detect keypresses.
Related
I was experimenting with pygame and noticed it raised a VideoExpose event when I press alt+tab and the window is fullscreen. when I switch press alt+tab again, everything on the screen is moved to the bottom left.
I know that this is supposed to mean that 'portions of the window must be redrawn', but how am I supposed to redraw them and what why does pygame even have this event in the first place?
If you are writing a program to use the windowing Event Model, the windowing environment sends the program events to notify it of environmental changes - window resize, mouse move, need to re-paint, etc.
Not handling these events will cause your application to be considered "non responsive" by the environment. Here on SO, there's about one question a week with PyGame and exactly this issue.
When working with PyGame re-drawing event handling may seem superfluous as the majority of PyGame games redraw the entire screen every frame, e.g.: 60 FPS. But if unnecessary, this method is a complete waste of resources (CPU-time, electricity, etc.) It is quite simple though, so good for beginners.
Say you were writing a card game like Solitaire... the screen updates only when interacting with the user. In terms of CPU, it's doing nothing 99.9% of the time while the user contemplates their next move. In this case, the program could be written to only re-draw the screen when necessary. When is it necessary? When the player gives input, or the program receives a pygame.VIDEOEXPOSE event from the widowing environment.
If your program is redrawing the window constantly, you can simply ignore the message. If not, when receiving the message call whatever block of code is normally used to render the window. The expose message may come with the region of the screen that needs to be re-drawn, in this case a really good application would only update that section of the display.
Ok, so what I want to do is allow my program to send mouse movements and keypresses (both mouse and keyboard) to a particular task without having to be tabbed into the task so I can do other things on my computer with the mouse and keyboard while the task runs. Is it possible to do this relatively simply with existing python modules?
example of what I want to do:
task='application name'
task.leftclick
task.moveX(int)
task.moveY(int)
task.keypress(r)
All while being able to use my mouse and keyboard normally on a different application.
Thanks for the help in advance!
(Python3.6)
For anyone who happens upon this post, I found https://pypi.org/project/ahk/ I haven't looked into it fully but either you can use this or create an auto hotkey script and just call that with you python code to achieve what I wanted to do in the question.
When the pygame window closes, I want to immediately stop execution; that's the end of the program. I have looked up and down the internet and every problem I come across is something like "Did you try pygame.quit()" or "You never break out of your infinite loop". That isn't my problem. Here's my code:
#!/usr/bin/env python3
import pygame
from sys import exit as sysExit
pygame.init()
screen = pygame.display.set_mode((512,512))
screen.fill((255,255,255))
pygame.display.update()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.display.update()
pygame.display.quit()
pygame.quit()
exit(0)
sysExit(0)
#None of these work, code under them is unreachable but the process hangs
As the comment and question title say, this process hangs. I honestly don't what else I could do to tell python I'm done, and I've tried every combination of these quit functions but nothing works. The window will close, but the program never ends. In my searching I've found people have issues with something called "IDLE" which I do not have.
Here's what I do have (my system): Linux Mint Cinnamon 18, 32-bit (i686), using python version 3.5.2 (no IDE, just running from terminal)
EDIT - Apparently there's some confusion about what I'm talking about when I say the program "hangs", so here's some screenshots of the issue in action. This first one shows you that the above code is, in fact, usable to reproduce the problem.
Now all I do is run this script, and it just gives me a blank window like you'd expect.
Now I click the "x" button on the window, and the window disappears, but my terminal is left like this. The screen capture won't show you the blinking cursor, but you'll notice there's no new prompt.
I've so far been resorting to doing this to get the thing to stop:
throw it in the background, force kill the job (SIGTERM gets ignored btw) and foreground it again and now I have a prompt.
check pygame.init() -> (numpass, numfails), then loading each module manually (yes, each module has an init() and quit() method). I would suspect the mixed or music module to be the problem (due to os/driver/hardware issues).
The pygame irc channel helped me figure this out. Specifically, this answer comes from user DR0ID_ who walked me through some debugging I should've thought of in the first place.
First of all, once I'm done with this answer I'll edit the question, but I have to apologize for leaving something out initially: I'm doing all this on a Virtualbox VM. By walking through the different modules initialized by pygame.init(), I discovered that the one that actually hangs it is pygame.mixer. No word yet from the pygame devs, but the working theory is that this is related to Virtualbox sound drivers and/or their interface with the host drivers. Basically, if you're on a virtual machine and don't need to play sounds, the workaround is to only initialize the modules you need. Since in my example I only need pygame.display, the solution is easy:
#!/usr/bin/env python3
import pygame
pygame.display.init()
screen = pygame.display.set_mode((512, 512))
screen.fill((255, 255, 255))
pygame.display.update()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.display.quit()
exit()
Does pygame.display.set_mode have to be used to utilize the keyboard keys?
Once I added it to my code everything worked - but I do not want to open a pygame window.
Does anyone know how to utilize the keyboard without having to call pygame.display.set_mode ?
You have to use pygame.display.set_mode to create a window, since it's this very window that recieves the keyboard events from your OS' window manager.
You can run pygame without a window (by setting the environment variable SDL_VIDEODRIVER to "dummy"), but you can't recieve keyboard events with pygame then.
Maybe you want to look into low-level hooks (e.g. here's an example for windows).
I am creating a small app for myself to be able to show my keyboard inputs and show them in a Joystick layout, like this:
This itself, works perfectly fine while the Pygame windows is focused, my problem is, i can't have this focused all the time, in fact it will never have focus because either way i will be using OBS to stream or i will be using my emulator, and pygame doesn't detect inputs that are out of the window. Is there any way to make python or pygame read all the input made to the computer??? I am hitting a wall here. Thanks in advance!!
There's an SDL environment variable for this! Simply setting it will enable background input.
import os
os.environ["SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS"] = "1"
Add that to the top of the sample in the joystick docs and try it out.
Tested with pygame 2.1.2, sdl 2.0.18, Windows 10 (21H2), Xbox One like controller
ref:
https://wiki.libsdl.org/SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS
https://wiki.libsdl.org/CategoryHints
As per two comments directly above, IN order to keep focus on the pygame window (effectively keep the cursor within the bounds of the pygame window until a I was able to make this work with the following code:
pygame.event.set_grab(True) # Keeps the cursor within the pygame window
Combine this code with a way to quit the program with a key press such as the ESCAPE key (since it will be impossible to close the window by moving your cursor to the frame of the window to close it that way by pygame.QUIT):
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
run = False
Use pygame.event.set_grab(True)
When your program runs in a windowed environment, it will share the mouse and keyboard devices with other applications that have focus. If your program sets the event grab to True, it will lock all input into your program.
It is best to not always grab the input, since it prevents the user from doing other things on their system.
You will need another way to exit though, since you will not be able to move the mouse out of the display window.