Python program won't respond until keyboard interrupt - python

I'm trying to draw an image with PyGame, and I copied this code from Adafruit. It's strange, seems nothing displays on the screen until I Ctrl-C, at which time it shows the image. Then the image stays on the screen until I press Ctrl-C again. I then get the following message:
Traceback (most recent call last):
File "RaspiDisplay.py", line 60, in
time.sleep(10)
KeyboardInterrupt
What's going on? By the way, I'm running this via ssh on a raspberry pi, with Display set to 0 (my TV) If I put a print statement in init, that also doesn't print until I press Ctrl-C.
import os
import pygame
import time
import random
class pyscope :
screen = None;
def __init__(self):
"Ininitializes a new pygame screen using the framebuffer"
# Based on "Python GUI in Linux frame buffer"
# http://www.karoltomala.com/blog/?p=679
disp_no = os.getenv("DISPLAY")
if disp_no:
print "I'm running under X display = {0}".format(disp_no)
# Check which frame buffer drivers are available
# Start with fbcon since directfb hangs with composite output
drivers = ['fbcon', 'directfb', 'svgalib']
found = False
for driver in drivers:
# Make sure that SDL_VIDEODRIVER is set
if not os.getenv('SDL_VIDEODRIVER'):
os.putenv('SDL_VIDEODRIVER', driver)
try:
pygame.display.init()
except pygame.error:
print 'Driver: {0} failed.'.format(driver)
continue
found = True
break
if not found:
raise Exception('No suitable video driver found!')
size = (pygame.display.Info().current_w, pygame.display.Info().current_h)
print "Framebuffer size: %d x %d" % (size[0], size[1])
self.screen = pygame.display.set_mode(size, pygame.FULLSCREEN)
# Clear the screen to start
self.screen.fill((0, 0, 0))
# Initialise font support
pygame.font.init()
# Render the screen
pygame.display.update()
def __del__(self):
"Destructor to make sure pygame shuts down, etc."
def test(self):
# Fill the screen with red (255, 0, 0)
red = (255, 0, 0)
self.screen.fill(red)
# Update the display
pygame.display.update()
# Create an instance of the PyScope class
scope = pyscope()
scope.test()
time.sleep(10)

You're not running an event loop anywhere. Instead, you're just initializing everything, and then going to sleep for 10 seconds. During that 10 seconds, your code is doing nothing, because that's what you told it to do. That means no updating the screen, responding to mouse clicks, or anything else.
There are a few different ways to drive pygame, but the simplest is something like this:
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
# any other event handling you need
# all the idle-time stuff you want to do each frame
# usually ending with pygame.display.update() or .flip()
See the tutorial for more information.
As a side note, your initialization code has a bunch of problems. You iterate through three drivers, but you only set SDL_VIDEODRIVER once, so you're just trying 'fbcon' three times in a row. Also, you've got code to detect the X display, but you don't allow pygame/SDL to use X, so… whatever you were trying to do there, you're not doing it. Finally, you don't need a found flag in Python for loops; just use an else clause.

Related

How to add On and Off buttons with pyautogui?

