I'm using python 2.7 and code ssh client with paramiko library, I use myhost.channel.send(chr(keycode)) to send every keycode to server. But It only works with 1 byte keycodes. I want to send other multi-byte keycodes like arrow keys. How can I achieve this? Please help me.
A GUI like Windows or MacOS identifies keys with 'keycodes', but an SSH pipe just transfers bytes, not keycodes.
Assuming the program running inside ssh on your server is interactive (that is, it's expecting a human to be using it), you'll need to find out what kind of byte-patterns it's expecting to receive. When you open your channel, make sure you're calling .get_pty() and giving it a terminal parameter (the default, vt100, is pretty safe). Then, you'll need to read the documentation for the VT100 terminal to find out what byte sequences it sends when various keys are pressed. I recommend reading the Xterm Control Sequences documentation (Xterm is not strictly a vt100 emulator, but its documentation is very complete), and not confusingly mixed up with the hardware details of the original VT100 terminal). Note that in that document, "CSI" effectively means the Python string '\e['.
For example, the Xterm Control Sequences document says that the arrow keys are "CSI A" for up, "CSI B" for down, "CSI C" for right, and "CSI D" for left. In Python, that looks like:
up = '\e[A'
down = '\e[B'
right = '\e[C'
left = '\e[D'
In macOS 10.13.2 you can use:
class Keyboard:
up = '\x1b[A'
down = '\x1b[B'
right = '\x1b[C'
left = '\x1b[D'
(I read them from sys.stdin)
I think in python you can do the following:
channel.sendall(chr(0x1b)+"[B")
0x1B is the ASCII Escape character for VT100 terminal.
Related
I'm trying to port my Vim 8.0 configuration (~/.vimrc) to Python. That is, I'm setting Vim options as fields on vim.options mapping:
import vim
# set wildmenu
vim.options['wildmenu'] = True
# set wildcharm=<C-Z>
vim.options['wildcharm'] = ord('^Z') # [Literal ^Z (ASCII 26), CTRL-V CTRL-Z]
# set wildchar=<F10>
vim.options['wildchar'] = -15211 # extracted from Vim
The wildchar and wildcharm Vim options are of type "number". As far as I understand, they expect a kind of a keycode (at least in simple cases it is the ASCII code of the character in question).
In Vimscript, when you say something like set wildchar=<F10>, Vim translates the Vim-specific textual representation into a numeric keycode.
In Python, this is not the case (vim.options['wildchar'] = '<F10>' gives a TypeError).
For simple cases, it is possible to use ord() on a string containing the literally typed control character (see above with Ctrl-Z). However, a key like F10 produces multiple characters, so I can't use ord() on it.
In the end, I want to be able to do something like this:
vim.options['wildchar'] = magic('<F10>')
Does this magic() function exist?
Edit: I'm not asking how to invoke Vimscript code from Python (i. e. vim.command(...)). I understand that the encompassing problem can be trivially solved this way, but I'm asking a different question here.
:python vim.command("set wildchar=<F10>")
See the vim.command documentation for more explanation.
I am working with pythons pexpect module to automate tasks, I need help in figuring out key characters to use with sendcontrol. how could one send the controlkey ENTER ? and for future reference how can we find the key characters?
here is the code i am working on.
#!/usr/bin/env python
import pexpect
id = pexpect.spawn ('ftp 192.168.3.140')
id.expect_exact('Name')
id.sendline ('anonymous')
id.expect_exact ('Password')
*# Not sure how to send the enter control key
id.sendcontrol ('???')*
id.expect_exact ('ftp')
id.sendline ('dir')
id.expect_exact ('ftp')
lines = id.before.split ('\n')
for line in lines :
print line
pexpect has no sendcontrol() method. In your example you appear to be trying to send an empty line. To do that, use:
id.sendline('')
If you need to send real control characters then you can send() a string that contains the appropriate character value. For instance, to send a control-C you would:
id.send('\003')
or:
id.send(chr(3))
Responses to comment #2:
Sorry, I typo'ed the module name -- now fixed. More importantly, I was looking at old documentation on noah.org instead of the latest documentation at SourceForge. The newer documentation does show a sendcontrol() method. It takes an argument that is either a letter (for instance, sendcontrol('c') sends a control-C) or one of a variety of punctuation characters representing the control characters that don't correspond to letters. But really sendcontrol() is just a convenient wrapper around the send() method, which is what sendcontrol() calls after after it has calculated the actual value that you want to send. You can read the source for yourself at line 973 of this file.
I don't understand why id.sendline('') does not work, especially given that it apparently works for sending the user name to the spawned ftp program. If you want to try using sendcontrol() instead then that would be either:
id.sendcontrol('j')
to send a Linefeed character (which is control-j, or decimal 10) or:
id.sendcontrol('m')
to send a Carriage Return (which is control-m, or decimal 13).
If those don't work then please explain exactly what does happen, and how that differs from what you wanted or expected to happen.
If you're just looking to "press enter", you can send a newline:
id.send("\n")
As for other characters that you might want to use sendcontrol() with, I found this useful: https://condor.depaul.edu/sjost/lsp121/documents/ascii-npr.htm
For instance, I was interested in Ctrl+v. Looking it up in the table shows this line:
control character
python & java
decimal
description
^v
\x16
22
synchronous idle
So if I want to send that character, I can do any of these:
id.send('\x16')
id.send(chr(22))
id.sendcontrol('v')
sendcontrol() just looks up the correct character to send and then sends it like any other text
For keys not listed in that table, you can run this script: https://github.com/pexpect/pexpect/blob/master/tests/getch.py (ctrl space to exit)
For instance, ran that script and pressed F4 and it said:
27<STOP>
79<STOP>
83<STOP>
So then to press F4 via pexpect:
id.send(chr(27) + chr(79) + chr(83))
Some terminals will send ^? as backspace, some other terminals will send ^H.
Most of the terminals can be configured to change their behavior.
I do not want to deal with all the possible combinations but I would like to accept both ^? and ^H as a backspace from python.
doing this
os.system("stty erase '^?'")
I will accept the first option and with
os.system("stty erase '^H'")
I will accept the second one but the first will be no longer available.
I would like to use
raw_input("userinput>>")
to grab the input.
The only way I was able to figure out is implementing my own shell which works not on "raw based input" but on "char based input".
Any better (and quicker) idea?
The built-in function raw_input() (or input() in Python 3) will automatically use the readline library after importing it. This gives you a nice and full-feautured line editor, and it is probably your best bet on platforms where it is available, as long as you don't mind Readline having a contagious licence (GPL).
I don't know your question exactly. IMO, you need a method to read some line-based text(including some special character) from console to program.
No matter what method you use, if read this character have special mean in different console, you should confront a console(not only system-specific, but also console-specific) question, all text in console will be store in buffer first, and then show in screen, finally processed and send in to your program. Another way to surround this problem is to use a raw line-obtaining console environment.
You can add a special method(a decorator) to decorate the raw_input() or somewhat input method to process special word.
After solved that question
using this snippet can deal with input,:
def pre():
textline=raw_input()
# ^? should replace to the specific value.
textline.replace("^?","^H")
return textline
To be faster, maybe invoke some system function depend on OS is an idea. But in fact, IO in python is faster enough for common jobs.
To fix ^? on erase do stty erase ^H
i am using telnetlib in python...
i have used '\r' for enter key,'\t' for TAB.
as same as this scenario i want the char sequence for SHIFT,PAGE UP,PAGE DOWN,F1,F2...F12.
pleas help me regarding this issue as i have to use all this keyboard keys in my code.
import telnetlib
HOST = "localhost"
user = raw_input("Enter your remote account: ")
password = getpass.getpass()
tn = telnetlib.Telnet(HOST)
tn.write("ls\n")
tn.write("exit\n")
tn.write("\r") #this is for enter
tn.write("\t") # this is for tab
#what should be here to other keys..pls
print tn.read_all()
Unfortunately not all key-presses result in one or more bytes being sent over the wire. This is really about terminal emulation, since control keys are "meant" to be interpreted by the terminal device (or emulator).
Different terminal types define different keys and map them to different byte values in the stream. For example, some terminals have F11 and F12, and some don't. Some define Ctrl+F keys, Shift+F keys, Alt+F keys, Command+F keys; others don't. And different terminals map these keys to completely different byte sequences over the wire. The issue is the same when it comes to arrow keys and cursor-mode keys like insert.
You may find that certain keys are trapped by the client and not transmitted at all, or that non-keyboard events (such as resizing the terminal window with the mouse) transmit terminal escape sequences.
You can always go with thistelnet client : https://www.redhat.com/archives/redhat-list/2000-August/msg00070.html
I have to send F2 key to telnet host. How do I send it using python...using getch() I found that the character < used for the F2 key but when sending >, its not working. I think there is a way to send special function keys but I am not able to find it. If somebody knows please help me. Thanks in advance
Extended keys (non-alphanumeric or symbol) are composed of a sequence of single characters, with the sequence depending on the terminal you have told the telnet server you are using. You will need to send all characters in the sequence in order to make it work. Here, using od -c <<< 'CtrlVF2' I was able to see a sequence of \x1b0Q with the xterm terminal.
First, as Ignacio pointed out, you have to determine the exact sequence of characters sent by F2. On my machine, this happens to be ^[OQ, where ^[ denotes an escape character with ASCII code 27. This is identical to what he got. You have to send the exact same byte sequence over telnet. Assuming that the correct sequence is the one I have shown above, it boils down to this:
import telnetlib
tn = telnetlib.Telnet(HOST, PORT)
tn.write(idpass)
tn.write("\x1b0Q")
tn.close()
In case you are wondering, \x1b stands for a character having ASCII code 27, since 27 in hexadecimal is 1b.
This works on my machine (tested by a simple echo server on the receiving end), so if it does not work for you, it means that the remote end expects something else in place of an F2 keypress.