pynput does not send ctrl+c to copy selected text - python

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.

Related

Python key changer program

I have got a keyboard with a non-working windows key.
I tried to fix it with Python if I press the > key, the program will press the windows key, but it's not working.
Here's the code:
import msvcrt
import pyautogui
while True:
if msvcrt.kbhit():
key_stroke = msvcrt.getch()
if key_stroke == b'>':
pyautogui.press('super')
print(key_stroke)
Can anyone help me? Thanks
To press ">" you need to press two keys "shift" + ".", when you release the "." key you registered ">" being a keystroke. but till that time you have not released the "shift" key.
In a nutshell when you execute pyautogui.press('super') in line 7, you are already pressing the "shift" key and then sending the "super" key command.
Solution to your problem is simple, release the "shift" key before sending the pyautogui.press('super') cmd.
The below code will resolve your problem.
Please install pynput package first (pip install pynput). Documentation for pynput
Solution - 1 (Modifying your code)
import msvcrt
import pyautogui
from pynput import keyboard
kb = keyboard.Controller()
while True:
if msvcrt.kbhit():
key_stroke = msvcrt.getch()
if key_stroke == b'>':
kb.release(keyboard.Key.shift)
pyautogui.press('super')
print(key_stroke)
Solution - 2 (This will give you more control over your keyboard events)
To exit from the shell press the "Esc" key.
from pynput import keyboard
kb = keyboard.Controller()
def on_press(key):
try:
print('alphanumeric key {0} pressed'.format(
key.char))
except AttributeError:
print('special key {0} pressed'.format(
key))
def on_release(key):
print('{0} released'.format(
key))
if hasattr(key, 'char') and key.char == ">":
kb.release(keyboard.Key.shift)
kb.press(keyboard.Key.cmd)
kb.release(keyboard.Key.cmd)
if key == keyboard.Key.esc:
# Stop listener
return False
# Collect events until released
with keyboard.Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
# ...or, in a non-blocking fashion:
listener = keyboard.Listener(
on_press=on_press,
on_release=on_release)
listener.start()
If you want to remap keys in python, the keyboard module is what you are looking for.
Please install keyboard package first (pip install keyboard). Documentation
The remap_hotkey function does exactly what you need.
keyboard.wait blocks the execution of the code until a key is pressed.
import keyboard
keyboard.remap_hotkey("Shift+.", "windows")
while True:
keyboard.wait()
Note that "Shift+." may change depending on your keyboard layout.

ipython shell - how to emulate an enter press

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

How to open a program using keyboard input?

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)-

Multimedia Keys in Python (Linux)

I want to detect when the XF86Launch1 key is pressed on my keyboard, using Python.
I have a headless server with a Bluetooth connected keyboard. I'd like to launch a command-line program whenever a specific multimedia key is pressed.
At the moment, I'm using:
import sys
import tty, termios
def getch():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
print getch()
But it won't detect multimedia keys. Nothing prints out when I press them.
Is there a way to detect these keys on a headless Ubuntu box - or a better way to launch a program on keypress?
Rather than trying to read stdin of the tty, you can use linux's input device api to read them.
On linux, all input devices show up as a file under /dev/input (such as /dev/input/event0) and when one read()s from these files, structured data indicating when keys are pressed and released is returned.
In C, the libevdev library provides a wrapper around those. In python, you could use the python-evdev library. It should also be possible to read directly from the input device (though you may need to carefully read the kernel documentation & source to handle that properly).
I think that your problem is that multimedia keys do not map to terminal input.
It's possible that you could make progress by running xev to trap the key and xmodmap to map the key to a different input.
Alternatively, use something like TKinter and see if a graphical program doesn't collect the keypresses.
from Tkinter import *
root = Tk()
def key(event):
print "pressed", repr(event.char)
def callback(event):
frame.focus_set()
frame = Frame(root, width=100, height=100)
frame.bind("<Key>", key)
frame.bind("<Button-1>", callback)
frame.pack()
root.mainloop()
Another possibility is to map to an F key instead of a multimedia key. (i.e. F9)
Edit: Further research into this resulted in these two links:
Extra Keyboard Keys
Extra Keyboard Keys in Console
The console itself does not support multimedia keys. But it does support custom F keys. F30-F246 are always free. Rather than map to XF86Launch1, map to F70. Then map F70 to keyboard input in your keymap, or use the Python script you already wrote to handle it.
pycopia may be an option. I am using it with this bluetooth button and it seems to work fairly well. I am still working on getting it to reconnect to the button when the button goes to sleep and then comes back. Here's part of the script that I'm using:
keyboard.py:
from pycopia.OS.Linux import Input
from pycopia.OS.Linux import event
class Satechi(Input.EventDevice):
DEVNAME = 'Satechi'
def register_callback(self, cb):
self._callback = cb
def poll(self):
while 1:
ev = self.read()
if ev.evtype == event.EV_KEY:
self._callback(ev)
read_handler = poll
button.py
from keyboard import Satechi
def callback(event):
pass #Do something fun
if __name__ == '__main__':
pm = Satechi()
pm.find()
pm.register_callback(callback)
while 1:
try:
pm.poll()
except OSError:
pm = Satechi()
while True:
try:
pm.find()
pm.register_callback(callback)
break
except IOError:
pass
pm.close()
Where DEVNAME is the devices name in /proc/bus/input/devices.
You can print event in the callback to figure out what the code and value is for the button you are looking for
Try to read xinput test <id> stdout in a loop and catch the events you need.
Here is some example in Bash:
#!/bin/bash
keyboard_id=9 # use xinput to find your keyboard id
xinput test $keyboard_id | while read line ; do
case $line in
"key press 44") echo -e "\n == j pressed ==" ;;
"key press 45") echo -e "\n == k pressed ==" ;;
esac
done

Python key pressed without Tk

I use a Raspberry Pi via SSH from my Windows 7 and I build a robot. If you press an arrow, it will move. I detect the key with TkInter module, but it needs a graphic environment. So if I am only in an SSH terminal, it can't run. Is there some module which can detect keys and doesn't need a window?
This is the exact use case sshkeyboard library. It does not require a graphic environment or window, and is simple to use: simply pip install sshkeyboard and:
from sshkeyboard import listen_keyboard
def press(key):
if key == "up":
print("up pressed")
elif key == "down":
print("down pressed")
elif key == "left":
print("left pressed")
elif key == "right":
print("right pressed")
listen_keyboard(on_press=press)
It will detect all arrows, print the detections to terminal.
You can also detect releasing keys with a on_release=... parameter which works the exact same way as on_press.
i have not tried it, but a quick search has shown up this:
example
github source
which is essentially a linux implementation of pyhook (windows only)
so to use it:
import pyxhook
import time
#This function is called every time a key is presssed
def kbevent( event ):
#print key info
print event
#If the ascii value matches spacebar, terminate the while loop
if event.Ascii == 32:
global running
running = False
#Create hookmanager
hookman = pyxhook.HookManager()
#Define our callback to fire when a key is pressed down
hookman.KeyDown = kbevent
#Hook the keyboard
hookman.HookKeyboard()
#Start our listener
hookman.start()
#Create a loop to keep the application running
running = True
while running:
time.sleep(0.1)
#Close the listener when we are done
hookman.cancel()

Categories

Resources