I am writing a command-line notepad program and I want to detect keyboard press combinations, for example, Ctrl+S and Ctrl+D.
I have found many codes which work, but they all require me to download a module, like the keyboard module.
However, my parents have set restrictions such that I am not able to download any modules.
Could someone give me an alternative to the following code:
import keyboard as kb
while True:
if kb.is_pressed("ctrl+s"):
print("Ctrl+s is pressed!")
without having to download external modules?
Since you're on windows, you can use the built-in msvcrt module, i.e.:
import msvcrt
from time import sleep
while 1:
if msvcrt.kbhit():
key = msvcrt.getch()
# print(key) # uncomment to see which keys are being pressed.
if key == b"\x13":
print("CTRL+S")
sleep(0.05) # Added to reduce cpu load, 5% before, 0.01% after
Notes:
Run it on a console, not inside the IDE.
python3 myscript.py
I'm using PythonWin. If in the IDE I click Run, then any input() commands will pop up as a windows message box. But in the console they are printed console commands.
I tried using msvcrt.getch() in PythonWin, and it returns the character \xFF every time.
I would like to have my program use msvcrt.getch() if it's in the console, and input() if it's in PythonWin. So, how can my program tell which one it's running in?
You can check if you are in a regular shell (python.exe) or a custom one (IPython, PythonWin, DreamPie...) by using os.isatty:
import os
import sys
import io
try:
if os.isatty(sys.stdin.fileno()):
print "msvcrt.getch() will work."
else:
print "msvcrt.getch() will fail."
except (AttributeError, io.UnsupportedOperation):
print "msvcrt.getch() will fail."
I was able to figure out a solution by stepping into the source code of input() when running through PythonWin. I am posting here so that others who run across this issue will have a solution.
"pywin.framework.startup" in sys.modules is True when running in PythonWin, but False when running in the console.
So my code looks like this:
if "pywin.framework.startup" in sys.modules:
move = raw_input(promptstr)
else:
print(promptstr)
move = msvcrt.getch()
I'm trying to write a very simple program that will wait for x seconds before checking to see it a key has been pressed then, depending on this outcome will go into a different loop further down the code. I have this code:
import msvcrt
import time
import sys
time.sleep(1)
if msvcrt.kbhit():
sys.stdout.write('y')
else:
sys.stdout.write('n')
So I press any key when it first starts (making kbhit ==true) but it always just falls to the second statement and prints 'n'.
Any suggestions what I'm doing wrong?
{Using Python 2.7 and IDLE}
Thanks
The msvcrt.kbhit() function will only work if the program it is in has been run from the windows command line (or if a console window is opened for its input and output when you double click on its .py file).
If you run from IDLE or using the pythonw.exe interpreter, the program won't be connected to a console window and the console-IO commands from msvcrt won't work.
This happens if a prompt is written using sys.stdout.write or print instead of raw_input. The following script demonstrates it:
$ cat overwrite.py
import readline, sys
if 'libedit' in readline.__doc__:
readline.parse_and_bind('bind ^I rl_complete')
else:
readline.parse_and_bind('tab: complete')
def set_completer(choices):
choices = sorted(map(str,choices))
def completer(txt, state):
if state == 0:
completer.options = [c for c in choices if c.startswith(txt)]
if state < len(completer.options):
return completer.options[state]
return None
readline.set_completer(completer)
set_completer(['foo','flup'])
sys.stdout.write('input: ')
x = raw_input()
print x
If you run python overwrite.py, you get the expected prompt: "input: ". If you hit backspace once, nothing gets deleted (readline thinks it's already at the beginning of the line, I guess). If you hit 'f' then backspace, however, the whole line, prompt included, is wiped.
It would be very inconvenient to have to go through and replace all the places I write to stdout and am expecting to get input from the user with calls to raw_input, so I hope it's not necessary to use raw_input. The python docs are uncharacteristically sparse concerning readline.
There is no other real way to fix this; while readline has the rl_already_prompted variable, it still requires the prompt to be passed in so that readline's functions can manage the input line properly.
I am running command-line Python scripts from the Windows taskbar by having a shortcut pointing to the Python interpreter with the actual script as a parameter.
After the script has been processed, the interpreter terminates and the output window is closed which makes it impossible to read script output.
What is the most straightforward way to keep the interpreter window open until any key is pressed?
In batch files, one can end the script with pause. The closest thing to this I found in python is raw_input() which is sub-optimal because it requires pressing the return key (instead of any key).
One way is to leave a raw_input() at the end so the script waits for you to press Enter before it terminates.
Try os.system("pause") — I used it and it worked for me.
Make sure to include import os at the top of your script.
There's no need to wait for input before closing, just change your command like so:
cmd /K python <script>
The /K switch will execute the command that follows, but leave the command interpreter window open, in contrast to /C, which executes and then closes.
The best option: os.system('pause') <-- this will actually display a message saying 'press any key to continue' whereas adding just raw_input('') will print no message, just the cursor will be available.
not related to answer:
os.system("some cmd command") is a really great command as the command can execute any batch file/cmd commands.
One way is to leave a raw_input() at the end so the script waits for you to press enter before it terminates.
The advantage of using raw_input() instead of msvcrt.* stuff is that the former is a part of standard Python (i.e. absolutely cross-platform). This also means that the script window will be alive after double-clicking on the script file icon, without the need to do
cmd /K python <script>
On Windows you can use the msvcrt module.
msvcrt.kbhit()
Return True if a keypress is waiting to be read.
msvcrt.getch()
Read a keypress and return the resulting character as a byte string. Nothing is echoed to the console. This call will block if a keypress is not already available, but will not wait for Enter to be pressed. If the pressed key was a special function key, this will return '\000' or '\xe0'; the next call will return the keycode. The Control-C keypress cannot be read with this function.
If you want it to also work on Unix-like systems you can try this solution using the termios and fcntl modules.
As to the "problem" of what key to press to close it, I (and thousands of others, I'm sure) simply use input("Press Enter to close").
There's a simple way to do this, you can use keyboard module's wait function. For example, you can do:
import keyboard
print("things before the pause")
keyboard.wait("esc") # esc is just an example, you can obviously put every key you want
print("things after the pause")
Getting python to read a single character from the terminal in an unbuffered manner is a little bit tricky, but here's a recipe that'll do it:
Recipe 134892: getch()-like unbuffered character reading from stdin on both Windows and Unix (Python)
On Windows 10 insert at beggining this:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
Strange, but it works for me! (Together with input() at the end, of course)
An external WConio module can help here: http://newcenturycomputers.net/projects/wconio.html
import WConio
WConio.getch()
import pdb
pdb.debug()
This is used to debug the script. Should be useful to break also.
If you type
input("")
It will wait for them to press any button then it will continue. Also you can put text between the quotes.