I would like to exit the ipython shell, i.e. type %exit then hit enter, when the escape key is pressed. I can successfully type "%escape" in the shell, but am having difficulty figuring out the "enter" press.
ref: https://ipython.readthedocs.io/en/latest/config/details.html#keyboard-shortcuts
Code in a .py file in the startup folder:
from prompt_toolkit.key_binding import KeyBindings
from IPython import get_ipython
ip = get_ipython()
def exit_ipy(event):
buffer = event.current_buffer
buffer.insert_text('%exit') # just need to figure out how to insert an "enter" press after
buffer.accept_action.validate_and_handle(event.cli, buffer) # I thoght this may work?
ip = get_ipython()
registry = ip.pt_app.key_bindings
registry.add_binding(u'escape')(exit_ipy)
This should do the trick :
import pyautogui
from prompt_toolkit.key_binding import KeyBindings
from IPython import get_ipython
ip = get_ipython()
def exit_ipy(event):
buffer = event.current_buffer
buffer.insert_text('%exit')
pyautogui.press('enter') # simulates an enter press
ip = get_ipython()
registry = ip.pt_app.key_bindings
registry.add_binding(u'escape')(exit_ipy)
pyautogui let you simulate a key press exactly like if you did it yourself, so I think that this solution will work
PS: I CAN NOT TEST THIS SO I DID NOT
Related
I am trying to find a way to simulate/automate mouse motion using the Wayland protocol on a debian based OS as did using Xlib in X11/X Window System giving the x and y coordinates:
from Xlib.display import Display
from Xlib.ext.xtest import fake_input
from Xlib import X
import os
#Go to x and y coordinates and click with left button (1):
x = 26
y = 665
button = 1
myDisplay = Display(os.environ['DISPLAY'])
fake_input(myDisplay, X.MotionNotify, x=x, y=y)
myDisplay.sync()
fake_input(myDisplay, X.ButtonPress, button)
myDisplay.sync()
fake_input(myDisplay, X.ButtonRelease, button)
myDisplay.sync()
and with pynput:
from pynput.mouse import Button, Controller
mouse = Controller()
mouse.position = (26,665)
mouse.click(Button.left)
I have tried with uinput to reproduce the same idea from the scripts presented above, the code doesn't give error but nothing happens when the script is executed:
sudo modprobe uinput && sudo python3 uinputtest.py
import uinput
# Create new mouse device
device = uinput.Device([
uinput.BTN_LEFT,
uinput.BTN_RIGHT,
uinput.REL_X,
uinput.REL_Y,
])
# Move the pointer to x = 26 and y = 665
device.emit(uinput.REL_X, 26)
device.emit(uinput.REL_Y, 665)
# Click and release the left mouse button
device.emit(uinput.BTN_LEFT, 1)
device.emit(uinput.BTN_LEFT, 0)
Is there anything missing on this last script? I am trying to execute it on Wayland with super user permission.
You should wait a bit before emitting any event.
In uinput example code it says:
We are inserting a pause here so that userspace has time
to detect, initialize the new device, and can start listening to
the event, otherwise it will not notice the event we are about
to send. This pause is only needed in our example code!
Putting a time.sleep(1) after the device intialization fixes the problem.
Ydotool, which provides a userspace application and daemon for what you are trying to achieve also waits for a second.
My project is to make a program that you can run while you are playing games or other programs in the background.
When you press a certain key, your notepad should open and also close after you press the same key again.
I have managed to open notepad with subprocess and that works fine but I have no idea to make it open only when a certain key is pressed.
Thanks for any help!
EDIT:
What I tried already:
import subprocess
import keyboard
if keyboard.is_pressed('k'):
subprocess.Popen('C:\\Windows\\System32\\notepad.exe')
input()
here it just doesn't detect any keyboard input, the input() at the end makes the program not close instantly
import subprocess
import keyboard
keyboard.add_hotkey('ctrl+k', print,args=("hello", "test"))
input()
Here if I press "ctrl+k it" will print hello test that means the hotkey works fine. When I switch this part "print,args=("hello", "test")" to "subprocess.Popen('C:\Windows\System32\notepad.exe')"(it should open the program instead of printing hello test) the notepad opens instantly after I run the program and when I press "ctrl+k" I get a big error.
A more complex, but still working example could be the following. With this code your program will be always listening the keyboard, not only when you are focused on the input, so may be mre practical in your case
from pynput import keyboard
import subprocess
import threading
class MyException(Exception): pass
class Listening:
"""Is allways waiting for the keyboard input"""
def __init__(self):
self.notepad_open = False # to know the state
with keyboard.Listener(
on_press=self.on_press) as listener:
try:
listener.join()
except:
pass
def on_press(self, key):
try:
if key.char == "k":
if not self.notepad_open:
self.subprocess = \
subprocess.Popen('C:\\Windows\\System32\\notepad.exe')
self.notepad_open = True # update state
else:
self.subprocess.kill()
self.notepad_open = False # update state
except: # special key was pressed
pass
thread = threading.Thread(target=lambda: Listening())
thread.start()
The problem is that you check for the key 'k' only once at the beginning. If you want the program to correctly work then you should try this:
import time
import subprocess
import keyboard
while True:
if keyboard.is_pressed('k'):
subprocess.Popen('C:\\Windows\\System32\\notepad.exe')
time.sleep(5)
-I used the time so that you can only open the program once 5 seconds(If you're curious, see what happens without it)-
i am currently trying to write a short script that will rickroll (open a youtube link) while the user is watching and can't interfere.
I have managed to open insert the link slowly letter by letter and am now trying to block user inputs.
I have tried using the ctypes import to block all inputs, run the script and then unblock again, but it somehow won't block the input. I'm just receiving my RuntimeError message.
How do i fix it, so the inputs get blocked?
Thanks in advance!
Heres the code:
import subprocess
import pyautogui
import time
import ctypes
from ctypes import wintypes
BlockInput = ctypes.windll.user32.BlockInput
BlockInput.argtypes = [wintypes.BOOL]
BlockInput.restype = wintypes.BOOL
blocked = BlockInput(True)
if blocked:
try:
subprocess.Popen(["C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",])
time.sleep(3)
pyautogui.write('www.youtube.com/watch?v=DLzxrzFCyOs', interval= 0.5)
pyautogui.hotkey('enter')
finally:
unblocked = BlockInput(False)
else:
raise RuntimeError('Input is already blocked by another thread')
You can use the keyboard module to block all keyboard inputs and the mouse module to constantly move the mouse, preventing the user from moving it.
See these links for more details:
https://github.com/boppreh/keyboard
https://github.com/boppreh/mouse
This blocks all the keys on the keyboard (the 150 is large enough to ensure all keys are blocked).
#### Blocking Keyboard ####
import keyboard
#blocks all keys of keyboard
for i in range(150):
keyboard.block_key(i)
This effectively blocks mouse-movement by constantly moving the mouse to position (1,0).
#### Blocking Mouse-movement ####
import threading
import mouse
import time
global executing
executing = True
def move_mouse():
#until executing is False, move mouse to (1,0)
global executing
while executing:
mouse.move(1,0, absolute=True, duration=0)
def stop_infinite_mouse_control():
#stops infinite control of mouse after 10 seconds if program fails to execute
global executing
time.sleep(10)
executing = False
threading.Thread(target=move_mouse).start()
threading.Thread(target=stop_infinite_mouse_control).start()
#^failsafe^
And then your original code here (the if statement and try/catch block are no longer necessary).
#### opening the video ####
import subprocess
import pyautogui
import time
subprocess.Popen(["C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",])
time.sleep(3)
pyautogui.write('www.youtube.com/watch?v=DLzxrzFCyOs', interval = 0.5)
pyautogui.hotkey('enter')
#### stops moving mouse to (1,0) after video has been opened
executing = False
Just a few notes:
The mouse-moving is hard to stop from outside of the program (it's basically impossible to close the program when it is executing, especially as the keyboard is also being blocked), that's why I put in the failsafe, which stops moving the mouse to (1,0) after 10 seconds.
(On Windows) Control-Alt-Delete does allow Task Manager to be opened and then the program can be force-stopped from there.
This doesn't stop the user from clicking the mouse, which can sometimes prevent the YouTube link from being typed in full (i.e. a new tab can be opened)
See a full version of the code here:
https://pastebin.com/WUygDqbG
you could do something like this to block both keyboard and mouse input
from ctypes import windll
from time import sleep
windll.user32.BlockInput(True) #this will block the keyboard input
sleep(15) #input will be blocked for 15 seconds
windll.user32.BlockInput(False) #now the keyboard will be unblocked
Here's a function for blocking keyboard and mouse input. You can pass a number to the blockMouseAndKeys function to adjust the timeout period:
import os
import time
import pyautogui
from threading import Thread
from keyboard import block_key
def blockMouseAndKeys(timeout=5):
global blocking
blockStartTime = time.time()
pyautogui.FAILSAFE = False
blocking = True
try: float(timeout)
except: timeout = 5
def blockKeys(timeout):
global blocking
while blocking:
if timeout:
if time.time()-blockStartTime > timeout:
print(f'Keyboard block timed out after {timeout}s.')
return
for i in range(150):
try: block_key(i)
except: pass
def blockMouse(timeout):
global blocking
while blocking:
def resetMouse(): pyautogui.moveTo(5,5)
Thread(target=resetMouse).start()
if timeout:
if time.time()-blockStartTime > timeout:
print(f'Mouse block timed out after {timeout}s.')
return
def blockTimeout(timeout):
global blocking
time.sleep(timeout)
blocking = False
pyautogui.FAILSAFE = False
print('Done blocking inputs!')
print('Blocking inputs...')
Thread(target=blockKeys, args=[timeout]).start()
Thread(target=blockMouse, args=[timeout]).start()
Thread(target=blockTimeout, args=[timeout]).start()
blockMouseAndKeys(timeout=10)
os.startfile('https://www.youtube.com/watch?v=DLzxrzFCyOs')
I have a script in python that execute a batch program that need press two or three times the "d" key and after the "q" key.
I tried this but without solution:
import os
import keyboard
import time
from pynput.keyboard import Key, Controller
os.system('"C:/Users/xxx/Documents/Software/xxx.exe 192.168.0.15"')
time.sleep(5)
keyboard = Controller()
keyd = "d"
keyq = "q"
keyboard.press(keyd)
keyboard.release(keyd)
time.sleep(3)
keyboard.press(keyq)
keyboard.release(keyq)
Only open the console but the script don't press the keys, but if you press with the keyboard the program works fine.
You could try to use the subprocess module.
Example:
subprocess-test.py
import subprocess
p = subprocess.Popen(["python", "input-app.py"], stdin=subprocess.PIPE)
p.stdin.write("Hello\n".encode(encoding='UTF-8'))
p.stdin.write("World\n".encode(encoding='UTF-8'))
input-app.py
input1 = input("Input 1: ")
input2 = input("Input 2: ")
print(input1, input2)
See more information here:
https://docs.python.org/3/library/subprocess.html
https://stackoverflow.com/a/3684694/42659
Sorry, I won't be able to help more as I only have a short lunch break. I hope this already does help though or points you in the right direction!
You can use: pyautogui for pressing code as simply as:
import pyautogui
pyautogui.press('d')
Your case can be handled as follows:
import os
import pyautogui
import time
os.system('"C:/Users/xxx/Documents/Software/xxx.exe 192.168.0.15"')
time.sleep(5)
keyd = "d"
keyq = "q"
pyautogui.press(keyd)
time.sleep(3)
pyautogui.press(keyq)
If pressing keys don't work, you may try to enter exact strings as well:
import os
import pyautogui
import time
os.system('"C:/Users/xxx/Documents/Software/xxx.exe 192.168.0.15"')
time.sleep(5)
keyd = "d"
keyq = "q"
pyautogui.write(keyd)
time.sleep(3)
pyautogui.write(keyq)
I am using python 2.7 on win7 64 bits. Here is a code, which just replaces every selected text by <h1>text</h1>. pynput-1.6.8 is used for global hotkey and keypress, while pyperclip-1.7.0 is used to handle clipboard.
But I found that in fact, CTRL+C is not pressed at all.
What is the problem? Thanks
from pynput.keyboard import Key, Controller, GlobalHotKeys
import pyperclip
# initilize the clipboard to null
pyperclip.copy('')
keyboard = Controller()
def on_activate_h():
print('<ctrl>+<alt>+h pressed')
# copy current text to clipboard
# but in fact, it does not on my PC
# why
keyboard.press(Key.ctrl)
keyboard.press('c')
keyboard.release('c')
keyboard.release(Key.ctrl)
txt = pyperclip.paste()
if txt:
keyboard.type(f'<h1>{txt}</h1>')
def on_activate_i():
print('<ctrl>+<alt>+i pressed')
with GlobalHotKeys({
'<ctrl>+<alt>+h': on_activate_h,
'<ctrl>+<alt>+i': on_activate_i}) as h:
h.join()
If anybody is still running into this:
The copy doesn't work because the Alt key is still pressed from your global hotkey.
You can simply release the Alt key before triggering Ctrl+C:
keyboard.release(Key.alt)
keyboard.press(Key.ctrl)
keyboard.press('c')
keyboard.release('c')
keyboard.release(Key.ctrl)
This workaround is not required on Linux or macOS.