Currently I am working on a keylogger as final project for my Python course. My idea is that when a user presses the return/enter button the time appears next to the previous typed text. Additionally, I would also like to stop the running when ESC is pressed. This is what I exactly mean:
www.gmail.com 02:20:50
www.google.com 02:21:42
stackoverflow 02:21:44
My code so far is something like this:
import sys, termios, tty, os
from datetime import datetime
def getch():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd , termios.TCSADRAIN , old_settings)
return ch
file=open('register.txt','a')
while True:
char = getch()
if (char != "q"):
file.write(char)
if (char == "\n"):
file.write('\t'+datetime.now().strftime('%H:%M:%S'))
else:
print("Quit!")
exit(0)
file.close()
The problems here are although everything is successfully written in the file register.txt the time doesn't show up, and also I do not have any idea how to specify the character ESC to exit the program
Thanks in advance!
Related
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
I have a very weird print() bug while using Threads and Termios. I have a repeating Thread catching a key via Termios while printing some stuff. But always it prints a new line it doesn't start at the beginning of the line but where the last line ended.
This is my code:
def func1():
while True:
try:
var = int(inputChar())
except ValueError:
var = 0
Thread(target=func1).start()
while True:
print("stuff")
time.sleep(2)
This is my inputChar() function:
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
This ist the expected output:
stuff
stuff
stuff
stuff
stuff
This is the output:
stuff
stuff
stuff
stuff
stuff
I have no idea why this is happening but you can fix it by replacing the print command with
print("stuff\r")
or
sys.stdout.write("stuff\n\r")
the \r at the end is known as a cartridge return. It's useful when sys.stdout.write() is not a viable option
I have written the program below which is intended to act as the terminal UI for a chat I am about to build for a university project. At its present state, the aim is to always have the last line act as the area to write a message, and when enter is pressed the message is written above and the last line becomes blank again.
That works fine if that's all I want. But, I also want to always have a number of "prompt symbols" at the start of the last line, namely here :>. To make that happen, when enter is pressed,the whole current line is deleted, the bare message is printed, a newline character inserted, and finally I wish to print the :> in the new line and repeat.
What happens, however, is that the prompt string is indeed printed, but the cursor, after the first enter pressed, begins at the start of the line, which means any subsequent input will overwrite the prompt characters. That does not happen the first time for some reason, where the first prompt is printed before anything else happens.
So in the end, I would like for a way for the cursor to actually start after the two prompt characters when a newline is printed. This is all I want as regards to functionality of the terminal, therefore I would like to find an easy way to solve this and be done with it instead of meddling with ncurses library and the likes. Thank you all for your time. The point of interest in the code where happens whatever I want to happen is inside the last while loop.
The code should be run with Python3.
import sys
from string import printable
import termios
import tty
class _Getch:
"""Gets a single character from standard input. Does not echo to the
screen."""
def __init__(self):
try:
self.impl = _GetchWindows()
except ImportError:
self.impl = _GetchUnix()
def __call__(self): return self.impl()
class _GetchUnix:
def __init__(self):
import tty, sys
def __call__(self):
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
# ch = sys.stdin.read(1)
ch = sys.stdin.read(1)[0]
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
class _GetchWindows:
def __init__(self):
import msvcrt
def __call__(self):
import msvcrt
return msvcrt.getch()
# enter: ord 13
#backspace: ord 127
current_input = ""
prompt_msg = ":> "
print(10*"\n"+prompt_msg,end="")
getch = _Getch()
def clear_input():
linelen = (len(current_input)+len(prompt_msg))
sys.stdout.write("\b"*linelen+" "*linelen+"\b"*linelen)
sys.stdout.flush()
while(True):
ch=getch()
if ord(ch)==3:# ctrl+c
exit()
# >>>>>>>.POINT OF INTEREST<<<<<<<<<<<
if ord(ch)==13:# enter
clear_input()
print(current_input)
current_input = ""
# print(prompt_msg,end="")
sys.stdout.write(prompt_msg)
sys.stdout.flush()
if ord(ch)==127 and len(current_input)>0:# backspace
sys.stdout.write("\b"+" "+"\b")
sys.stdout.flush()
current_input=current_input[:-1]
if ch in printable or ord(ch)>127: # printable
current_input+=ch
sys.stdout.write(ch)
sys.stdout.flush()
Rather than trying to get the pointer to go two places forward - which I had no luck finding an answer for - I simply deleted the carriage return character ("\r") from the current_input string in every place that should be done - there were rogue carriage return characters surviving in the string as it seems, that caused the problem.
I need to read the key pressed by user without waiting for enter.
I want to read both the characters and arrow keys.
The solution that I'm using is the same of this topic.
import sys,tty,termios
def getch():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(3)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
while(1):
k=getch()
if k=='\x1b[A':
print "up"
elif k=='\x1b[B':
print "down"
elif k=='\x1b[C':
print "right"
elif k=='\x1b[D':
print "left"
If I want to read arrow keys I use ch = sys.stdin.read(3), and if I want to read individual characters I use ch = sys.stdin.read(1), but I need to read both types of keys.
The rest of the script is written in Python 2.7 and will run on a Linux system.
Because I'm not the system admistrator, please
don't suggest installing a new package.
I have been trying to write a keyboard listener without installing any packages. What I wanted was to create a non-blocking way of reading only one character of user input. So I created another thread besides the main one. Here is my code:
import sys, os
import thread
import time
try:
from msvcrt import getch
except ImportError:
def getch():
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
char = None;
def key_listener():
global char;
while True:
char = getch()
# escape key to exit
if ord(char) == 27:
break
#print char #comment this line for test
thread.start_new_thread(key_listener, ())
while True:
print("Whatever")
time.sleep(1);
And the printed strings are a bit weird:
Yinans-MacBook-Pro:anaconda game Yinan$ python inputtest.py
Whatever
Whatever
Whatever
Whatever
Whatever
Whatever
See those indents? I never expected to have that. And I have been trying a whole afternoon to solve it but failed. Does anybody know how to solve this? I will be so grateful. (btw I'm using a macbook pro.)
Putting STDIN in raw mode put STDOUT in raw mode as well, so the normal \n is not expanded to a CRLF. You will need to print a \r at the end of your string in order to return the cursor to the first column.