I made a simple auto-clicker in python. Every three seconds the script clicks wherever your mouse is. How would I add "on and off" keys? I imagine it is a simple if/else statement but I don't know how to write it.
As of Wed Sep 15 12:10, I do not have an answer that works well.
import pyautogui
import time
def Auto_Click():
width, height = pyautogui.position()
pyautogui.click(width, height)
time.sleep(3)
while True:
Auto_Click()
I'd suggest listening to specific key presses indefinitely to switch clicking on and off. And as there is an indefinite loop for the clicking as well, you will need multithreading (to perform clicking and listening for key presses simultaneously).
Notes
The auto clicker is switched off by default right on start (To avoid clicks at unwanted positions on screen right after running it). Press SHIFT to toggle it after pointing the mouse at wanted position.
Press ESC to exit the program.
I have used SHIFT and ESC keys for toggles so that the key presses won't show up in the next prompt unlike the character keys.
Use the below code if you really need to use pyautogui. Here is the solution using pynput for handling both mouse and keyboard. (My code is basically a modified version which uses keyboard module and pyautogui instead)
import time
import keyboard
import pyautogui
import threading
INTERVAL = 0.5 # Time interval between consecutive clicks
DELAY = 0.5 # Time delay between consecutive program cycles [after the clicks are turned off]
TOGGLE_KEY = 'shift' # Key to toggle the clicking
EXIT_KEY = 'esc' # Key to stop and exit from the program
class AutoClicker(threading.Thread):
def __init__(self, interval, delay):
super(AutoClicker, self).__init__()
self.interval = interval
self.delay = delay
self.running = False
self.program_running = True
def start_clicking(self):
self.running = True
def stop_clicking(self):
self.running = False
def exit(self):
self.stop_clicking()
self.program_running = False
def toggle_clicking(self):
if self.running:
self.stop_clicking()
else:
self.start_clicking()
def click(self):
width, height = pyautogui.position()
pyautogui.click(width, height)
# This function is invoked when the thread starts.
def run(self):
while self.program_running:
while self.running:
self.click()
time.sleep(self.interval)
time.sleep(self.delay)
if __name__ == '__main__':
# Run indefinite loop of clicking on seperate thread
auto_clicker_thread = AutoClicker(INTERVAL, DELAY)
auto_clicker_thread.start() # Invokes run() function of the thread
# So that we can listen for key presses on the main thread
keyboard.add_hotkey(TOGGLE_KEY, lambda: auto_clicker_thread.toggle_clicking())
keyboard.add_hotkey(EXIT_KEY, lambda: auto_clicker_thread.exit())

PyImgui Graphical User Interface not visible

