pexpect send cursor movement - python

How can you send cursor movements like the up,down,left,right keys with pexpect. The example below is to automate elinks which uses the up/down keys to select different links on a page.
from pexpect import spawn
child = spawn('elinks http://python.org')
#what goes here to send down key
child.interact()

The below script has the codes for all the four cursor movements, with an example of how one might use it in pexpect. To discover the exact string sequences for any typed in text you may use the get_keys.py script below.
KEY_UP = '\x1b[A'
KEY_DOWN = '\x1b[B'
KEY_RIGHT = '\x1b[C'
KEY_LEFT = '\x1b[D'
child.sendline(KEY_DOWN * 5) #send five key downs
get_keys.py
import curses
screen = curses.initscr()
screen.addstr("Press any set of keys then press enter\n")
keys = ''
while True:
event = screen.getkey()
if event == "\n":
break
keys += event
curses.endwin()
print repr(keys)

How about using escape sequence for up(^[[A) or down(^[[B) like this.
child.send("\033[A") # up
child.send("\033[B") # down

try this send '\033\117\102' for down key

Related

problem rising events with keyboard clicks in PySimpleGUI

I tried to find codes online about rising events in my PySimpleGUI program by simple keyboard clicks like ENTER or Ctrl+A for instance but I couldn't just find any about it, I went to the documentation of PySimpleGUI and didn't shut my tap without learning a thing.
Here is a simple code i wrote:
import PySimpleGUI as sg
layout = [[sg.I(key='In'), sg.B('Ok')],[sg.T(enable_events=True,key='T')]]
win=sg.Window("Keyboard Events", layout)
while True:
event, value= win.read()
#close event
if event == sg.WIN_CLOSED:
break
#greeting evnt
if event in ('Ok'): #( 'OK', 'KEYBOARD ENTER EVENT'):
msg = "Hello "+value['In'] # message to show user
win['T'].update(msg) # show user message
win['In'].update("") # clear input field after submitting
win.close()
What should I say to PySimpleGUI for let it run #greeting event when I press the ENTER key? Can someone help me please? Thanks guys!
Good question! And yes, its the documentation, not you. While this may not answer your question directly, here is some useful information.
You can choose to set return_keyboard_events=True as option when creating the window (sg.Window()). This will return every key hitting an input, as well as some scrolling events, meta keys, and so on.
window.read() returns a tuple (event, values). event can be:
None (sg.WIN_CLOSED)
A string of length one with the key from an input. For example 'a'.
The key of a control. For example, 'Ok'.
A tuple with more information. For example, clicking in a table gives a tuple of (keyname, "+CLICKED+", (row, column)
A special key, such as Return:6033979789 or Meta_L:922810622.
I use this as an alternative to bind_return_key when I might have multiple text entries on the screen:
if isinstance(event, str) and event.startswith('Return'):
event = 'return ' + self.window.find_element_with_focus().key
Also, I find printing to the console is necessary to debug events:
event, values = self.window.read()
print(f" event (type:{type(ui_event)}, {ui_event}, len:({len(ui_event)})"
f" with values {ui_values}")
Option required for element
sg.Input(do_not_clear=False, key='In') clear input field after event
sg.Button('Ok', bind_return_key=True) the return key will cause this button to be pressed
import PySimpleGUI as sg
layout = [[sg.I(do_not_clear=False, key='In'), sg.B('Ok', bind_return_key=True)],[sg.T(enable_events=True,key='T')]]
win=sg.Window("Keyboard Events", layout)
while True:
event, value= win.read()
#close event
if event == sg.WIN_CLOSED:
break
#greeting evnt
if event == 'Ok':
msg = "Hello "+value['In'] # message to show user
win['T'].update(msg) # show user message
win.close()

Is there any way to detect key press in Python?

I am wanting to make a program with different responses when you press a key. Is there any way that you can detect a key press in Python?
The program is like when you press 0, it will say you pressed 0 and when you pressed ctrl-c it will say that you interrupted the program, so on.
Can you do this in a while True: loop as well?
Also, I don't want it to be like input and I am using Linux (I don't want to have to use root).
Assuming you want a command line application
you should be able to do it with
import sys
import termios
import tty
custom_messages = {'a': 'some other message'}
custom_messages['b'] = 'what?';
stdin = sys.stdin.fileno()
tattr = termios.tcgetattr(stdin)
try:
tty.setcbreak(stdin, termios.TCSANOW)
while True:
char = sys.stdin.read(1)
print(custom_messages.get(char, 'You pressed ' + char))
except KeyboardInterrupt:
print('You interrupted')
sys.exit() ## ?
finally:
termios.tcsetattr(stdin, termios.TCSANOW, tattr)
I based my answer on disabling buffering in stdin

The controller.type method does not work correctly inside the onpress event - Pynput

I'm building a rudimentary autocomplete for my work, and it was doing fine, until I ran into this problem.
See example
import threading
from pynput import keyboard
from pynput.keyboard import Controller
controll = Controller()
def on_press(key):
if(key == keyboard.Key.alt_l):
controll.type("RIGHT !!!")
if(key == keyboard.Key.delete or key == keyboard.Key.enter):
return False
def handleKey():
x = input('INPUT> ')
print(x)
handle = threading.Thread(target=handleKey)
handle.start()
controll.type("RIGHT !!!")
with keyboard.Listener(
on_press=on_press) as listener:
listener.join()
When you press alt, you will see the output with the wrong string;
It must be [2] RIGHT !, but it was pressed [2]ight
But note that this only happens with the method call inside the event.
Is this a known issue? Am I using it wrong? I'm really confused
I believe that only with python3 and pip3 install pynput, this will make the example work
Tested with Windows 10
I've had a similar issue when trying to press a key while listening to a key. By my experience it is next to impossible. I have even tried to use other libraries' press functions such as pyautogui and keyboard inside of the pynput on_press function.
def on_press(key):
if key = keyboard.Key.esc:
return False
else:
if len(words) > i:
# p = keyboard.KeyCode.from_char(words[i])
pyautogui.press(word[i]) // also used keyboard.press(word[i])
i += 1
else:
keyboard.Controller.press(keyboard.Key.space)
with keyboard.Listener(on_press=on_press, suppress=True) as listener:
listener.join()
I feel like since the press action and the listen action are in different threads the program has to finish one before the other. At least that is what I gathered as I also have not found a solution to this. I also tried putting the press line after the listener.join() like this:
def on_press(key):
if key != keyboard.Key.esc:
return True
with keyboard.Listener(on_press=on_press, suppress=True) as listener:
listener.join()
if len(words) > i:
# p = keyboard.KeyCode.from_char(words[i])
pyautogui.press(words[i])
i += 1
else:
keyboard.Controller.press(keyboard.Key.space)
However, this did not solve the issue either because the program finished after listening to one input and then pressing words[i] once.
Please let me know if you find something. However I may not be able to comment bc of low reputation.
I had a similar issue as well, and something like this worked for me (on Ubuntu 20.04):
from pynput import keyboard
import threading
from time import sleep
event_queue = []
event_to_callback = {
# put your own key-to-function mapping here
# keyboard.KeyCode.from_char('c') : deal_with_c
}
def process_events():
while True:
for c in event_queue:
event_to_callback[c]()
event_queue.clear()
sleep(0.2)
keyboard.Listener(on_press=lambda k: event_queue.append(k)).start()
threading.Thread(target=process_events, args=()).start()
This decouples the listener's thread from the controller's thread; any callbacks that invoke pynput.keyboard.Controller methods will now be executed on a separate thread, different from the one of the listener.

detect key press in python, where each iteration can take more than a couple of seconds?

Edit: The below answer to use keyboard.on_press(callback, suppress=False) works fine in ubuntu without any issues.
But in Redhat/Amazon linux, it fails to work.
I have used the code snippet from this thread
import keyboard # using module keyboard
while True: # making a loop
try: # used try so that if user pressed other than the given key error will not be shown
if keyboard.is_pressed('q'): # if key 'q' is pressed
print('You Pressed A Key!')
break # finishing the loop
except:
break # if user pressed a key other than the given key the loop will break
But the above code requires the each iteration to be executed in nano-seconds. It fails in the below case:
import keyboard # using module keyboard
import time
while True: # making a loop
try: # used try so that if user pressed other than the given key error will not be shown
print("sleeping")
time.sleep(5)
print("slept")
if keyboard.is_pressed('q'): # if key 'q' is pressed
print('You Pressed A Key!')
break # finishing the loop
except:
print("#######")
break # if user pressed a key other than the given key the loop will break
You can make use of event handlers in keyboard module to achieve the desired result.
One such handler is keyboard.on_press(callback, suppress=False):
Which invokes a callback for every key_down event.
You can refer more at keyboard docs
Here is the code you can try:
import keyboard # using module keyboard
import time
stop = False
def onkeypress(event):
global stop
if event.name == 'q':
stop = True
# ---------> hook event handler
keyboard.on_press(onkeypress)
# --------->
while True: # making a loop
try: # used try so that if user pressed other than the given key error will not be shown
print("sleeping")
time.sleep(5)
print("slept")
if stop: # if key 'q' is pressed
print('You Pressed A Key!')
break # finishing the loop
except:
print("#######")
break # if user pressed a key other than the given key the loop will break
for people that might need this in the future, you can use keyboard.wait() which will basically wait untill the key gets pressed
keyboard.wait("o")
print("you pressed the letter o")
Do keep in mind that it blocks code execution after it. if you want to run code if the key is not being pressed i'd suggest doing
if keyboard.is_pressed("0"):
#do stuff
else:
#do other stuff
Edit: never mind, the other answer uses pretty much the same approach
This is what i could come up with, using the same "keyboard" module, see in-code comments below
import keyboard, time
from queue import Queue
# keyboard keypress callback
def on_keypress(e):
keys_queue.put(e.name)
# tell keyboard module to tell us about keypresses via callback
# this callback happens on a separate thread
keys_queue = Queue()
keyboard.on_press(on_keypress)
try:
# run the main loop until some key is in the queue
while keys_queue.empty():
print("sleeping")
time.sleep(5)
print("slept")
# check if its the right key
if keys_queue.get()!='q':
raise Exception("terminated by bad key")
# still here? good, this means we've been stoped by the right key
print("terminated by correct key")
except:
# well, you can
print("#######")
finally:
# stop receiving the callback at this point
keyboard.unhook_all()
You could use a thread
import threading
class KeyboardEvent(threading.Thread):
def run(self):
if keyboard.is_pressed('q'): # if key 'q' is pressed
print('You Pressed A Key!')
break # finishing the loop
keyread = KeyboardEvent()
keyread.start()
This would run in parallel to anything in the main thread and be dedicated to listening for that key press essentially.

Pyhook event.Injected?

Really more of a question here. Based on pyHook's tutorial, the .HookManager().OnMouseEvent event variable in the function has a .Injected attribute. I couldn't find any information about it, does anyone know what it is? I tried doing
event.Injected = '<char to inject>'
but it didn't work.
Disclaimer: I'm not expert of this stuff,
I'm just sharing my observations about the tutorial and the documentation,
in the hope that it will be helpful.
The attributes on event are not for you to set manually,
but for your event handlers to read and act upon.
As you can see in the documentation of KeyboardEvent and MouseEvent,
the purpose of the Injected instance variables is to check if the event was generated programmatically or not.
I think, this means events that your handlers receive from mouse and keyboard activity, will always have this variable False.
And there is a way to generate events programmatically,
I imagine for the purpose of testing your handlers.
And the method appear to be HookManager.KeyboardSwitch and HookManager.MouseSwitch.
Try this for example. Create a simple program to see the details of some real keyboard events:
import pythoncom, pyHook
def OnKeyboardEvent(event):
print 'MessageName:',event.MessageName
print 'Message:',event.Message
print 'Time:',event.Time
print 'Window:',event.Window
print 'WindowName:',event.WindowName
print 'Ascii:', event.Ascii, chr(event.Ascii)
print 'Key:', event.Key
print 'KeyID:', event.KeyID
print 'ScanCode:', event.ScanCode
print 'Extended:', event.Extended
print 'Injected:', event.Injected
print 'Alt', event.Alt
print 'Transition', event.Transition
print '---'
# return True to pass the event to other handlers
return True
# create a hook manager
hm = pyHook.HookManager()
# watch for key press events
hm.KeyDown = OnKeyboardEvent
# set the hook
hm.HookKeyboard()
# wait forever
pythoncom.PumpMessages()
Press a couple of keys and observe the outputs. Press Control-C to terminate the program.
Then, to generate some events programmatically and see what they look like,
try something like this:
import pythoncom, pyHook
def OnKeyboardEvent(event):
# ... same code as in previous sample ...
# create a hook manager
hm = pyHook.HookManager()
# watch for key press events
hm.KeyDown = OnKeyboardEvent
# set the hook
hm.HookKeyboard()
# send keyboard event programmatically
msg = ... # a value like in the "Message: ..." output in the previous run
vk_code = ... # a value like in the "KeyID: ..." output in the previous run
scan_code = ... # a value like in the "ScanCode: ..." output in the previous run
ascii = ... # a value like in the "Ascii: ..." output in the previous run
flags = 0x10 # see http://pyhook.sourceforge.net/doc_1.5.0/pyhook.HookManager-pysrc.html#KeyboardEvent.IsInjected
time = ... # a value like in the "Time: ..." output in the previous run
hwnd = ... # a value like in the "Window: ..." output in the previous run
win_name = ... # a value like in the "WindowName: ..." output in the previous run
hm.KeyboardSwitch(msg, vk_code, scan_code, ascii, flags, time, hwnd, win_name)
After you set appropriate values,
and run this program,
you should see "Injected: True" in the output.
I think this is the basic idea, and similarly for mouse events.
Unfortunately I'm not able to test this,
because it seems pyHook is a library for Windows OS, which I don't have.

Categories