python curses, how to use control, shift keys? - python

I am currently making a python project in curses, I want to know how to use the control and shift keys using stdscr.getch(), the other keys work, except for a few keys including ctrl and shift.
The code for the files look like this
# script_1.py
import curses
stdscr = curses.initscr()
curses.noecho()
curses.curs_set(False)
curses.start_color()
stdscr.keypad(True)
curses.mousemask(True)
# script_2.py
from script_1 import *
cmd = stdscr.getch()
if cmd == curses.KEY_CONTROL_L:
print("You pressed Left Control") # This code won't work
elif cmd == curses.KEY_SHIFT_L:
print("You pressed Left Shift") # This code won't work

Related

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

Python Blessed Library Missing Key Press Events

The blessed Python library looks great for making console apps, but I'm having trouble with the keyboard functionality. In the code below, only every second keypress is detected. Why is this please?
I'm on Windows 10 with Python 3.8.
from blessed import Terminal
term = Terminal()
print(f"{term.home}{term.black_on_skyblue}{term.clear}")
with term.cbreak(), term.hidden_cursor():
while term.inkey() != 'q':
inp = term.inkey()
if inp.name == "KEY_LEFT":
print("You pressed left")
Move term.inkey() outside your inner while loop instead so it listens for keys first:
from blessed import Terminal
term = Terminal()
print(f"{term.home}{term.black_on_skyblue}{term.clear}")
with term.cbreak(), term.hidden_cursor():
inp = term.inkey()
while term.inkey() != 'q':
if inp.name == "KEY_LEFT":
print("You pressed left")

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

How to use threads to get input from keyboard in python 3?

I am making a snake game which requires the player to press the WASD keys without stopping the game process to to get input from player. So I can't use input() for this situation because then the game stops ticking to get input.
I found a getch() function which immediately gives input without pressing enter, but this function also stops game ticking to get input like input(). I decided to use threading module to get input via getch() in different thread. The problem is that getch() isn't working while in different thread and I'm not sure why.
import threading, time
from msvcrt import getch
key = "lol" #it never changes because getch() in thread1 is useless
def thread1():
while True:
key = getch() #this simply is almost ignored by interpreter, the only thing it
#gives is that delays print() unless you press any key
print("this is thread1()")
threading.Thread(target = thread1).start()
while True:
time.sleep(1)
print(key)
So why getch() is useless when it is in thread1()?
The problem was that you're creating a local variable key inside thread1 instead of overwriting the existing one. The quick-and-easy solution would be to declare key to be global inside thread1.
Finally, you should consider using locks. I don't know if it's necessary or not, but I'd imagine weird things could happen if you try and write a value to key in the thread while printing it out at the same time.
The working code:
import threading, time
from msvcrt import getch
key = "lol"
def thread1():
global key
lock = threading.Lock()
while True:
with lock:
key = getch()
threading.Thread(target = thread1).start()
while True:
time.sleep(1)
print(key)
I tried using getch but it didn't work for me... (win7 here).
You can try using tkinter module // but I still can't make it running with threads
# Respond to a key without the need to press enter
import tkinter as tk #on python 2.x use "import Tkinter as tk"
def keypress(event):
if event.keysym == 'Escape':
root.destroy()
x = event.char
if x == "w":
print ("W pressed")
elif x == "a":
print ("A pressed")
elif x == "s":
print ("S pressed")
elif x == "d":
print ("D pressed")
else:
print (x)
root = tk.Tk()
print ("Press a key (Escape key to exit):")
root.bind_all('<Key>', keypress)
# don't show the tk window
root.withdraw()
root.mainloop()
As Michael0x2a says you may try using library made for game-making - pygame or pyglet.
#EDIT #Michael0x2a:
Are you sure your code works?
Whatever I press it always prints the same key.
#EDIT2:
Thanks!

Categories

Resources