So I just started coding GUI in python and after coding some stuff in tkinter i felt like I might as well use imgui as I know some stuff about it from C++.
Now starting to read the docs and somehow the imgui window isn't showing up. I just see a console pop open for a milisecond but no gui.
# initilize imgui context (see documentation)
imgui.create_context()
imgui.get_io().display_size = 100, 100
imgui.get_io().fonts.get_tex_data_as_rgba32()
# start new frame context
imgui.new_frame()
# open new window context
imgui.begin("Your first window!", True)
# draw text label inside of current window
imgui.text("Hello world!")
# close current window context
imgui.end()
# pass all drawing comands to the rendering pipeline
# and close frame context
imgui.render()
imgui.end_frame()
I feel like I didn't choose any engine to render but I'm not sure.
Yes, if you don't select a backend renderer for pyimgui, it won't render anything. I think you might find an imgui.ini file with imgui's interpretation of what you've asked for, in the current directory, but you won't get any graphical output.
To get graphical output, select a renderer, like in this file in the master pyimgui repository:
https://github.com/swistakm/pyimgui/blob/master/doc/examples/integrations_pygame.py
Note that, as I write this, most but not all of the examples in this directory work:
https://github.com/swistakm/pyimgui/tree/master/doc/examples
The "all in one" example did not work for me, and the SDL2 example required changing:
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 16)
to:
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4)
as my GPU doesn't seem to do 16-point multisampling.
Also, these examples don't play well with Python3 in that the error prints() are wrong, and will fail instead of printing a useful error:
print("Error: SDL could not initialize! SDL Error: " + SDL_GetError())
should be:
print("Error: SDL could not initialize! SDL Error: ", SDL_GetError())
So, if you get any errors at these lines, you know what to do. :-)
Finally, for future searchers, here is a quick cut and paste of the pygame version which works for me (from https://github.com/swistakm/pyimgui/blob/master/doc/examples/integrations_pygame.py ). I ran it with python 3.6:
#!/usr/bin/env python3
from __future__ import absolute_import
import sys
import pygame
import OpenGL.GL as gl
from imgui.integrations.pygame import PygameRenderer
import imgui
def main():
pygame.init()
size = 800, 600
pygame.display.set_mode(size, pygame.DOUBLEBUF | pygame.OPENGL | pygame.RESIZABLE)
imgui.create_context()
impl = PygameRenderer()
io = imgui.get_io()
io.display_size = size
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
impl.process_event(event)
imgui.new_frame()
if imgui.begin_main_menu_bar():
if imgui.begin_menu("File", True):
clicked_quit, selected_quit = imgui.menu_item(
"Quit", 'Cmd+Q', False, True
)
if clicked_quit:
exit(1)
imgui.end_menu()
imgui.end_main_menu_bar()
imgui.show_test_window()
imgui.begin("Custom window", True)
imgui.text("Bar")
imgui.text_colored("Eggs", 0.2, 1., 0.)
imgui.end()
# note: cannot use screen.fill((1, 1, 1)) because pygame's screen
# does not support fill() on OpenGL sufraces
gl.glClearColor(1, 1, 1, 1)
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
imgui.render()
impl.render(imgui.get_draw_data())
pygame.display.flip()
if __name__ == "__main__":
main()

Python/Pygame script not responding when closed, while Renoise is open

I'm writing a Python script using Pygame and OSC that will allow me to control the music tracker software Renoise (version 3.0.0) by doing things in a Pygame (1.9.1) environment and sending messages to the software via OSC. If you're wondering, the purpose of this script is for live performance and generative music creation. I'm having a pretty annoying issue, however: when I try to close the Pygame window, it just hangs - doesn't even respond to Control+C - but this only happens if Renoise is open, or has been opened at least once during the session. If I reboot and run the script without opening Renoise, it works as intended. What could possibly be the issue here?
I'm using Python version 2.7.6, Pygame version 1.9.1, and Renoise version 3.0.0. This is all running on an Xubuntu 14.04 laptop.
Code for my main script (the imported OSC module is simply OSC.py available in many places on the internet):
#!/usr/bin/python
import sys
import pygame
import OSC
from pygame.locals import *
class Pot:
def __init__(self, ip, port):
self.clk = pygame.time.Clock()
self.screen = pygame.display.set_mode( (1600, 900) )
self.fillColor = pygame.Color(255,255,255)
pygame.display.set_caption("Pygame OSC Test")
self.client = OSC.OSCClient()
self.client.connect( (ip, port) )
def oscsend(self, addr, *data):
msg = OSC.OSCMessage()
msg.setAddress("/renoise" + str(addr))
for d in data:
msg.append(d)
try:
self.client.send(msg)
except OSC.OSCClientError, err:
print err
def tick(self):
# clear the screen
self.screen.fill(self.fillColor)
#TODO: other drawing stuff here
# process events
for event in pygame.event.get():
if event.type == QUIT:
self.client.close()
del(self.client)
return False
pygame.display.update()
self.clk.tick(10)
return True
if __name__ == "__main__":
p,f = pygame.init()
print "Num modules passed:", p
print "Num modules failed:", f
pot = Pot("localhost", 8000)
running = True
while running:
running = pot.tick()
pygame.quit()
sys.exit(0)
I managed to fix my problem by making sure pygame.mixer wasn't initialized. I assume it was causing some problems with Renoise by them both using the sound hardware at the same time.
To only initialize certain modules of pygame, just call their initialization methods individually. For instance, pygame.display.init() will initialize the Display module. Calling pygame.init() is simply a shortcut to initializing all the currently loaded modules. Hope this helps somebody!
Edited version after a closer look: You are returning False when the programme is quitted. But the variable "running" still remains true! Your loop is still going about his business and happily looping there...
I'd change it this way:
for event in pygame.event.get():
if event.type == QUIT:
self.client.close()
del(self.client)
pygame.quit()
sys.exit()
2nd option:
return False
Change this part that "running" is set to false. i'd go with the first option though.
If that doesn't solve the problem, please let me know, that would be an interesting issue to have a closer look at.

disable or lock mouse and keyboard in Python?

Is there a way of disabling or locking mouse and keyboard using python? I want to freeze the mouse and disable the keyboard.
I haven't tested (actually I've tested the mouse part, and it annoyingly works) but something like this using pyhook would do what you want:
import pythoncom, pyHook
def uMad(event):
return False
hm = pyHook.HookManager()
hm.MouseAll = uMad
hm.KeyAll = uMad
hm.HookMouse()
hm.HookKeyboard()
pythoncom.PumpMessages()
I have extended Fábio Diniz's answer to a class which provides both a block() and an unblock() function which block (selectively) mouse/keyboard inputs. I also added a timeout functionality which (hopefully) addresses the annoyance of locking oneself out.
import pyHook
from threading import Timer
import win32gui
import logging
class blockInput():
def OnKeyboardEvent(self,event):
return False
def OnMouseEvent(self,event):
return False
def unblock(self):
logging.info(" -- Unblock!")
if self.t.is_alive():
self.t.cancel()
try: self.hm.UnhookKeyboard()
except: pass
try: self.hm.UnhookMouse()
except: pass
def block(self, timeout = 10, keyboard = True, mouse = True):
self.t = Timer(timeout, self.unblock)
self.t.start()
logging.info(" -- Block!")
if mouse:
self.hm.MouseAll = self.OnMouseEvent
self.hm.HookMouse()
if keyboard:
self.hm.KeyAll = self.OnKeyboardEvent
self.hm.HookKeyboard()
win32gui.PumpWaitingMessages()
def __init__(self):
self.hm = pyHook.HookManager()
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
block = blockInput()
block.block()
import time
t0 = time.time()
while time.time() - t0 < 10:
time.sleep(1)
print(time.time() - t0)
block.unblock()
logging.info("Done.")
You can have a look at the main routine for example usage.
For me, just two lines of programming solved the problem:
from ctypes import *
ok = windll.user32.BlockInput(True) #enable block
#or
ok = windll.user32.BlockInput(False) #disable block
Totally different take since all the solutions mentioned above use a quiet outdated library(pyhook) and this pyhook method personally didnt work for me.
import keyboard
from pynput.mouse import Controller
from time import sleep
def blockinput():
global block_input_flag
block_input_flag = 1
t1 = threading.Thread(target=blockinput_start)
t1.start()
print("[SUCCESS] Input blocked!")
def unblockinput():
blockinput_stop()
print("[SUCCESS] Input unblocked!")
def blockinput_start():
mouse = Controller()
global block_input_flag
for i in range(150):
keyboard.block_key(i)
while block_input_flag == 1:
mouse.position = (0, 0)
def blockinput_stop():
global block_input_flag
for i in range(150):
keyboard.unblock_key(i)
block_input_flag = 0
blockinput()
print("now blocking")
sleep(5)
print("now unblocking")
I just slightly modified the #Robert code and instead of the time I used external interrupt to close the program i.e. if you connect any external drive then the program gets close and your mouse and keyboard will be working perfectly.
import pyHook
from threading import Timer
import win32gui
import logging
import win32file
def locate_usb():#this will check any external Drives
drive_list = []
drivebits = win32file.GetLogicalDrives()
# print(drivebits)
for d in range(1, 26):
mask = 1 << d
if drivebits & mask:
# here if the drive is at least there
drname = '%c:\\' % chr(ord('A') + d)
t = win32file.GetDriveType(drname)
if t == win32file.DRIVE_REMOVABLE:
drive_list.append(drname)
return drive_list
class blockInput():
def OnKeyboardEvent(self,event):
return False
def OnMouseEvent(self,event):
return False
def unblock(self):
try: self.hm.UnhookKeyboard()
except: pass
try: self.hm.UnhookMouse()
except: pass
def block(self ,keyboard = True, mouse = True):
while(1):
if mouse:
self.hm.MouseAll = self.OnMouseEvent
self.hm.HookMouse()
if keyboard:
self.hm.KeyAll = self.OnKeyboardEvent
self.hm.HookKeyboard()
win32gui.PumpWaitingMessages()
cg= locate_usb()
if cg:
break
def __init__(self):
self.hm = pyHook.HookManager()
if __name__ == '__main__':
block = blockInput()
block.block()
block.unblock()
I hope this code will help you
Since 2018, you can now use pynput (v1.4+) to suppress keyboard and mouse events on Windows, Mac, and Linux.
import pynput
# Disable mouse and keyboard events
mouse_listener = pynput.mouse.Listener(suppress=True)
mouse_listener.start()
keyboard_listener = pynput.keyboard.Listener(suppress=True)
keyboard_listener.start()
# Enable mouse and keyboard events
mouse_listener.stop()
keyboard_listener.stop()
This also disables mouse scrolling and clicking.
However, this does not stop users from pressing Ctrl+Alt+Del on Windows. But you can run the script in an elevated command prompt, and the mouse and keyboard will still be disabled, even if they opened Task Manager using Ctrl+Alt+Delete, so there is no harm done (apparently there are way to actually prevent Ctrl+Alt+Delete, but do your own research for that)
You can use pyautogui to do this. Though I recommend adding keyboard for making a stopping key. First, you want to install pyautogui and keyboard.
Please note: this only disables the mouse not the keyboard, that is a very bad idea.
pip install pyautogui
pip install keyboard
Ok, with that sorted, we have to actually make the disabler.
import pyautogui
import keyboard
stopKey = "s" #The stopKey is the button to press to stop. you can also do a shortcut like ctrl+s
maxX, maxY = pyautogui.size() #get max size of screen
While True:
if keyboard.is_pressed(stopKey):
break
else:
pyautogui.moveTo(maxX/2, maxY/2) #move the mouse to the center of the screen
Ok, but there is 2 ways to get out of this. pressing S, and also quickly moving the mouse to one of the corners of the screen (that is a pyautogui failsafe, but we can disable that). If you want to disable the failsafe, add this after the imports:
pyautogui.FAILSAFE = False
Please note that disabling the failsafe is NOT recommended!
Ok, so now the only way to exit is the S key. If you want to stop this somewhere else in your program, do this:
pyautogui.press(stopKey)
Ok, so its not perfect, but it will stop you from doing basically anything with your mouse.

