Linux terminals vs Windows consoles - was Re: python 2.7.12 on Linux behaving differently than on Windows

Michael Torrie torriem at gmail.com
Thu Dec 8 11:35:42 EST 2016


On 12/08/2016 05:43 AM, BartC wrote:
> (Neither will see Shift+Ctrl+B, which means go to start of the file, 
> same as Ctrl+Home. Ubuntu sees Ctrl+Home, but not Debian, although it 
> will report Alt+Home. And some laptop keyboards already have Home on an 
> Alternate-Function shift! It's a mess.)

Yes terminal-emulators on Linux are very different than consoles on
Windows because of a ton of historical baggage.  Unlike a Windows
console, ttys on Unix are designed to connect to serial lines that are
essentially 2-way data pipes. Thus all keyboard handling has to be
wrapped up in escape codes that travel along with the screen data down
those pipes.

Now you may consider this an obsolete model.  But the abstraction is
still particularly useful in the linux world as I can connect my
terminal emulator to a variety of mechanisms including remote ssh
connections, plain old telnet, actual serial lines, etc.  You may not
find that useful, but like I've said in this thread, I use this
functionality every day.  In Windows I would instead use a dedicated
program like Putty to access these various communication streams and
interpret them.

The reason you are seeing such different codes is because there are
different schemes for terminals.  Back in the day we dealt with real
terminals.  A little CRT with a keyboard and a serial link.  The
terminal would interpret various codes coming in the serial link and do
things like move the cursor, underline, bold, inverse, etc.  Different
companies developed their own competing terminals that had some feature
they thought people would like.  So we had vt100, vt200, Sun, Dec, ANSI,
and other terminal types. Some terminals could even interpret escape
codes and draw vector graphics on the CRT.  Unix had to support them all
because people used all kinds of different terminals even in the same
environment.

Now we mostly just use one terminal type, "xterm."  But you can still
find variations as you've found. But if you have the correct TERM
environment variable set (it usually is), you can and should use a
terminal library to decode and encode your escape sequences.

> 
>>> Except that was only two Linuxes; perhaps on others, the keyboard will
>>> likely be crippled in some other way.
>>
>> No, they'll all be the same -- if it has an ASCII code,
>> you'll be able to get it from a tty device, otherwise you
>> won't.
>>
> 
>>> How people manage to do anything on such an OS I've no idea.

The best way to handle terminals is to use a terminal library that
understands many different terminal types (encodings).  For example,
instead of getting a raw keyboard ascii code that could vary from
terminal emulation to terminal emulation, use ncurses to process the
keystrokes and give you some kind of normalized sequence.

Alternatively pick one terminal type and require all your users to use
that type of terminal.

But just know that all terminal types share some limitations with
regards to the modifier keys.  Some you just can't get via the terminal
interface.

> How do they work; what magic do they use to get that key information, 
> and why can't it be done outside of a GUI? As I understand a Linux GUI 
> is built on top of Linux.

X windows came much later than terminals and they built a more robust
protocol that allows client programs to access full keyboard state
information.

Applications running on a terminal don't have this information solely
because there's never been a facility for encoding this information into
escape codes.  There's no other great technical reason for this
limitation.  It's entirely possible that we could create a new,
non-standard terminal type that supported the shift modifier.

> # Python 2 because of the 'print' handling
> 
> def getch():     # adapted from first getch I saw on the internet
>          import sys, tty, termios
>          fd = sys.stdin.fileno()
>          old_settings = termios.tcgetattr(fd)
>          tty.setraw(sys.stdin.fileno())
>          ch = sys.stdin.read(1)
>          termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
>          return ord(ch)
> 
> print "Press keys"
> print ("Hit Escape twice to quit")
> 
> escape=0
> while 1:
>      k=getch()
> 
>      if k==27:
>          print
>          print "Esc ",
>          if escape: break
>      elif k==13:
>          print "Enter"
>      elif k==10:
>          print "Newline"
>      elif k<=26:
>          print "Ctrl",chr(k+64)
>      else:
>          print chr(k),
> 
>      escape = k==27
> 
> ----------------------

Raw terminal handling is indeed crufty!  That's why I prefer to use
ncurses when I need anything more basic than standard in and standard out.

> (On another test, using a C-based getch(), pressing Enter returns code 
> 10 not 13; another difference to note. Either code appears to clash with 
> Ctrl-M or Ctrl-J, a difference from Windows where Ctrl-J, Ctrl-M and 
> Enter are distinct keys, as they are in actuality.)

Interesting.  I wouldn't have thought ENTER would return a line feed.
What is your TERM environment variable set to?  If you switch to a
text-mode virtual console, you'd probably find yet more variations.

Yes Control codes are, well control codes.  Any ascii value under 32.
They are more or less common across terminal types.  I don't know of any
way around that with terminals.

In any case, don't worry about raw values. Use a terminal handling
library to give you something sane to work with.


More information about the Python-list mailing list