I want to detect mouse movement events with python-curses. I don't know how to enable these events. I tried to enable all mouse-events as follows:
stdscr = curses.initscr()
curses.mousemask(curses.REPORT_MOUSE_POSITION | curses.ALL_MOUSE_EVENTS)
while True:
c = stdscr.getch()
if c == curses.KEY_MOUSE:
id, x, y, z, bstate = curses.getmouse()
stdscr.addstr(curses.LINES-2, 0, "x: " + str(x))
stdscr.addstr(curses.LINES-1, 0, "y: " + str(y))
stdscr.refresh()
if c == ord('q'):
break
curses.endwin()
I only get mouse-events when a mouse-button is clicked, pushed-down, etc but no mouse move events. How do I enable these events?
I got it to work by changing my $TERM env var / terminfo. On Ubuntu it worked by simply setting TERM=screen-256color, but on OSX I had to edit a terminfo file, using the instructions here:
Which $TERM to use to have both 256 colors and mouse move events in python curses?
but for me the format was different so I added the line:
XM=\E[?1003%?%p1%{1}%=%th%el%;,
To test it, I used this Python code (note screen.keypad(1) is very necessary, otherwise mouse events cause getch to return escape key codes).
import curses
screen = curses.initscr()
screen.keypad(1)
curses.curs_set(0)
curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION)
curses.flushinp()
curses.noecho()
screen.clear()
while True:
key = screen.getch()
screen.clear()
screen.addstr(0, 0, 'key: {}'.format(key))
if key == curses.KEY_MOUSE:
_, x, y, _, button = curses.getmouse()
screen.addstr(1, 0, 'x, y, button = {}, {}, {}'.format(x, y, button))
elif key == 27:
break
curses.endwin()
curses.flushinp()
Related
I am using scrcpy to mirror an Android phone to my computer in order to play a game. The issue is that scrcpy does not support keyboard mapping natively, so I'm writing a Python script to map the keyboard to execute the key presses I need to play the game (using WASD to move around, space to jump, etc.).
I'm fairly new to programing in general and to Python in particular, but so far it's been going pretty well using Pynput. Basically, I am mapping different keys on my keyboard to correspond to mouse clicks on different areas of the screen. My issue is that, as written, my script can only push one left mouse press event at a time.
For example, pressing "w" (to move forward) and space (jump) at the same time will move the cursor to different areas on the screen, and will therefore not result in the desired outcome. The game itself supports simultaneous touch input when played on an Android screen (I can press different areas on the screen at the same time to execute certain actions), so ideally I would need my script to be able to recreate this behavior.
I was wondering if there was a way to do this in Python?
from pynput.mouse import Button, Controller
from pynput.keyboard import Key, KeyCode, Listener
global MOUSE
MOUSE = Controller()
global CENTER
global HEIGHT
CENTER = 315
HEIGHT = 800
global LISTEN
def cust_click(x,y):
MOUSE.position = (x,y)
MOUSE.press(Button.left)
def cust_mvmt_click(x, y):
MOUSE.position = (CENTER, HEIGHT)
MOUSE.press(Button.left)
MOUSE.move(x, y)
#WASD movement
def w():
cust_mvmt_click(0, -100)
def s():
cust_mvmt_click(0, 100)
def a():
cust_mvmt_click(-100, 0)
def d():
cust_mvmt_click(100, 0)
#Miscellaneous
def space():
cust_click(CENTER*5.75,HEIGHT*0.95)
def c():
cust_click(CENTER*5.15, HEIGHT*1.2)
#Weapon controls
def r():
cust_click(CENTER*4.75, HEIGHT*1.15)
def f():
cust_click(CENTER*0.5, HEIGHT*0.7)
def ctrl():
cust_click(CENTER*5.15, HEIGHT)
def q():
cust_click(CENTER*5.3, HEIGHT*0.77)
def switch1():
cust_click(CENTER*2.75, HEIGHT*1.15)
def switch2():
cust_click(CENTER*3.3, HEIGHT*1.15)
def switch3():
cust_click(CENTER*3, HEIGHT*1.05)
def on_press(key):
if key == KeyCode(char='w'):
w()
elif key == KeyCode(char='f'):
f()
elif key == Key.shift_l:
ctrl()
elif key == KeyCode(char='q'):
q()
elif key == KeyCode(char='s'):
s()
elif key == KeyCode(char='a'):
a()
elif key == KeyCode(char='d'):
d()
elif key == KeyCode(char='c'):
c()
elif key == KeyCode(char='r'):
r()
elif key == Key.space:
space()
elif key == KeyCode(char='1'):
switch1()
elif key == KeyCode(char='2'):
switch2()
elif key == KeyCode(char='3'):
switch3()
elif key == Key.tab:
LISTEN.stop()
def on_release(key):
if key == Key.shift_l or key == KeyCode(char='1') or key == KeyCode(char='f') or key == KeyCode(char='2') or key == KeyCode(char='3') or key == KeyCode(char='r') or key == KeyCode(char='c') or key == KeyCode(char='s') or key == KeyCode(char='a') or key == KeyCode(char='d') or key == Key.space or key == KeyCode(char='q') or key == KeyCode(char='w'):
MOUSE.release(Button.left)
MOUSE.position = (CENTER*390/100,HEIGHT*70/100) #1235, 565
# Collect events until released
with Listener(
on_press=on_press,
on_release=on_release) as LISTEN:
LISTEN.join()
You can use pydirectinput or pydirectinput-rgx for clicking. Check
https://www.google.com/url?sa=t&source=web&rct=j&url=https://pypi.org/project/PyDirectInput/&ved=2ahUKEwi9sbb7w6b6AhXE23MBHV85ChgQFnoECBEQAQ&usg=AOvVaw2EChi0UGXZlMafbw1aHhod
for its documentation.
I want to detect mouse movement events with python-curses. I don't know how to enable these events. I tried to enable all mouse-events as follows:
stdscr = curses.initscr()
curses.mousemask(curses.REPORT_MOUSE_POSITION | curses.ALL_MOUSE_EVENTS)
while True:
c = stdscr.getch()
if c == curses.KEY_MOUSE:
id, x, y, z, bstate = curses.getmouse()
stdscr.addstr(curses.LINES-2, 0, "x: " + str(x))
stdscr.addstr(curses.LINES-1, 0, "y: " + str(y))
stdscr.refresh()
if c == ord('q'):
break
curses.endwin()
I only get mouse-events when a mouse-button is clicked, pushed-down, etc but no mouse move events. How do I enable these events?
I got it to work by changing my $TERM env var / terminfo. On Ubuntu it worked by simply setting TERM=screen-256color, but on OSX I had to edit a terminfo file, using the instructions here:
Which $TERM to use to have both 256 colors and mouse move events in python curses?
but for me the format was different so I added the line:
XM=\E[?1003%?%p1%{1}%=%th%el%;,
To test it, I used this Python code (note screen.keypad(1) is very necessary, otherwise mouse events cause getch to return escape key codes).
import curses
screen = curses.initscr()
screen.keypad(1)
curses.curs_set(0)
curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION)
curses.flushinp()
curses.noecho()
screen.clear()
while True:
key = screen.getch()
screen.clear()
screen.addstr(0, 0, 'key: {}'.format(key))
if key == curses.KEY_MOUSE:
_, x, y, _, button = curses.getmouse()
screen.addstr(1, 0, 'x, y, button = {}, {}, {}'.format(x, y, button))
elif key == 27:
break
curses.endwin()
curses.flushinp()
I'm trying to build a short script in Python, where if the mouse is clicked, the mouse will reset to some arbitrary position (right now the middle of the screen).
I'd like this to run in the background, so it could work with other applications (most likely Chrome, or some web browser). I'd also like it so that a user could hold down a certain button (say CTRL) and they could click away and not have the position reset. This way they could close the script without frustration.
I'm pretty sure I know how to do this, but I'm not sure which library to use. I'd prefer if it was cross-platform, or at least work on Windows and Mac.
Here's my code so far:
#! python3
# resetMouse.py - resets mouse on click - usuful for students with
# cognitive disabilities.
import pymouse
width, height = m.screen_size()
midWidth = (width + 1) / 2
midHeight = (height + 1) / 2
m = PyMouse()
k = PyKeyboard()
def onClick():
m.move(midWidth, midHeight)
try:
while True:
# if button is held down:
# continue
# onClick()
except KeyboardInterrupt:
print('\nDone.')
Try this
from pynput.mouse import Listener
def on_move(x, y):
print(x, y)
def on_click(x, y, button, pressed):
print(x, y, button, pressed)
def on_scroll(x, y, dx, dy):
print(x, y, dx, dy)
with Listener(on_move=on_move, on_click=on_click, on_scroll=on_scroll) as listener:
listener.join()
The following code worked perfectly for me. Thanks to Hasan's answer.
from pynput.mouse import Listener
def is_clicked(x, y, button, pressed):
if pressed:
print('Clicked ! ') #in your case, you can move it to some other pos
return False # to stop the thread after click
with Listener(on_click=is_clicked) as listener:
listener.join()
I was able to make it work just with win32api. It works when clicking on any window.
import win32api
import time
width = win32api.GetSystemMetrics(0)
height = win32api.GetSystemMetrics(1)
midWidth = int((width + 1) / 2)
midHeight = int((height + 1) / 2)
state_left = win32api.GetKeyState(0x01) # Left button up = 0 or 1. Button down = -127 or -128
while True:
a = win32api.GetKeyState(0x01)
if a != state_left: # Button state changed
state_left = a
print(a)
if a < 0:
print('Left Button Pressed')
else:
print('Left Button Released')
win32api.SetCursorPos((midWidth, midHeight))
time.sleep(0.001)
I was able to make it work for Windows using pyHook and win32api:
import win32api, pyHook, pythoncom
width = win32api.GetSystemMetrics(0)
height = win32api.GetSystemMetrics(1)
midWidth = (width + 1) / 2
midHeight = (height + 1) / 2
def moveCursor(x, y):
print('Moving mouse')
win32api.SetCursorPos((x, y))
def onclick(event):
print(event.Position)
moveCursor(int(midWidth), int(midHeight))
return True
try:
hm = pyHook.HookManager()
hm.SubscribeMouseAllButtonsUp(onclick)
hm.HookMouse()
pythoncom.PumpMessages()
except KeyboardInterrupt:
hm.UnhookMouse()
print('\nDone.')
exit()
PYTHON 3.3, msvcrt
import sys, msvcrt
print("Please press a key to see its value")
while 1:
key = msvcrt.getch()
print("the key is")
print(key)
if ord(key) == 27: # key nr 27 is escape
sys.exit()
this is my code, just as an example.
the code pauses when it gets to the key = msvcrt.getch()*, or *key = ord(getch()) for that matter, right here i used the first one.
I'd like to have this code constantly print the key is
instead of just printing the key is when i give a new input (when i press a key).
so the printed output would look something like this:
the key is
the key is
the key is
the key is
the key is
the key is
77
the key is
the key is
the key is
which is needed if you want to make something like snake, where you don't want your game to be paused everytime you want to getch, you don't want it to pause, waiting for an input.
Use msvcrt.kbhit to check whether key was pressed:
import sys, msvcrt
import time
print("Please press a key to see its value")
while 1:
print("the key is")
if msvcrt.kbhit(): # <--------
key = msvcrt.getch()
print(key)
if ord(key) == 27:
sys.exit()
time.sleep(0.1)
Another example to make Python program stop at a certain level, and wait for the user to press Enter "Yes" and/ or Space for "No" can be generated using pygame.
As an example I used Space for "No", but you could use the touche Escape for "No".
You might not need some imported librairies. Needed them while making tic toc toe game.
The code is below :
import numpy as np
import pygame as pg
from math import floor
import sys
import time
pg.init()
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 0, 255)
yellow = (255, 255, 0)
white = (255, 255, 255)
gris = (192, 192, 192)
cell = 100
thickness =2
window = pg.display.set_mode((300, 300))
pg.display.set_caption("by #djilytech")
for col in range(3):
for row in range(3):
pg.draw.rect(window, gris, (row * cell, col * cell, cell - 2, cell - 2), thickness)
pg.time.delay(120)
pg.display.update()
run = False
while not run:
for ev in pg.event.get():
if ev.type == pg.QUIT:
pg.quit()
sys.exit()
if ev.type == pg.KEYDOWN:
if ev.key == pg.K_RETURN:
print(" This mean the user wants to play again or said YES")
# So I can have some code here for what I want
if ev.key == pg.K_SPACE:
print("User does not want to continue")
# Will exit the program
run = True
I am attempting to make menu system using the curses module. I have the following code:
import sys, os, traceback, curses
def main(scrn):
screen = scrn
screen.border(0)
curses.start_color()
curses.init_pair(2,curses.COLOR_WHITE,curses.COLOR_BLUE)
while True:
event = screen.getch()
if event == ord("q"):
break
elif event == curses.KEY_RIGHT:
#enter function containing while loop, passing job
job_sub()
#loop to hand the subscreen for a job element
def job_sub():
screen = curses.newwin(5, 10, 3, 3)
screen.box()
objects =["RUN", "MAINTAIN", "EDIT"]
for i in range( len(objects) ):
if i == 0:
screen.addstr(i+1,1, objects[i], curses.color_pair(2))
else:
screen.addstr(i+1,1, objects[i])
screen.refresh()
while True:
event = screen.getch()
if event == curses.KEY_LEFT:
break
screen.erase()
return
if __name__=='__main__':
try:
# Initialize curses
screen=curses.initscr()
curses.noecho()
curses.cbreak()
screen.keypad(1)
main(screen)
screen.keypad(0)
curses.echo()
curses.nocbreak()
curses.endwin()
except:
# In event of error, restore terminal to sane state.
screen.keypad(0)
curses.echo()
curses.nocbreak()
curses.endwin()
traceback.print_exc()
The program runs until I hit the right arrow key. After that, it freezes, like it's stuck in a loop. It won't respond to any more input. Any help is appreciated.
In your job_sub() function you create a new window but you don't enable the keypad for it. As a result the arrow key is not sending a curses.KEY_LEFT value.