Python move cursor two places forward - python

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.

Related

How to use _Getch?

I want to detect a keypress in my code to allow the running processes to advance only if a certain time has passed and the user has requested the code to advance (must be cross-platform).
The problem is I am using Windows (so I can use msvcrt) but people that will run my code may (and probably will) have Linux or MacOS and I found some code online by Danny Yoo (http://code.activestate.com/recipes/134892/) which is supposed to do what I want but I don't know how to use it properly. I'm not even sure how to import it into my code even though it's in the same directory.
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)
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()
getch = _Getch()
I tried calling import _Getch in my code and creating a variable getch = _Getch._Getch() but I don't feel this is doing what I want. What I want is to have this supposed cross-platform getch to detect if the user types 'n' for example and then continues to the next part of the process code.

Printing current time after pressing enter

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!

How can I create a Python script that runs in the background and reacts to keyboard input?

At the moment I'm using AutoHotKey for triggering scripts via keyboard shortcuts. I like programming in Python much more than dealing with AutoHotKey and every time I touch my AutoHotKey scripts I wish I could simply write clean AutoHotkey code.
Let's take the simply AutoHotKey script that prints hello world in whatever window I am when I press the insert key:
foo(){
send, "hello world"
}
Insert:: foo()
How would I do the same thing in Python3 on Windows?
You will have to hook into the gizzards of windows to achieve this. You'd probably have to do that via the ctypes or CFFI module, because the necessary API's don't seem to exist in pywin32.
According to this page, you will need to use three windows API calls:
SetWindowsHookEx, using the idHook WH_KEYBOARD_LL to set up a keyboard hook; a function that peeks at keyboard events.
UnhookWindowsHookEx to eventually remove the hook.
And if you're not interested in a particular keypress, CallNextHookEx to pass it on to the next hook.
You can combine two answers from StackOverflow to (almost) solve this issue.
Use this answer (by tehvan) to create a getch() like method to read in one character from the user without the need for a \n. (repeated below from the answer)
Use the Python3 version of this answer (by Barafu Albino) to call the previously defined _Getch() class in a separate process.
Please note that the following code works for Python3 only and uses any key to stop the process, not just the insert key.
# This code is a combination of two StackOverflow answers
# (links given in the answer)
# ------- Answer 1 by tehvan -----------------------------------
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)
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()
getch = _Getch()
# -------- Answer 2 by Barafu Albino (modified) -------
import _thread
def input_thread(a_list):
_Getch().__call__()
a_list.append(True)
def do_stuff():
a_list = []
_thread.start_new_thread(input_thread, (a_list,))
print('Press any key to stop.')
while not a_list:
pass
# This is where you can put the stuff
# you want to do until the key is pressed
print('Stopped.')
do_stuff()

unexpected indent outputs of print function with multithreads in python

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.

Python curses reading a single character from stdin affects output from print statement

I'm trying to do a non-blocking read of a single character from stdin. I have found a solution with the curses library, but I'm doing something wrong when trying to write output back to stdout.
import curses
from time import sleep
def callback(screen):
screen.nodelay(1)
return screen.getkey()
while 1:
try:
key = curses.wrapper(callback)
print "Got keypress: ", key
except:
sleep(3)
print "No Keypress"
print "Program\nOutput"
# Prints
No Keypress
Program
Output
Everything works flawlessly with the exception of the indented output. Is there any way to fix this?
It would appear that using curses, '\n' is just a form feed. You presumably need to output a carriage return as well, or else explicitly use curses to reposiition the cursor.
In the case proper curses window is started, only screen.addch('\n') worked for me (in which case, both the carriage return and the line feed are printed); I couldn't get print (or rather, sys.stdout.write) to "behave", even with specifying \r\n.
#!/usr/bin/python -tt
#youres to use
import curses
from time import sleep
def callback(screen):
screen.nodelay(1)
return screen.getkey()
def getkey():
try:
key = curses.wrapper(callback)
except:
key = None
return key
#tryer
while 1:
sleep(1)
k= getkey()
if k != None:
print "goo", k
else:
print "foo"

Categories