I am using PySDL2 and I am coding a little script that load a image on a windows but I am getting this error message "ctypes.ArgumentError: argument 4: : expected LP_c_int instance instead of int" when i use this function "SDL_QueryTexture". This is my code:
"""Simple example for using sdl2 directly."""
import os
import sys
import ctypes
from sdl2 import *
def run():
SDL_Init(SDL_INIT_VIDEO)
window = SDL_CreateWindow(b"Hello World",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
459, 536, SDL_WINDOW_SHOWN)
render = SDL_CreateRenderer(window, -1, 0)
fname = os.path.join(os.path.dirname(os.path.abspath(__file__)),
"resources", "self-control.bmp")
imageSurface = SDL_LoadBMP(fname.encode("utf-8"))
imageTexture = SDL_CreateTextureFromSurface(render, imageSurface)
SDL_FreeSurface(imageSurface)
sourceRectangle = SDL_Rect()
destinationRectangle = SDL_Rect()
SDL_QueryTexture(imageTexture, None, None, sourceRectangle.w, sourceRectangle.h)
destinationRectangle.x = sourceRectangle.x = 0
destinationRectangle.y = sourceRectangle.y = 0
destinationRectangle.w = sourceRectangle.w
destinationRectangle.h = sourceRectangle.h
SDL_RenderCopy(render, imageTexture, sourceRectangle, destinationRectangle)
running = True
event = sdl2.SDL_Event()
while running:
while SDL_PollEvent(ctypes.byref(event)) != 0:
if event.type == sdl2.SDL_QUIT:
running = False
break
SDL_Delay(10)
SDL_DestroyWindow(window)
SDL_Quit()
return 0
if __name__ == "__main__":
sys.exit(run())
I know is something related to ctypes, i hope someone can help me.
SDL_QueryTexture gets pointers to ints to write result to, you cannot simply pass int here. Workaround would be something like
w = ctypes.c_int()
h = ctypes.c_int()
SDL_QueryTexture(imageTexture, None, None, w, h)
And then getting result from w.value and h.value.
However you already have a surface, why not just read width and height from it?
imageSurface.contents.w, imageSurface.contents.h
Related
I am trying to program something with win32gui and now I need to know how I can get the filelocation of the file I am running in Visual Studio Code, Word or Wordpad. I used win32gui.GetOpenFileName, but it doesn't work anymore after I checked the type of variable I get. My question is: Is it the best way to get the filelocation or is there a better way. If it is the best way does someone know why it's not working anymore?
My Second question is regarding the running of the script. I want to run the script automatically as soon as I start Word, Visual Studio Code or Wordpad. What is the best way to do this?
I tried finding solutions online but at the moment I am lacking inspiration. Thank you for your help.
Update>
I got this far with the code. I want to change it so that I can get the file automatically and I want to start is with Visual Studio Code instead of starting it manuely every time.
import win32gui
import math
e = math.e
maxwidth = 1874
maxheight = 950
x =450
y = 1500 + round(maxwidth/(1+e**(-0.009*(0-57.45))))
#minwidth = 700
#minheight = 505
k = 0
l = 0
def main():
win32gui.EnumWindows(callback, None)
def callback(hwnd, extra):
windowopen = False
name = win32gui.GetWindowText(hwnd)
if name.endswith('Visual Studio Code') and name.startswith('_test.py'):
windowopen = True
print(name)
while windowopen:
j = 0
for i in open('D:\_test.py', 'r'):
j += 1
k = round(maxwidth/(1+e**(-0.009*(j-57.45))))
l = round(maxheight/(1+e**(-0.009*(j-57.45))))
yuse = y - k
win32gui.MoveWindow(hwnd, yuse, x, k, l, True)
print(name)
file = win32gui.GetOpenFileName
print(file)
if __name__ == '__main__':
main()
Update>
I imported os and than used the .path.dirname function to get my file location:
import os
dir_path = os.path.dirname(os.path.realpath(__file__))
I referenced the Pygame MIDI documentation and this code to try to get MIDI input to work.
The MIDI Interface (Avid Eleven Rack) receives MIDI data from my MIDI controller just fine in my audio software (Pro Tools). Using Pygame, however, I can not seem to read any information at all.
Source Code
import pygame
from pygame.locals import *
from pygame import midi
class MidiInput():
def __init__(self):
# variables
self.elevenRackInID = 2
# init methods
pygame.init()
pygame.midi.init()
self.midiInput = pygame.midi.Input(self.elevenRackInID, 100)
def run(self):
# print(pygame.midi.Input(3, 100))
# for i in range(10):
# print(pygame.midi.get_device_info(i), i)
self.read = self.midiInput.read(100)
# self.convert = pygame.midi.midis2events(self.read, self.elevenRackInID)
print(self.read)
test = MidiInput()
while True:
test.run()
The only thing printed to the console are empty square brackets:
[]
Additional Info
I just checked again: the input ID is the right one and it is in fact an input.
"self.midiInput.poll()" returns False. So according to the Pygame documentation there is no data coming in.
You can see the data, poll and device info below:
data: [] || poll: False || device info: (b'MMSystem', b'Eleven Rack', 1, 0, 1)
A list of all my MIDI devices according to Pygame (with indexes):
(b'MMSystem', b'Microsoft MIDI Mapper', 0, 1, 0) 0
(b'MMSystem', b'External', 1, 0, 0) 1
(b'MMSystem', b'Eleven Rack', 1, 0, 1) 2
(b'MMSystem', b'Maschine Mikro MK2 In', 1, 0, 0) 3
(b'MMSystem', b'Microsoft GS Wavetable Synth', 0, 1, 0) 4
(b'MMSystem', b'External', 0, 1, 0) 5
(b'MMSystem', b'Eleven Rack', 0, 1, 0) 6
(b'MMSystem', b'Maschine Mikro MK2 Out', 0, 1, 0) 7
Any help or suggestions are greatly appreciated!
I got an answer in another forum. It turns out that there is an example file which shows how to get the code to work.
So if someone else stumbles over this problem here is the useful part of example code:
import sys
import os
import pygame as pg
import pygame.midi
def print_device_info():
pygame.midi.init()
_print_device_info()
pygame.midi.quit()
def _print_device_info():
for i in range(pygame.midi.get_count()):
r = pygame.midi.get_device_info(i)
(interf, name, input, output, opened) = r
in_out = ""
if input:
in_out = "(input)"
if output:
in_out = "(output)"
print(
"%2i: interface :%s:, name :%s:, opened :%s: %s"
% (i, interf, name, opened, in_out)
)
def input_main(device_id=None):
pg.init()
pg.fastevent.init()
event_get = pg.fastevent.get
event_post = pg.fastevent.post
pygame.midi.init()
_print_device_info()
if device_id is None:
input_id = pygame.midi.get_default_input_id()
else:
input_id = device_id
print("using input_id :%s:" % input_id)
i = pygame.midi.Input(input_id)
pg.display.set_mode((1, 1))
going = True
while going:
events = event_get()
for e in events:
if e.type in [pg.QUIT]:
going = False
if e.type in [pg.KEYDOWN]:
going = False
if e.type in [pygame.midi.MIDIIN]:
print(e)
if i.poll():
midi_events = i.read(10)
# convert them into pygame events.
midi_evs = pygame.midi.midis2events(midi_events, i.device_id)
for m_e in midi_evs:
event_post(m_e)
del i
pygame.midi.quit()
You can find the file yourself in this directory:
C:\Users\myUser\AppData\Roaming\Python\Python37\site-packages\pygame\examples\midi.py
Replace 'myUser' with your Win username. Also, 'Python37' can vary on the version of Python you have installed.
I don't believe the code posted below by Leonhard W is usable: neither the pygame.midi poll() method nor the pygame.midi read() method are blocking. The result is that CPU consumption goes through the roof (~50%).
Of course in practice the code to read the MIDI events would be run in a separate thread, though this won't help with CPU consumption.
In response to another very useful comment elsewhere, I've taken a look at the Mido library (https://mido.readthedocs.io/en/latest/index.html#). This provides blocking read methods and with just a few lines of code I can look for messages from a MIDI controller keyboard and pass them onto a MIDI synth.
import mido
names = mido.get_input_names()
print(names)
out_port = mido.open_output()
with mido.open_input(names[0]) as inport:
for msg in inport:
out_port.send(msg)
The only downside is that I'm getting a significant delay (perhaps 1/4s) between hitting the key and hearing the note. Oh well, onwards and upwards.
how can I execute mouse clicks in windows from Python code that is running in WSL?
I tried using PyAutoGUI, however, I get the following error:
...
File "/usr/lib/python3.6/os.py", line 669, in __getitem__
raise KeyError(key) from None
KeyError: 'DISPLAY'
Because I am using wsl, it decides that my platform is linux. If I hardcode it to windows, ctypes do have attribute win.dll in dc = ctypes.windll.user32.GetDC(0)
if sys.platform == 'win32':
import ctypes
if _PILLOW_INSTALLED:
from PIL import ImageGrab
# Makes this process aware of monitor scaling so the screenshots are correctly sized:
try:
ctypes.windll.user32.SetProcessDPIAware()
except AttributeError:
pass # Windows XP doesn't support this, so just do nothing.
dc = ctypes.windll.user32.GetDC(0)
class POINT(ctypes.Structure):
_fields_ = [('x', ctypes.c_long),
('y', ctypes.c_long)]
def _winPosition():
cursor = POINT()
ctypes.windll.user32.GetCursorPos(ctypes.byref(cursor))
return (cursor.x, cursor.y)
position = _winPosition
def _winScreenshot(filename=None):
# TODO - Use the winapi to get a screenshot, and compare performance with ImageGrab.grab()
# https://stackoverflow.com/a/3586280/1893164
try:
im = ImageGrab.grab()
if filename is not None:
im.save(filename)
except NameError:
raise ImportError('Pillow module must be installed to use screenshot functions on Windows.')
return im
screenshot = _winScreenshot
def _winSize():
return (ctypes.windll.user32.GetSystemMetrics(0), ctypes.windll.user32.GetSystemMetrics(1))
size = _winSize
def _winGetPixel(x, y):
colorRef = ctypes.windll.gdi32.GetPixel(dc, x, y) # A COLORREF value as 0x00bbggrr. See https://learn.microsoft.com/en-us/windows/win32/gdi/colorref
red = colorRef % 256
colorRef //= 256
green = colorRef % 256
colorRef //= 256
blue = colorRef
return (red, green, blue)
getPixel = _winGetPixel
elif platform.system() == 'Linux':
from Xlib.display import Display
import errno
scrotExists = False
try:
whichProc = subprocess.Popen(
['which', 'scrot'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
scrotExists = whichProc.wait() == 0
except OSError as ex:
if ex.errno == errno.ENOENT:
# if there is no "which" program to find scrot, then assume there
# is no scrot.
pass
else:
raise
_display = Display(os.environ['DISPLAY'])
def _linuxPosition():
coord = _display.screen().root.query_pointer()._data
return coord["root_x"], coord["root_y"]
position = _linuxPosition
def _linuxScreenshot(filename=None):
if not scrotExists:
raise NotImplementedError('"scrot" must be installed to use screenshot functions in Linux. Run: sudo apt-get install scrot')
if filename is not None:
tmpFilename = filename
else:
tmpFilename = '.screenshot%s.png' % (datetime.datetime.now().strftime('%Y-%m%d_%H-%M-%S-%f'))
if scrotExists:
subprocess.call(['scrot', '-z', tmpFilename])
im = Image.open(tmpFilename)
# force loading before unlinking, Image.open() is lazy
im.load()
if filename is None:
os.unlink(tmpFilename)
return im
else:
raise Exception('The scrot program must be installed to take a screenshot with PyScreeze on Linux. Run: sudo apt-get install scrot')
screenshot = _linuxScreenshot
def _linuxSize():
return _display.screen().width_in_pixels, _display.screen().height_in_pixels
size = _linuxSize
def _linuxGetPixel(x, y):
rgbValue = screenshot().getpixel((x, y))
return rgbValue[0], rgbValue[1], rgbValue[2]
getPixel = _linuxGetPixel
Does anyone know how to solve this problem?
Just to clarify... pyautogui will not work with WSL? Based on what I have read elsewhere this has to do with the lack of an X-server in the linux subsystem. Similar to how pyautogui will not work over a remote or headless terminal session.
So, try this with just plain old windows and it will work!
you could try adding this line AFTER importing pyautogui.
import pyautogui._pyautogui_win as platformModule
This should reassign / override the platformModule variable to the Windows version..
(In theory)
I want to detect applications window name when changing focus event occurs with python xlib, so in the first step I use this code:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import Xlib.display
import time
display = Xlib.display.Display()
while True:
window = display.get_input_focus().focus
wmname = window.get_wm_name()
wmclass = window.get_wm_class()
if wmclass is None and wmname is None:
window = window.query_tree().parent
wmname = window.get_wm_name()
print "WM Name: %s" % ( wmname, )
time.sleep(3)
But I want a correct way, then I research about xlib events and find Input Focus Events and write this code:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import Xlib.display
from Xlib import X
def main():
display = Xlib.display.Display(':0')
root = display.screen().root
root.change_attributes(event_mask=Xlib.X.FocusChangeMask)
while True:
event = root.display.next_event()
#if event.type == X.FocusIn or event.type == X.FocusOut:
if event.type == X.FocusOut :
window = display.get_input_focus().focus
wmname = window.get_wm_name()
wmclass = window.get_wm_class()
if wmclass is None and wmname is None:
window = window.query_tree().parent
wmname = window.get_wm_name()
print "WM Name: %s" % ( wmname, )
if __name__ == "__main__":
main()
Sadly it's not work correctly especially in tabbed browsing on google chrome and firefox, so Is there a correct way for this situation?
Your code is almost right, but it misses two things:
rather than listening only to focus changes, it should also listen to window property events which include changes of WM_NAME property, that also happen when you cycle tabs in your browser.
rather than listening only in root window, it should listen to every window (that gets focused). You can attach the event handler the same way as you do with the root window.
That being said, here is a working sample:
#!/usr/bin/python3
import Xlib
import Xlib.display
disp = Xlib.display.Display()
root = disp.screen().root
NET_WM_NAME = disp.intern_atom('_NET_WM_NAME')
NET_ACTIVE_WINDOW = disp.intern_atom('_NET_ACTIVE_WINDOW')
root.change_attributes(event_mask=Xlib.X.FocusChangeMask)
while True:
try:
window_id = root.get_full_property(NET_ACTIVE_WINDOW, Xlib.X.AnyPropertyType).value[0]
window = disp.create_resource_object('window', window_id)
window.change_attributes(event_mask=Xlib.X.PropertyChangeMask)
window_name = window.get_full_property(NET_WM_NAME, 0).value
except Xlib.error.XError: #simplify dealing with BadWindow
window_name = None
print(window_name)
event = disp.next_event()
#rr- As I just corrected elsewhere, you'll want to query both the current _NET_WM_NAME (UTF-8) and the legacy WM_NAME (non-UTF8) properties or the default xterm configuration will return no title.
I just posted a complete working example over on your Unix & Linux StackExchange question.
To avoid sending people on a cross-reference hunt, here's a copy of the code I posted there:
#!/usr/bin/python
from contextlib import contextmanager
import Xlib
import Xlib.display
disp = Xlib.display.Display()
root = disp.screen().root
NET_ACTIVE_WINDOW = disp.intern_atom('_NET_ACTIVE_WINDOW')
NET_WM_NAME = disp.intern_atom('_NET_WM_NAME') # UTF-8
WM_NAME = disp.intern_atom('WM_NAME') # Legacy encoding
last_seen = { 'xid': None, 'title': None }
#contextmanager
def window_obj(win_id):
"""Simplify dealing with BadWindow (make it either valid or None)"""
window_obj = None
if win_id:
try:
window_obj = disp.create_resource_object('window', win_id)
except Xlib.error.XError:
pass
yield window_obj
def get_active_window():
win_id = root.get_full_property(NET_ACTIVE_WINDOW,
Xlib.X.AnyPropertyType).value[0]
focus_changed = (win_id != last_seen['xid'])
if focus_changed:
with window_obj(last_seen['xid']) as old_win:
if old_win:
old_win.change_attributes(event_mask=Xlib.X.NoEventMask)
last_seen['xid'] = win_id
with window_obj(win_id) as new_win:
if new_win:
new_win.change_attributes(event_mask=Xlib.X.PropertyChangeMask)
return win_id, focus_changed
def _get_window_name_inner(win_obj):
"""Simplify dealing with _NET_WM_NAME (UTF-8) vs. WM_NAME (legacy)"""
for atom in (NET_WM_NAME, WM_NAME):
try:
window_name = win_obj.get_full_property(atom, 0)
except UnicodeDecodeError: # Apparently a Debian distro package bug
title = "<could not decode characters>"
else:
if window_name:
win_name = window_name.value
if isinstance(win_name, bytes):
# Apparently COMPOUND_TEXT is so arcane that this is how
# tools like xprop deal with receiving it these days
win_name = win_name.decode('latin1', 'replace')
return win_name
else:
title = "<unnamed window>"
return "{} (XID: {})".format(title, win_obj.id)
def get_window_name(win_id):
if not win_id:
last_seen['title'] = "<no window id>"
return last_seen['title']
title_changed = False
with window_obj(win_id) as wobj:
if wobj:
win_title = _get_window_name_inner(wobj)
title_changed = (win_title != last_seen['title'])
last_seen['title'] = win_title
return last_seen['title'], title_changed
def handle_xevent(event):
if event.type != Xlib.X.PropertyNotify:
return
changed = False
if event.atom == NET_ACTIVE_WINDOW:
if get_active_window()[1]:
changed = changed or get_window_name(last_seen['xid'])[1]
elif event.atom in (NET_WM_NAME, WM_NAME):
changed = changed or get_window_name(last_seen['xid'])[1]
if changed:
handle_change(last_seen)
def handle_change(new_state):
"""Replace this with whatever you want to actually do"""
print(new_state)
if __name__ == '__main__':
root.change_attributes(event_mask=Xlib.X.PropertyChangeMask)
get_window_name(get_active_window()[0])
handle_change(last_seen)
while True: # next_event() sleeps until we get an event
handle_xevent(disp.next_event())
There's also a more heavily commented version in this GitHub Gist.
Suppose we want to drive an autonomous car by predicting image labels from a previous set of images and labels collected (A Machine Learning application). For this task, the car is connected via bluetooth serial (rfcomm) to the Host Computer (A PC with *NIX) and the images are streamed directly from an Android phone using IP Webcam, meanwhile, the PC is running a program that links this two functions, displaying the captured images in a drawing environment created by pygame, and sending the instructions back to the car using serial.
At the moment, I've tried to implement those processes using the multiprocessing module, the seemed to work, but when I execute the client, the drawing function (if __name__ == '__main__') works after the getKeyPress() function ends.
The question is: It is possible to parallelize or synchronize the drawing fuinction enclosed within the if __name__ == '__main__' with the process declared in getKyPress(), such that the program works in two independent processes?
Here's the implemented code so far:
import urllib
import time
import os
import sys
import serial
import signal
import multiprocessing
import numpy as np
import scipy
import scipy.io as sio
import matplotlib.image as mpimg
from pygame.locals import *
PORT = '/dev/rfcomm0'
SPEED = 115200
ser = serial.Serial(PORT)
status = False
move = None
targets = []
inputs = []
tic = False
def getKeyPress():
import pygame
pygame.init()
global targets
global status
while not status:
pygame.event.pump()
keys = pygame.key.get_pressed()
targets, status = processOutputs(targets, keys)
targets = np.array(targets)
targets = flattenMatrix(targets)
sio.savemat('targets.mat', {'targets':targets})
def rgb2gray(rgb):
r, g, b = np.rollaxis(rgb[...,:3], axis = -1)
return 0.299 * r + 0.587 * g + 0.114 * b
def processImages(inputX, inputs):
inputX = flattenMatrix(inputX)
if len(inputs) == 0:
inputs = inputX
elif inputs.shape[1] >= 1:
inputs = np.hstack((inputs, inputX))
return inputs
def flattenMatrix(mat):
mat = mat.flatten(1)
mat = mat.reshape((len(mat), 1))
return mat
def send_command(val):
connection = serial.Serial( PORT,
SPEED,
timeout=0,
stopbits=serial.STOPBITS_TWO
)
connection.write(val)
connection.close()
def processOutputs(targets, keys):
global move
global status
global tic
status = False
keypress = ['K_p', 'K_UP', 'K_LEFT', 'K_DOWN', 'K_RIGHT']
labels = [1, 2, 3, 4, 5]
commands = ['p', 'w', 'r', 'j', 's']
text = ['S', 'Up', 'Left', 'Down', 'Right']
if keys[K_q]:
status = True
return targets, status
else:
for i, j, k, g in zip(keypress, labels, commands, text):
cmd = compile('cond = keys['+i+']', '<string>', 'exec')
exec cmd
if cond:
move = g
targets.append(j)
send_command(k)
break
send_command('p')
return targets, status
targetProcess = multiprocessing.Process(target=getKeyPress)
targetProcess.daemon = True
targetProcess.start()
if __name__ == '__main__':
import pygame
pygame.init()
w = 288
h = 352
size=(w,h)
screen = pygame.display.set_mode(size)
c = pygame.time.Clock() # create a clock object for timing
pygame.display.set_caption('Driver')
ubuntu = pygame.font.match_font('Ubuntu')
font = pygame.font.Font(ubuntu, 13)
inputs = []
try:
while not status:
urllib.urlretrieve("http://192.168.0.10:8080/shot.jpg", "input.jpg")
try:
inputX = mpimg.imread('input.jpg')
except IOError:
status = True
inputX = rgb2gray(inputX)/255
out = inputX.copy()
out = scipy.misc.imresize(out, (352, 288), interp='bicubic', mode=None)
scipy.misc.imsave('input.png', out)
inputs = processImages(inputX, inputs)
print inputs.shape[1]
img=pygame.image.load('input.png')
screen.blit(img,(0,0))
pygame.display.flip()
c.tick(1)
if move != None:
text = font.render(move, False, (255, 128, 255), (0, 0, 0))
textRect = text.get_rect()
textRect.centerx = 20 #screen.get_rect().centerx
textRect.centery = 20 #screen.get_rect().centery
screen.blit(text, textRect)
pygame.display.update()
if status:
targetProcess.join()
sio.savemat('inputs.mat', {'inputs':inputs})
except KeyboardInterrupt:
targetProcess.join()
sio.savemat('inputs.mat', {'inputs':inputs})
targetProcess.join()
sio.savemat('inputs.mat', {'inputs':inputs})
Thanks in advance.
I would personally suggest writing this without using the multiprocessing module: it uses fork() which has unspecified effects with most complex libraries, like in this case pygame.
You should try to write this as two completely separate programs. It forces you to think about what data needs to go from one to the other, which is both a bad and a good thing (as it may clarify things). You can use some inter-process communication facility, like the stdin/stdout pipe; e.g. in one program (the "main" one) you start the other as a sub-process like this:
popen = subprocess.Popen([sys.executable, '-u', 'my_subproc.py'],
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
(The -u is for unbuffered.)
Then read/write the data to popen.stdin/popen.stdout in the parent process, and to sys.stdin/sys.stdout in the subprocess. The simplest example would be if the two processes only need a synchronization signal, e.g. the parent process waits in a loop for the subprocess to say "next please". To do this the subprocess does print 'next please', and the parent process does popen.stdin.readline(). (The print goes to sys.stdin in the subprocess.)
Unrelated small note:
keypress = ['K_p', ...]
...
cmd = compile('cond = keys['+i+']', '<string>', 'exec')
exec cmd
if cond:
This looks like very heavy code to just do:
keypress = [K_p, ...] # not strings, directly the values
...
if keys[i]:
My suggestion is to use separate threads.
#At the beginning
import threading
#Instead of def getKeyPress()
class getKeyPress(threading.Thread):
def run(self):
import pygame
pygame.init()
global targets
global status
while not status:
pygame.event.pump()
keys = pygame.key.get_pressed()
targets, status = processOutputs(targets, keys)
targets = np.array(targets)
targets = flattenMatrix(targets)
sio.savemat('targets.mat', {'targets':targets})
#Instead of
#targetProcess = multiprocessing.Process(target=getKeyPress)
#targetProcess.daemon = True
#targetProcess.start()
gkp = getKeyPress()
gkp.start()
An alternative would be creating two different scripts and using sockets to handle the inter-process communication.