Python send control + Q then control + A (special keys)

Pressing Ctrl + key is actually a "user-friendly" way to enter ASCII control characters. This is done by subtracting 64 from the ASCII code of the entered key (taking the capital letter where applicable). The combination Ctrl + H, for example, is equivalent to entering a backspace (H has code 72, 72-64=8, the backspace character). This Wikipedia page lists the ASCII control characters associated with their key combinations, so Ctrl+A, Ctrl+Q is equivalent to sending the string "\x01\x11" through the paramiko Channel:

channel = client.invoke_shell()
channel.send('\x01\x11')

Update

To check what is actually transmitted when I press Ctrl+A Ctrl+Q I have devised a small test program:

# decode.py
import sys

while True:
    inp = sys.stdin.read(1)
    if len(inp) == 0:
        break
    print ord(inp[0])

If I now call this via ssh localhost python decode.py and enter Ctrl+A Ctrl+V Ctrl+Q (i have to do the Ctrl+V because Ctrl+Q is interpreted as XON by my local shell and not passed on to the other side), then Enter Ctrl+D to close the connection, i get 1, 17 and 10 as ordinals, or '\x01\x11\n', as expected.

I basically get the same by executing printf '\x01\x11\n' | ssh localhost python decode.py. If, however, I allocate a pty on the remote end via printf '\x01\x11\n' | ssh -tt localhost python decode.py the \x11 is intercepted by the remote pty and not passed on through to the running script (i get 1,10 as output). In this case it helps to send a Ctrl+V (\x16) before the Ctrl+Q that instructs the pty to pass the next character Verbatim. As expected printf '\x01\x16\x11\n' | ssh -tt localhost python decode.py outputs 1, 17 and 10.


This works perfectly for me, returning exactly what I would expect. There are obviously some pieces missing from your code above, so this required a little winging.

import sys
import time
import getpass
import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('127.0.0.1',
            username='apsuser',
            password=getpass.getpass('Password: '))
shell = ssh.invoke_shell()
shell.settimeout(0.25)

shell.send('picocom /dev/ttyS0\n')
time.sleep(2)
sys.stdout.buffer.write(shell.recv(10000))
sys.stdout.buffer.flush()

shell.send('\x01')
shell.send('\x11')

time.sleep(2)
sys.stdout.buffer.write(shell.recv(10000))
sys.stdout.buffer.flush()
print()
time.sleep(2)

And the results are:

Password: 

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Apr 14 19:55:57 2016 from 127.0.0.1
picocom /dev/ttyS0
apsuser@Steve-Laptop:~$ picocom /dev/ttyS0
picocom v1.7

port is        : /dev/ttyS0
flowcontrol    : none
baudrate is    : 9600
parity is      : none
databits are   : 8
escape is      : C-a
local echo is  : no
noinit is      : no
noreset is     : no
nolock is      : no
send_cmd is    : sz -vv
receive_cmd is : rz -vv
imap is        : 
omap is        : 
emap is        : crcrlf,delbs,

Terminal ready

Thanks for using picocom
apsuser@Steve-Laptop:~$ 

So what did I do that your code does not do?


Just as assumption: maybe pseudoterminal would help

import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(...)
channel = сlient.get_transport().open_session()
channel.get_pty()
channel.settimeout(5)
channel.exec_command('\x11\x01')