pygame freezes when I try to exit it after running it from IDLE!

I'm running it through the livewires wrapper which is just training wheels for pygame and other python modules in general; but everytime I run it, it'll execute and when I try to exit, it will not respond and then crash.
Any input on how I could go about fixing this would be great. There isn't any input in my textbook and all google seems to yield are results to this problem using pygame itself.
Apparently pygame and Tkinter seem to conflict?
Thanks in advance!
Addendum - This is the code I was trying to run:
from livewires import games
screen_w = 640
screen_h = 480
my_screen = games.Screen (wid, heit)
my_screen.mainloop()
Similar question: Pygame screen freezes when I close it
There isn't any input in my textbook
and all google seems to yield are
results to this problem using pygame
itself.
Those results probably address the same problem you're having. This is the relevant part of the games.py file from livewires, and nowhere does it call pygame.quit():
def handle_events (self):
"""
If you override this method in a subclass of the Screen
class, you can specify how to handle different kinds of
events. However you must handle the quit condition!
"""
events = pygame.event.get ()
for event in events:
if event.type == QUIT:
self.quit ()
elif event.type == KEYDOWN:
self.keypress (event.key)
elif event.type == MOUSEBUTTONUP:
self.mouse_up (event.pos, event.button-1)
elif event.type == MOUSEBUTTONDOWN:
self.mouse_down (event.pos, event.button-1)
def quit (self):
"""
Calling this method will stop the main loop from running and
make the graphics window disappear.
"""
self._exit = 1
def mainloop (self, fps = 50):
"""
Run the pygame main loop. This will animate the objects on the
screen and call their tick methods every tick.
fps -- target frame rate
"""
self._exit = 0
while not self._exit:
self._wait_frame (fps)
for object in self._objects:
if not object._static:
object._erase ()
object._dirty = 1
# Take a copy of the _objects list as it may get changed in place.
for object in self._objects [:]:
if object._tickable: object._tick ()
self.tick ()
if Screen.got_statics:
for object in self._objects:
if not object._static:
for o in object.overlapping_objects ():
if o._static and not o._dirty:
o._erase ()
o._dirty = 1
for object in self._objects:
if object._dirty:
object._draw ()
object._dirty = 0
self._update_display()
self.handle_events()
# Throw away any pending events.
pygame.event.get()
The QUIT event just sets a flag which drops you out of the while loop in the mainloop function. I'm guessing that if you find this file in your Python directory and stick a pygame.quit() after the last line in mainloop, it will solve your problem.
I agree. you need to put the whole program (the part to be executed, not the definitions and such) into a while loop.The problem is that pygame is not told to close when exited in IDLE, but outside of IDLE the closure of the program overrides the need to close pygame.
here is the loop:
done = False
while done==False:
# ALL EVENT PROCESSING SHOULD GO BELOW THIS COMMENT
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done=True # Flag that we are done so we exit this loop
#Main program here
pygame.quit()

Categories

Resources