├── .gitignore ├── LICENSE ├── README ├── doc ├── ctlseqs(ms).html └── ctlseqs(ms)_files │ └── man2html.css ├── gui ├── __init__.py ├── font.py └── terminal.py ├── main.py ├── src ├── gui │ ├── __init__.py │ ├── font.py │ └── terminal.py ├── main.py └── terminal │ ├── __init__.py │ ├── ctrl.py │ ├── cursor.py │ ├── driver.py │ ├── emulator.py │ ├── esc.py │ ├── rendition.py │ └── screen.py ├── support └── gen-term-colors.py └── terminal ├── __init__.py ├── ctrl.py ├── cursor.py ├── emulator.py ├── esc.py ├── process.py ├── rendition.py └── screen.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | __pycache__ 3 | _PySide 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) The Regents of the University of California. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. Neither the name of the University nor the names of its contributors 13 | may be used to endorse or promote products derived from this software 14 | without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Simple attempt at terminal emulator in python and PySide (free QT library). 2 | It's very slow and more a proof of concept than anything as it shouldn't be 3 | used for anything serious. 4 | -------------------------------------------------------------------------------- /doc/ctlseqs(ms).html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ctlseqs(ms) 7 | 8 | 9 | 12 | 13 | 14 |

http://invisible-island.net/xterm/ 15 |


16 |

ctlseqs(ms)

17 |
  18 |                         XTerm Control Sequences
  19 | 
  20 |                                Edward Moy
  21 |                    University of California, Berkeley
  22 | 
  23 |                                Revised by
  24 | 
  25 |                              Stephen Gildea
  26 |                           X Consortium (1994)
  27 | 
  28 |                              Thomas Dickey
  29 |                       XFree86 Project (1996-2006)
  30 |                     invisible-island.net (2006-2016)
  31 |                updated for XTerm Patch #323 (2016/02/21)
  32 | 
  33 | 
34 |

Definitions

35 |
c    The literal character c.
  36 | 
  37 | C    A single (required) character.
  38 | 
  39 | Ps   A single (usually optional) numeric parameter, composed of one of
  40 |      more digits.
  41 | 
  42 | Pm   A multiple numeric parameter composed of any number of single
  43 |      numeric parameters, separated by ;  character(s).  Individual val-
  44 |      ues for the parameters are listed with Ps .
  45 | 
  46 | Pt   A text parameter composed of printable characters.
  47 | 
  48 | 
49 |

Control Bytes, Characters, and Sequences

50 |
ECMA-48 (aka "ISO 6429") documents C1 (8-bit) and C0 (7-bit) codes.
  51 | Those are respectively codes 128 to 159 and 0 to 31.  ECMA-48 avoids
  52 | referring to these codes as characters, because that term is associated
  53 | with graphic characters.  Instead, it uses "bytes" and "codes", with
  54 | occasional lapses to "characters" where the meaning cannot be mistaken.
  55 | 
  56 | Controls (including the escape code 27) are processed once:
  57 | 
  58 | o This means that a C1 control can be mistaken for badly-formed UTF-8
  59 |   when the terminal runs in UTF-8 mode because C1 controls are valid
  60 |   continuation bytes of a UTF-8 encoded (multibyte) value.
  61 | 
  62 | o It is not possible to use a C1 control obtained from decoding the
  63 |   UTF-8 text, because that would require reprocessing the data.  Conse-
  64 |   quently there is no ambiguity in the way this document uses the term
  65 |   "character" to refer to bytes in a control sequence.
  66 | 
  67 | The order of processing is a necessary consequence of the way ECMA-48 is
  68 | designed:
  69 | 
  70 | o Each byte sent to the terminal can be unambiguously determined to fall
  71 |   into one of a few categories (C0, C1 and graphic characters).
  72 | 
  73 | o ECMA-48 is modal; once it starts processing a control sequence, the
  74 |   terminal continues until the sequence is complete, or some byte is
  75 |   found which is not allowed in the sequence.
  76 | 
  77 | o Intermediate, parameter and final bytes may use the same codes as
  78 |   graphic characters, but they are processed as part of a control
  79 |   sequence and are not actually graphic characters.
  80 | 
  81 | o Eight-bit controls can have intermediate, etc., bytes in the range 160
  82 |   to 255.  Those can be treated as their counterparts in the range 32 to
  83 |   127.
  84 | 
  85 | o Single-byte controls can be handled separately from multi-byte control
  86 |   sequences because ECMA-48's rules are unambiguous.
  87 | 
  88 |   As a special case, ECMA-48 (section 9) mentions that the control func-
  89 |   tions shift-in and shift-out are allowed to occur within a 7-bit
  90 |   multibyte control sequence because those cannot alter the meaning of
  91 |   the control sequence.
  92 | 
  93 | o Some controls (such as OSC ) introduce a string mode, which is ended
  94 |   on a ST  (string terminator).
  95 | 
  96 |   Again, the terminal should accept single-byte controls within the
  97 |   string.  However, xterm has a resource setting brokenLinuxOSC to allow
  98 |   recovery from applications which rely upon malformed palette sequences
  99 |   used by the Linux console.
 100 | 
 101 | 
102 |

C1 (8-Bit) Control Characters

103 |
The xterm program recognizes both 8-bit and 7-bit control characters.
 104 | It generates 7-bit controls (by default) or 8-bit if S8C1T is enabled.
 105 | The following pairs of 7-bit and 8-bit control characters are equiva-
 106 | lent:
 107 | 
 108 | ESC D
 109 |      Index (IND  is 0x84).
 110 | ESC E
 111 |      Next Line (NEL  is 0x85).
 112 | ESC H
 113 |      Tab Set (HTS  is 0x88).
 114 | ESC M
 115 |      Reverse Index (RI  is 0x8d).
 116 | ESC N
 117 |      Single Shift Select of G2 Character Set (SS2  is 0x8e).  This
 118 |      affects next character only.
 119 | ESC O
 120 |      Single Shift Select of G3 Character Set (SS3  is 0x8f).  This
 121 |      affects next character only.
 122 | ESC P
 123 |      Device Control String (DCS  is 0x90).
 124 | ESC V
 125 |      Start of Guarded Area (SPA  is 0x96).
 126 | ESC W
 127 |      End of Guarded Area (EPA  is 0x97).
 128 | ESC X
 129 |      Start of String (SOS  is 0x98).
 130 | ESC Z
 131 |      Return Terminal ID (DECID is 0x9a).  Obsolete form of CSI c  (DA).
 132 | ESC [
 133 |      Control Sequence Introducer (CSI  is 0x9b).
 134 | ESC \
 135 |      String Terminator (ST  is 0x9c).
 136 | ESC ]
 137 |      Operating System Command (OSC  is 0x9d).
 138 | ESC ^
 139 |      Privacy Message (PM  is 0x9e).
 140 | ESC _
 141 |      Application Program Command (APC  is 0x9f).
 142 | 
 143 | These control characters are used in the vtXXX emulation.
 144 | 
 145 | 
146 |

VT100 Mode

147 |
Most of these control sequences are standard VT102 control sequences,
 148 | but there is support for later DEC VT terminals (i.e., VT220, VT320,
 149 | VT420, VT510), as well as ISO 6429 and aixterm color controls.  The only
 150 | VT102 feature not supported is auto-repeat, since the only way X pro-
 151 | vides for this will affect all windows.
 152 | There are additional control sequences to provide xterm-dependent func-
 153 | tions, such as the scrollbar or window size.  Where the function is
 154 | specified by DEC or ISO 6429, the code assigned to it is given in paren-
 155 | theses.
 156 | The escape codes to designate and invoke character sets are specified by
 157 | ISO 2022 (see that document for a discussion of character sets).
 158 | Many of the features are optional; xterm can be configured and built
 159 | without support for them.
 160 | 
 161 | 
162 |

Single-character functions

163 |
BEL       Bell (Ctrl-G).
 164 | BS        Backspace (Ctrl-H).
 165 | CR        Carriage Return (Ctrl-M).
 166 | ENQ       Return Terminal Status (Ctrl-E).  Default response is an empty
 167 |           string, but may be overridden by a resource answerbackString.
 168 | FF        Form Feed or New Page (NP).  Ctrl-L is treated the same as LF.
 169 | LF        Line Feed or New Line (NL).  (LF is Ctrl-J).
 170 | SI        Shift In (Ctrl-O) -> Switch to Standard Character Set.  This
 171 |           invokes the G0 character set (the default).
 172 | SO        Shift Out (Ctrl-N) -> Switch to Alternate Character Set.  This
 173 |           invokes the G1 character set.
 174 | SP        Space.
 175 | TAB       Horizontal Tab (HT) (Ctrl-I).
 176 | VT        Vertical Tab (Ctrl-K).  This is treated the same as LF.
 177 | 
 178 | 
179 |

Controls beginning with ESC

180 |
This excludes controls where ESC  is part of a 7-bit equivalent to 8-bit
 181 | C1 controls, ordered by the final character(s).
 182 | ESC SP F  7-bit controls (S7C1T).
 183 | ESC SP G  8-bit controls (S8C1T).
 184 | ESC SP L  Set ANSI conformance level 1 (dpANS X3.134.1).
 185 | ESC SP M  Set ANSI conformance level 2 (dpANS X3.134.1).
 186 | ESC SP N  Set ANSI conformance level 3 (dpANS X3.134.1).
 187 | ESC # 3   DEC double-height line, top half (DECDHL).
 188 | ESC # 4   DEC double-height line, bottom half (DECDHL).
 189 | ESC # 5   DEC single-width line (DECSWL).
 190 | ESC # 6   DEC double-width line (DECDWL).
 191 | ESC # 8   DEC Screen Alignment Test (DECALN).
 192 | ESC % @   Select default character set.  That is ISO 8859-1 (ISO 2022).
 193 | ESC % G   Select UTF-8 character set (ISO 2022).
 194 | ESC ( C   Designate G0 Character Set (ISO 2022, VT100).
 195 |           Final character C for designating 94-character sets.  In this
 196 |           list, 0 , A  and B  apply to VT100 and up, the remainder to
 197 |           VT220 and up.  The VT220 character sets, together with the
 198 |           Portuguese character set are activated by the National
 199 |           Replacement Character controls.  The A  is a special case,
 200 |           since it is also activated by the VT300-control for British
 201 |           Latin-1 separately from the National Replacement Character
 202 |           controls.
 203 |             C = 0  -> DEC Special Character and Line Drawing Set.
 204 |             C = <  -> DEC Supplementary (VT200).
 205 |             C = % 5  -> DEC Supplementary Graphics (VT300).
 206 |             C = >  -> DEC Technical (VT300).
 207 |             C = A  -> United Kingdom (UK).
 208 |             C = B  -> United States (USASCII).
 209 |             C = 4  -> Dutch.
 210 |             C = C  or 5  -> Finnish.
 211 |             C = R  or f  -> French.
 212 |             C = Q  or 9  -> French Canadian (VT200, VT300).
 213 |             C = K  -> German.
 214 |             C = Y  -> Italian.
 215 |             C = ` , E  or 6  -> Norwegian/Danish.
 216 |             C = % 6  -> Portuguese (VT300).
 217 |             C = Z  -> Spanish.
 218 |             C = H  or 7  -> Swedish.
 219 |             C = =  -> Swiss.
 220 | ESC ) C   Designate G1 Character Set (ISO 2022, VT100).
 221 |           The same character sets apply as for ESC ( C.
 222 | ESC * C   Designate G2 Character Set (ISO 2022, VT220).
 223 |           The same character sets apply as for ESC ( C.
 224 | ESC + C   Designate G3 Character Set (ISO 2022, VT220).
 225 |           The same character sets apply as for ESC ( C.
 226 | ESC - C   Designate G1 Character Set (VT300).
 227 |           The same character sets apply as for ESC ( C.
 228 | ESC . C   Designate G2 Character Set (VT300).
 229 |           The same character sets apply as for ESC ( C.
 230 | ESC / C   Designate G3 Character Set (VT300).
 231 |           These work for 96-character sets only.
 232 |             C = A  -> ISO Latin-1 Supplemental.
 233 | ESC 6     Back Index (DECBI), VT420 and up.
 234 | ESC 7     Save Cursor (DECSC).
 235 | ESC 8     Restore Cursor (DECRC).
 236 | ESC 9     Forward Index (DECFI), VT420 and up.
 237 | ESC =     Application Keypad (DECKPAM).
 238 | ESC >     Normal Keypad (DECKPNM).
 239 | ESC F     Cursor to lower left corner of screen.  This is enabled by the
 240 |           hpLowerleftBugCompat resource.
 241 | ESC c     Full Reset (RIS).
 242 | ESC l     Memory Lock (per HP terminals).  Locks memory above the cur-
 243 |           sor.
 244 | ESC m     Memory Unlock (per HP terminals).
 245 | ESC n     Invoke the G2 Character Set as GL (LS2).
 246 | ESC o     Invoke the G3 Character Set as GL (LS3).
 247 | ESC |     Invoke the G3 Character Set as GR (LS3R).
 248 | ESC }     Invoke the G2 Character Set as GR (LS2R).
 249 | ESC ~     Invoke the G1 Character Set as GR (LS1R).
 250 | 
 251 | 
252 |

Application Program-Control functions

253 |
APC Pt ST None.  xterm implements no APC  functions; Pt is ignored.  Pt
 254 |           need not be printable characters.
 255 | 
 256 | 
257 |

Device-Control functions

258 |
DCS Ps; Ps| Pt ST
 259 |           User-Defined Keys (DECUDK).  The first parameter:
 260 |             Ps = 0  -> Clear all UDK definitions before starting
 261 |           (default).
 262 |             Ps = 1  -> Erase Below (default).
 263 |           The second parameter:
 264 |             Ps = 0  <- Lock the keys (default).
 265 |             Ps = 1  <- Do not lock.
 266 |           The third parameter is a ';'-separated list of strings denot-
 267 |           ing the key-code separated by a '/' from the hex-encoded key
 268 |           value.  The key codes correspond to the DEC function-key codes
 269 |           (e.g., F6=17).
 270 | DCS $ q Pt ST
 271 |           Request Status String (DECRQSS).  The string following the "q"
 272 |           is one of the following:
 273 |             " q     -> DECSCA
 274 |             " p     -> DECSCL
 275 |             r       -> DECSTBM
 276 |             s       -> DECSLRM
 277 |             m       -> SGR
 278 |             SP q    -> DECSCUSR
 279 |           xterm responds with DCS 1 $ r Pt ST for valid requests,
 280 |           replacing the Pt with the corresponding CSI string, or DCS 0 $
 281 |           r Pt ST for invalid requests.
 282 | DCS + p Pt ST
 283 |           Set Termcap/Terminfo Data (xterm, experimental).  The string
 284 |           following the "p" is a name to use for retrieving data from
 285 |           the terminal database.  The data will be used for the "tcap"
 286 |           keyboard configuration's function- and special-keys, as well
 287 |           as by the Request Termcap/Terminfo String control.
 288 | DCS + q Pt ST
 289 |           Request Termcap/Terminfo String (xterm, experimental).  The
 290 |           string following the "q" is a list of names encoded in hexa-
 291 |           decimal (2 digits per character) separated by ; which corre-
 292 |           spond to termcap or terminfo key names.
 293 |           Two special features are also recognized, which are not key
 294 |           names: Co for termcap colors (or colors for terminfo colors),
 295 |           and TN for termcap name (or name for terminfo name).
 296 |           xterm responds with DCS 1 + r Pt ST for valid requests, adding
 297 |           to Pt an = , and the value of the corresponding string that
 298 |           xterm would send, or DCS 0 + r Pt ST for invalid requests.
 299 |           The strings are encoded in hexadecimal (2 digits per charac-
 300 |           ter).
 301 | 
 302 | 
303 |

Functions using CSI , ordered by the final character(s)

304 |
CSI Ps @  Insert Ps (Blank) Character(s) (default = 1) (ICH).
 305 | CSI Ps A  Cursor Up Ps Times (default = 1) (CUU).
 306 | CSI Ps B  Cursor Down Ps Times (default = 1) (CUD).
 307 | CSI Ps C  Cursor Forward Ps Times (default = 1) (CUF).
 308 | CSI Ps D  Cursor Backward Ps Times (default = 1) (CUB).
 309 | CSI Ps E  Cursor Next Line Ps Times (default = 1) (CNL).
 310 | CSI Ps F  Cursor Preceding Line Ps Times (default = 1) (CPL).
 311 | CSI Ps G  Cursor Character Absolute  [column] (default = [row,1]) (CHA).
 312 | CSI Ps ; Ps H
 313 |           Cursor Position [row;column] (default = [1,1]) (CUP).
 314 | CSI Ps I  Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
 315 | CSI Ps J  Erase in Display (ED).
 316 |             Ps = 0  -> Erase Below (default).
 317 |             Ps = 1  -> Erase Above.
 318 |             Ps = 2  -> Erase All.
 319 |             Ps = 3  -> Erase Saved Lines (xterm).
 320 | CSI ? Ps J
 321 |           Erase in Display (DECSED).
 322 |             Ps = 0  -> Selective Erase Below (default).
 323 |             Ps = 1  -> Selective Erase Above.
 324 |             Ps = 2  -> Selective Erase All.
 325 | CSI Ps K  Erase in Line (EL).
 326 |             Ps = 0  -> Erase to Right (default).
 327 |             Ps = 1  -> Erase to Left.
 328 |             Ps = 2  -> Erase All.
 329 | CSI ? Ps K
 330 |           Erase in Line (DECSEL).
 331 |             Ps = 0  -> Selective Erase to Right (default).
 332 |             Ps = 1  -> Selective Erase to Left.
 333 |             Ps = 2  -> Selective Erase All.
 334 | CSI Ps L  Insert Ps Line(s) (default = 1) (IL).
 335 | CSI Ps M  Delete Ps Line(s) (default = 1) (DL).
 336 | CSI Ps P  Delete Ps Character(s) (default = 1) (DCH).
 337 | CSI Ps S  Scroll up Ps lines (default = 1) (SU).
 338 | CSI ? Pi; Pa; Pv S
 339 |           If configured to support either Sixel Graphics or ReGIS Graph-
 340 |           ics, xterm accepts a three-parameter control sequence, where
 341 |           Pi, Pa and Pv are the item, action and value.
 342 |             Pi = 1  -> item (color registers)
 343 |             Pa = 1  -> read the number of color registers
 344 |             Pa = 2  -> reset the number of color registers
 345 |             Pa = 3  -> set the number of color registers to the value Pv
 346 |           The control sequence returns a response using the same form:
 347 | 
 348 |                CSI ? Pi; Ps; Pv S
 349 | 
 350 |           where Ps is the status:
 351 |             Ps = 0  -> success
 352 |             Ps = 3  -> failure
 353 | CSI Ps T  Scroll down Ps lines (default = 1) (SD).
 354 | CSI Ps ; Ps ; Ps ; Ps ; Ps T
 355 |           Initiate highlight mouse tracking.  Parameters are
 356 |           [func;startx;starty;firstrow;lastrow].  See the section Mouse
 357 |           Tracking.
 358 | CSI > Ps; Ps T
 359 |           Reset one or more features of the title modes to the default
 360 |           value.  Normally, "reset" disables the feature.  It is possi-
 361 |           ble to disable the ability to reset features by compiling a
 362 |           different default for the title modes into xterm.
 363 |             Ps = 0  -> Do not set window/icon labels using hexadecimal.
 364 |             Ps = 1  -> Do not query window/icon labels using hexadeci-
 365 |           mal.
 366 |             Ps = 2  -> Do not set window/icon labels using UTF-8.
 367 |             Ps = 3  -> Do not query window/icon labels using UTF-8.
 368 |           (See discussion of "Title Modes").
 369 | CSI Ps X  Erase Ps Character(s) (default = 1) (ECH).
 370 | CSI Ps Z  Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
 371 | CSI Pm `  Character Position Absolute  [column] (default = [row,1])
 372 |           (HPA).
 373 | CSI Pm a  Character Position Relative  [columns] (default = [row,col+1])
 374 |           (HPR).
 375 | CSI Ps b  Repeat the preceding graphic character Ps times (REP).
 376 | CSI Ps c  Send Device Attributes (Primary DA).
 377 |             Ps = 0  or omitted -> request attributes from terminal.  The
 378 |           response depends on the decTerminalID resource setting.
 379 |             -> CSI ? 1 ; 2 c  ("VT100 with Advanced Video Option")
 380 |             -> CSI ? 1 ; 0 c  ("VT101 with No Options")
 381 |             -> CSI ? 6 c  ("VT102")
 382 |             -> CSI ? 6 2 ; Psc  ("VT220")
 383 |             -> CSI ? 6 3 ; Psc  ("VT320")
 384 |             -> CSI ? 6 4 ; Psc  ("VT420")
 385 |           The VT100-style response parameters do not mean anything by
 386 |           themselves.  VT220 (and higher) parameters do, telling the
 387 |           host what features the terminal supports:
 388 |             Ps = 1  -> 132-columns.
 389 |             Ps = 2  -> Printer.
 390 |             Ps = 3  -> ReGIS graphics.
 391 |             Ps = 4  -> Sixel graphics.
 392 |             Ps = 6  -> Selective erase.
 393 |             Ps = 8  -> User-defined keys.
 394 |             Ps = 9  -> National Replacement Character sets.
 395 |             Ps = 1 5  -> Technical characters.
 396 |             Ps = 1 8  -> User windows.
 397 |             Ps = 2 1  -> Horizontal scrolling.
 398 |             Ps = 2 2  -> ANSI color, e.g., VT525.
 399 |             Ps = 2 9  -> ANSI text locator (i.e., DEC Locator mode).
 400 | CSI > Ps c
 401 |           Send Device Attributes (Secondary DA).
 402 |             Ps = 0  or omitted -> request the terminal's identification
 403 |           code.  The response depends on the decTerminalID resource set-
 404 |           ting.  It should apply only to VT220 and up, but xterm extends
 405 |           this to VT100.
 406 |             -> CSI  > Pp ; Pv ; Pc c
 407 |           where Pp denotes the terminal type
 408 |             Pp = 0  -> "VT100".
 409 |             Pp = 1  -> "VT220".
 410 |             Pp = 2  -> "VT240".
 411 |             Pp = 1 8 -> "VT330".
 412 |             Pp = 1 9 -> "VT340".
 413 |             Pp = 2 4 -> "VT320".
 414 |             Pp = 4 1 -> "VT420".
 415 |             Pp = 6 1 -> "VT510".
 416 |             Pp = 6 4 -> "VT520".
 417 |             Pp = 6 5 -> "VT525".
 418 |           and Pv is the firmware version (for xterm, this was originally
 419 |           the XFree86 patch number, starting with 95).  In a DEC termi-
 420 |           nal, Pc indicates the ROM cartridge registration number and is
 421 |           always zero.
 422 | CSI Pm d  Line Position Absolute  [row] (default = [1,column]) (VPA).
 423 | CSI Pm e  Line Position Relative  [rows] (default = [row+1,column])
 424 |           (VPR).
 425 | CSI Ps ; Ps f
 426 |           Horizontal and Vertical Position [row;column] (default =
 427 |           [1,1]) (HVP).
 428 | CSI Ps g  Tab Clear (TBC).
 429 |             Ps = 0  -> Clear Current Column (default).
 430 |             Ps = 3  -> Clear All.
 431 | CSI Pm h  Set Mode (SM).
 432 |             Ps = 2  -> Keyboard Action Mode (AM).
 433 |             Ps = 4  -> Insert Mode (IRM).
 434 |             Ps = 1 2  -> Send/receive (SRM).
 435 |             Ps = 2 0  -> Automatic Newline (LNM).
 436 | CSI ? Pm h
 437 |           DEC Private Mode Set (DECSET).
 438 |             Ps = 1  -> Application Cursor Keys (DECCKM).
 439 |             Ps = 2  -> Designate USASCII for character sets G0-G3
 440 |           (DECANM), and set VT100 mode.
 441 |             Ps = 3  -> 132 Column Mode (DECCOLM).
 442 |             Ps = 4  -> Smooth (Slow) Scroll (DECSCLM).
 443 |             Ps = 5  -> Reverse Video (DECSCNM).
 444 |             Ps = 6  -> Origin Mode (DECOM).
 445 |             Ps = 7  -> Wraparound Mode (DECAWM).
 446 |             Ps = 8  -> Auto-repeat Keys (DECARM).
 447 |             Ps = 9  -> Send Mouse X & Y on button press.  See the sec-
 448 |           tion Mouse Tracking.  This is the X10 xterm mouse protocol.
 449 |             Ps = 1 0  -> Show toolbar (rxvt).
 450 |             Ps = 1 2  -> Start Blinking Cursor (att610).
 451 |             Ps = 1 8  -> Print form feed (DECPFF).
 452 |             Ps = 1 9  -> Set print extent to full screen (DECPEX).
 453 |             Ps = 2 5  -> Show Cursor (DECTCEM).
 454 |             Ps = 3 0  -> Show scrollbar (rxvt).
 455 |             Ps = 3 5  -> Enable font-shifting functions (rxvt).
 456 |             Ps = 3 8  -> Enter Tektronix Mode (DECTEK).
 457 |             Ps = 4 0  -> Allow 80 -> 132 Mode.
 458 |             Ps = 4 1  -> more(1) fix (see curses resource).
 459 |             Ps = 4 2  -> Enable National Replacement Character sets
 460 |           (DECNRCM).
 461 |             Ps = 4 4  -> Turn On Margin Bell.
 462 |             Ps = 4 5  -> Reverse-wraparound Mode.
 463 |             Ps = 4 6  -> Start Logging.  This is normally disabled by a
 464 |           compile-time option.
 465 |             Ps = 4 7  -> Use Alternate Screen Buffer.  (This may be dis-
 466 |           abled by the titeInhibit resource).
 467 |             Ps = 6 6  -> Application keypad (DECNKM).
 468 |             Ps = 6 7  -> Backarrow key sends backspace (DECBKM).
 469 |             Ps = 6 9  -> Enable left and right margin mode (DECLRMM),
 470 |           VT420 and up.
 471 |             Ps = 9 5  -> Do not clear screen when DECCOLM is set/reset
 472 |           (DECNCSM), VT510 and up.
 473 |             Ps = 1 0 0 0  -> Send Mouse X & Y on button press and
 474 |           release.  See the section Mouse Tracking.  This is the X11
 475 |           xterm mouse protocol.
 476 |             Ps = 1 0 0 1  -> Use Hilite Mouse Tracking.
 477 |             Ps = 1 0 0 2  -> Use Cell Motion Mouse Tracking.
 478 |             Ps = 1 0 0 3  -> Use All Motion Mouse Tracking.
 479 |             Ps = 1 0 0 4  -> Send FocusIn/FocusOut events.
 480 |             Ps = 1 0 0 5  -> Enable UTF-8 Mouse Mode.
 481 |             Ps = 1 0 0 6  -> Enable SGR Mouse Mode.
 482 |             Ps = 1 0 0 7  -> Enable Alternate Scroll Mode.
 483 |             Ps = 1 0 1 0  -> Scroll to bottom on tty output (rxvt).
 484 |             Ps = 1 0 1 1  -> Scroll to bottom on key press (rxvt).
 485 |             Ps = 1 0 1 5  -> Enable urxvt Mouse Mode.
 486 |             Ps = 1 0 3 4  -> Interpret "meta" key, sets eighth bit.
 487 |           (enables the eightBitInput resource).
 488 |             Ps = 1 0 3 5  -> Enable special modifiers for Alt and Num-
 489 |           Lock keys.  (This enables the numLock resource).
 490 |             Ps = 1 0 3 6  -> Send ESC   when Meta modifies a key.  (This
 491 |           enables the metaSendsEscape resource).
 492 |             Ps = 1 0 3 7  -> Send DEL from the editing-keypad Delete
 493 |           key.
 494 |             Ps = 1 0 3 9  -> Send ESC  when Alt modifies a key.  (This
 495 |           enables the altSendsEscape resource).
 496 |             Ps = 1 0 4 0  -> Keep selection even if not highlighted.
 497 |           (This enables the keepSelection resource).
 498 |             Ps = 1 0 4 1  -> Use the CLIPBOARD selection.  (This enables
 499 |           the selectToClipboard resource).
 500 |             Ps = 1 0 4 2  -> Enable Urgency window manager hint when
 501 |           Control-G is received.  (This enables the bellIsUrgent
 502 |           resource).
 503 |             Ps = 1 0 4 3  -> Enable raising of the window when Control-G
 504 |           is received.  (enables the popOnBell resource).
 505 |             Ps = 1 0 4 4  -> Reuse the most recent data copied to CLIP-
 506 |           BOARD.  (This enables the keepClipboard resource).
 507 |             Ps = 1 0 4 7  -> Use Alternate Screen Buffer.  (This may be
 508 |           disabled by the titeInhibit resource).
 509 |             Ps = 1 0 4 8  -> Save cursor as in DECSC.  (This may be dis-
 510 |           abled by the titeInhibit resource).
 511 |             Ps = 1 0 4 9  -> Save cursor as in DECSC and use Alternate
 512 |           Screen Buffer, clearing it first.  (This may be disabled by
 513 |           the titeInhibit resource).  This combines the effects of the 1
 514 |           0 4 7  and 1 0 4 8  modes.  Use this with terminfo-based
 515 |           applications rather than the 4 7  mode.
 516 |             Ps = 1 0 5 0  -> Set terminfo/termcap function-key mode.
 517 |             Ps = 1 0 5 1  -> Set Sun function-key mode.
 518 |             Ps = 1 0 5 2  -> Set HP function-key mode.
 519 |             Ps = 1 0 5 3  -> Set SCO function-key mode.
 520 |             Ps = 1 0 6 0  -> Set legacy keyboard emulation (X11R6).
 521 |             Ps = 1 0 6 1  -> Set VT220 keyboard emulation.
 522 |             Ps = 2 0 0 4  -> Set bracketed paste mode.
 523 | CSI Pm i  Media Copy (MC).
 524 |             Ps = 0  -> Print screen (default).
 525 |             Ps = 4  -> Turn off printer controller mode.
 526 |             Ps = 5  -> Turn on printer controller mode.
 527 |             Ps = 1  0  -> HTML screen dump.
 528 |             Ps = 1  1  -> SVG screen dump.
 529 | CSI ? Pm i
 530 |           Media Copy (MC, DEC-specific).
 531 |             Ps = 1  -> Print line containing cursor.
 532 |             Ps = 4  -> Turn off autoprint mode.
 533 |             Ps = 5  -> Turn on autoprint mode.
 534 |             Ps = 1  0  -> Print composed display, ignores DECPEX.
 535 |             Ps = 1  1  -> Print all pages.
 536 | CSI Pm l  Reset Mode (RM).
 537 |             Ps = 2  -> Keyboard Action Mode (AM).
 538 |             Ps = 4  -> Replace Mode (IRM).
 539 |             Ps = 1 2  -> Send/receive (SRM).
 540 |             Ps = 2 0  -> Normal Linefeed (LNM).
 541 | CSI ? Pm l
 542 |           DEC Private Mode Reset (DECRST).
 543 |             Ps = 1  -> Normal Cursor Keys (DECCKM).
 544 |             Ps = 2  -> Designate VT52 mode (DECANM).
 545 |             Ps = 3  -> 80 Column Mode (DECCOLM).
 546 |             Ps = 4  -> Jump (Fast) Scroll (DECSCLM).
 547 |             Ps = 5  -> Normal Video (DECSCNM).
 548 |             Ps = 6  -> Normal Cursor Mode (DECOM).
 549 |             Ps = 7  -> No Wraparound Mode (DECAWM).
 550 |             Ps = 8  -> No Auto-repeat Keys (DECARM).
 551 |             Ps = 9  -> Don't send Mouse X & Y on button press.
 552 |             Ps = 1 0  -> Hide toolbar (rxvt).
 553 |             Ps = 1 2  -> Stop Blinking Cursor (att610).
 554 |             Ps = 1 8  -> Don't print form feed (DECPFF).
 555 |             Ps = 1 9  -> Limit print to scrolling region (DECPEX).
 556 |             Ps = 2 5  -> Hide Cursor (DECTCEM).
 557 |             Ps = 3 0  -> Don't show scrollbar (rxvt).
 558 |             Ps = 3 5  -> Disable font-shifting functions (rxvt).
 559 |             Ps = 4 0  -> Disallow 80 -> 132 Mode.
 560 |             Ps = 4 1  -> No more(1) fix (see curses resource).
 561 |             Ps = 4 2  -> Disable National Replacement Character sets
 562 |           (DECNRCM).
 563 |             Ps = 4 4  -> Turn Off Margin Bell.
 564 |             Ps = 4 5  -> No Reverse-wraparound Mode.
 565 |             Ps = 4 6  -> Stop Logging.  (This is normally disabled by a
 566 |           compile-time option).
 567 |             Ps = 4 7  -> Use Normal Screen Buffer.
 568 |             Ps = 6 6  -> Numeric keypad (DECNKM).
 569 |             Ps = 6 7  -> Backarrow key sends delete (DECBKM).
 570 |             Ps = 6 9  -> Disable left and right margin mode (DECLRMM),
 571 |           VT420 and up.
 572 |             Ps = 9 5  -> Clear screen when DECCOLM is set/reset (DEC-
 573 |           NCSM), VT510 and up.
 574 |             Ps = 1 0 0 0  -> Don't send Mouse X & Y on button press and
 575 |           release.  See the section Mouse Tracking.
 576 |             Ps = 1 0 0 1  -> Don't use Hilite Mouse Tracking.
 577 |             Ps = 1 0 0 2  -> Don't use Cell Motion Mouse Tracking.
 578 |             Ps = 1 0 0 3  -> Don't use All Motion Mouse Tracking.
 579 |             Ps = 1 0 0 4  -> Don't send FocusIn/FocusOut events.
 580 |             Ps = 1 0 0 5  -> Disable UTF-8 Mouse Mode.
 581 |             Ps = 1 0 0 6  -> Disable SGR Mouse Mode.
 582 |             Ps = 1 0 0 7  -> Disable Alternate Scroll Mode.
 583 |             Ps = 1 0 1 0  -> Don't scroll to bottom on tty output
 584 |           (rxvt).
 585 |             Ps = 1 0 1 1  -> Don't scroll to bottom on key press (rxvt).
 586 |             Ps = 1 0 1 5  -> Disable urxvt Mouse Mode.
 587 |             Ps = 1 0 3 4  -> Don't interpret "meta" key.  (This disables
 588 |           the eightBitInput resource).
 589 |             Ps = 1 0 3 5  -> Disable special modifiers for Alt and Num-
 590 |           Lock keys.  (This disables the numLock resource).
 591 |             Ps = 1 0 3 6  -> Don't send ESC  when Meta modifies a key.
 592 |           (This disables the metaSendsEscape resource).
 593 |             Ps = 1 0 3 7  -> Send VT220 Remove from the editing-keypad
 594 |           Delete key.
 595 |             Ps = 1 0 3 9  -> Don't send ESC  when Alt modifies a key.
 596 |           (This disables the altSendsEscape resource).
 597 |             Ps = 1 0 4 0  -> Do not keep selection when not highlighted.
 598 |           (This disables the keepSelection resource).
 599 |             Ps = 1 0 4 1  -> Use the PRIMARY selection.  (This disables
 600 |           the selectToClipboard resource).
 601 |             Ps = 1 0 4 2  -> Disable Urgency window manager hint when
 602 |           Control-G is received.  (This disables the bellIsUrgent
 603 |           resource).
 604 |             Ps = 1 0 4 3  -> Disable raising of the window when Control-
 605 |           G is received.  (This disables the popOnBell resource).
 606 |             Ps = 1 0 4 7  -> Use Normal Screen Buffer, clearing screen
 607 |           first if in the Alternate Screen.  (This may be disabled by
 608 |           the titeInhibit resource).
 609 |             Ps = 1 0 4 8  -> Restore cursor as in DECRC.  (This may be
 610 |           disabled by the titeInhibit resource).
 611 |             Ps = 1 0 4 9  -> Use Normal Screen Buffer and restore cursor
 612 |           as in DECRC.  (This may be disabled by the titeInhibit
 613 |           resource).  This combines the effects of the 1 0 4 7  and 1 0
 614 |           4 8  modes.  Use this with terminfo-based applications rather
 615 |           than the 4 7  mode.
 616 |             Ps = 1 0 5 0  -> Reset terminfo/termcap function-key mode.
 617 |             Ps = 1 0 5 1  -> Reset Sun function-key mode.
 618 |             Ps = 1 0 5 2  -> Reset HP function-key mode.
 619 |             Ps = 1 0 5 3  -> Reset SCO function-key mode.
 620 |             Ps = 1 0 6 0  -> Reset legacy keyboard emulation (X11R6).
 621 |             Ps = 1 0 6 1  -> Reset keyboard emulation to Sun/PC style.
 622 |             Ps = 2 0 0 4  -> Reset bracketed paste mode.
 623 | CSI Pm m  Character Attributes (SGR).
 624 |             Ps = 0  -> Normal (default).
 625 |             Ps = 1  -> Bold.
 626 |             Ps = 2  -> Faint, decreased intensity (ISO 6429).
 627 |             Ps = 3  -> Italicized (ISO 6429).
 628 |             Ps = 4  -> Underlined.
 629 |             Ps = 5  -> Blink (appears as Bold).
 630 |             Ps = 7  -> Inverse.
 631 |             Ps = 8  -> Invisible, i.e., hidden (VT300).
 632 |             Ps = 9  -> Crossed-out characters (ISO 6429).
 633 |             Ps = 2 1  -> Doubly-underlined (ISO 6429).
 634 |             Ps = 2 2  -> Normal (neither bold nor faint).
 635 |             Ps = 2 3  -> Not italicized (ISO 6429).
 636 |             Ps = 2 4  -> Not underlined.
 637 |             Ps = 2 5  -> Steady (not blinking).
 638 |             Ps = 2 7  -> Positive (not inverse).
 639 |             Ps = 2 8  -> Visible, i.e., not hidden (VT300).
 640 |             Ps = 2 9  -> Not crossed-out (ISO 6429).
 641 |             Ps = 3 0  -> Set foreground color to Black.
 642 |             Ps = 3 1  -> Set foreground color to Red.
 643 |             Ps = 3 2  -> Set foreground color to Green.
 644 |             Ps = 3 3  -> Set foreground color to Yellow.
 645 |             Ps = 3 4  -> Set foreground color to Blue.
 646 |             Ps = 3 5  -> Set foreground color to Magenta.
 647 |             Ps = 3 6  -> Set foreground color to Cyan.
 648 |             Ps = 3 7  -> Set foreground color to White.
 649 |             Ps = 3 9  -> Set foreground color to default (original).
 650 |             Ps = 4 0  -> Set background color to Black.
 651 |             Ps = 4 1  -> Set background color to Red.
 652 |             Ps = 4 2  -> Set background color to Green.
 653 |             Ps = 4 3  -> Set background color to Yellow.
 654 |             Ps = 4 4  -> Set background color to Blue.
 655 |             Ps = 4 5  -> Set background color to Magenta.
 656 |             Ps = 4 6  -> Set background color to Cyan.
 657 |             Ps = 4 7  -> Set background color to White.
 658 |             Ps = 4 9  -> Set background color to default (original).
 659 | 
 660 |           If 16-color support is compiled, the following apply.  Assume
 661 |           that xterm's resources are set so that the ISO color codes are
 662 |           the first 8 of a set of 16.  Then the aixterm colors are the
 663 |           bright versions of the ISO colors:
 664 |             Ps = 9 0  -> Set foreground color to Black.
 665 |             Ps = 9 1  -> Set foreground color to Red.
 666 |             Ps = 9 2  -> Set foreground color to Green.
 667 |             Ps = 9 3  -> Set foreground color to Yellow.
 668 |             Ps = 9 4  -> Set foreground color to Blue.
 669 |             Ps = 9 5  -> Set foreground color to Magenta.
 670 |             Ps = 9 6  -> Set foreground color to Cyan.
 671 |             Ps = 9 7  -> Set foreground color to White.
 672 |             Ps = 1 0 0  -> Set background color to Black.
 673 |             Ps = 1 0 1  -> Set background color to Red.
 674 |             Ps = 1 0 2  -> Set background color to Green.
 675 |             Ps = 1 0 3  -> Set background color to Yellow.
 676 |             Ps = 1 0 4  -> Set background color to Blue.
 677 |             Ps = 1 0 5  -> Set background color to Magenta.
 678 |             Ps = 1 0 6  -> Set background color to Cyan.
 679 |             Ps = 1 0 7  -> Set background color to White.
 680 | 
 681 |           If xterm is compiled with the 16-color support disabled, it
 682 |           supports the following, from rxvt:
 683 |             Ps = 1 0 0  -> Set foreground and background color to
 684 |           default.
 685 | 
 686 |           Xterm maintains a color palette whose entries are identified
 687 |           by an index beginning with zero.  If 88- or 256-color support
 688 |           is compiled, the following apply:
 689 |           o All parameters are decimal integers.
 690 |           o RGB values range from zero (0) to 255.
 691 |           o ISO-8613-3 can be interpreted in more than one way; xterm
 692 |             allows the semicolons in this control to be replaced by
 693 |             colons (but after the first colon, colons must be used).
 694 | 
 695 |           These ISO-8613-3 controls are supported:
 696 |             Pm = 3 8 ; 2 ; Pr; Pg; Pb -> Set foreground color to the
 697 |           closest match in xterm's palette for the given RGB Pr/Pg/Pb.
 698 |             Pm = 3 8 ; 5 ; Ps -> Set foreground color to Ps.
 699 |             Pm = 4 8 ; 2 ; Pr; Pg; Pb -> Set background color to the
 700 |           closest match in xterm's palette for the given RGB Pr/Pg/Pb.
 701 |             Pm = 4 8 ; 5 ; Ps -> Set background color to Ps.
 702 | 
 703 | CSI > Ps; Ps m
 704 |           Set or reset resource-values used by xterm to decide whether
 705 |           to construct escape sequences holding information about the
 706 |           modifiers pressed with a given key.  The first parameter iden-
 707 |           tifies the resource to set/reset.  The second parameter is the
 708 |           value to assign to the resource.  If the second parameter is
 709 |           omitted, the resource is reset to its initial value.
 710 |             Ps = 0  -> modifyKeyboard.
 711 |             Ps = 1  -> modifyCursorKeys.
 712 |             Ps = 2  -> modifyFunctionKeys.
 713 |             Ps = 4  -> modifyOtherKeys.
 714 |           If no parameters are given, all resources are reset to their
 715 |           initial values.
 716 | CSI Ps n  Device Status Report (DSR).
 717 |             Ps = 5  -> Status Report.
 718 |           Result ("OK") is CSI 0 n
 719 |             Ps = 6  -> Report Cursor Position (CPR) [row;column].
 720 |           Result is CSI r ; c R
 721 | 
 722 |           Note: it is possible for this sequence to be sent by a func-
 723 |           tion key.  For example, with the default keyboard configura-
 724 |           tion the shifted F1 key may send (with shift-, control-, alt-
 725 |           modifiers)
 726 |             CSI 1  ; 2  R , or
 727 |             CSI 1  ; 5  R , or
 728 |             CSI 1  ; 6  R , etc.
 729 |           The second parameter encodes the modifiers; values range from
 730 |           2 to 16.  See the section PC-Style Function Keys for the
 731 |           codes.  The modifyFunctionKeys and modifyKeyboard resources
 732 |           can change the form of the string sent from the modified F1
 733 |           key.
 734 | 
 735 | CSI > Ps n
 736 |           Disable modifiers which may be enabled via the CSI > Ps; Ps m
 737 |           sequence.  This corresponds to a resource value of "-1", which
 738 |           cannot be set with the other sequence.  The parameter identi-
 739 |           fies the resource to be disabled:
 740 |             Ps = 0  -> modifyKeyboard.
 741 |             Ps = 1  -> modifyCursorKeys.
 742 |             Ps = 2  -> modifyFunctionKeys.
 743 |             Ps = 4  -> modifyOtherKeys.
 744 |           If the parameter is omitted, modifyFunctionKeys is disabled.
 745 |           When modifyFunctionKeys is disabled, xterm uses the modifier
 746 |           keys to make an extended sequence of functions rather than
 747 |           adding a parameter to each function key to denote the modi-
 748 |           fiers.
 749 | CSI ? Ps n
 750 |           Device Status Report (DSR, DEC-specific).
 751 |             Ps = 6  -> Report Cursor Position (DECXCPR) [row;column] as
 752 |           CSI ? r ; c R (assumes the default page, i.e., "1").
 753 |             Ps = 1 5  -> Report Printer status as CSI ? 1 0 n  (ready).
 754 |           or CSI ? 1 1 n  (not ready).
 755 |             Ps = 2 5  -> Report UDK status as CSI ? 2 0 n  (unlocked) or
 756 |           CSI ? 2 1 n  (locked).
 757 |             Ps = 2 6  -> Report Keyboard status as
 758 |           CSI ? 2 7 ; 1 ; 0 ; 0 n  (North American).
 759 |           The last two parameters apply to VT400 & up, and denote key-
 760 |           board ready and LK01 respectively.
 761 |             Ps = 5 3  -> Report Locator status as CSI ? 5 3 n  Locator
 762 |           available, if compiled-in, or CSI ? 5 0 n  No Locator, if not.
 763 |             Ps = 5 5  -> Report Locator status as CSI ? 5 3 n  Locator
 764 |           available, if compiled-in, or CSI ? 5 0 n  No Locator, if not.
 765 |             Ps = 5 6  -> Report Locator type as CSI ? 5 7 ; 1 n  Mouse,
 766 |           if compiled-in, or CSI ? 5 7 ; 0 n  Cannot identify, if not.
 767 |             Ps = 6 2  -> Report macro space (DECMSR) as CSI Pn \* {
 768 |             Ps = 6 3  -> Report memory checksum (DECCKSR) as DCS Pt ! x
 769 |           x x x ST
 770 |               Pt is the request id (from an optional parameter to the
 771 |           request).
 772 |               The x's are hexadecimal digits 0-9 and A-F.
 773 |             Ps = 7 5  -> Report data integrity as CSI ? 7 0 n  (ready,
 774 |           no errors)
 775 |             Ps = 8 5  -> Report multi-session configuration as CSI ? 8 3
 776 |           n  (not configured for multiple-session operation).
 777 | CSI > Ps p
 778 |           Set resource value pointerMode.  This is used by xterm to
 779 |           decide whether to hide the pointer cursor as the user types.
 780 |           Valid values for the parameter:
 781 |             Ps = 0  -> never hide the pointer.
 782 |             Ps = 1  -> hide if the mouse tracking mode is not enabled.
 783 |             Ps = 2  -> always hide the pointer, except when leaving the
 784 |           window.
 785 |             Ps = 3  -> always hide the pointer, even if leaving/entering
 786 |           the window.  If no parameter is given, xterm uses the default,
 787 |           which is 1 .
 788 | CSI ! p   Soft terminal reset (DECSTR).
 789 | CSI Ps $ p
 790 |           Request ANSI mode (DECRQM).  For VT300 and up, reply is
 791 |             CSI Ps; Pm$ y
 792 |           where Ps is the mode number as in RM, and Pm is the mode
 793 |           value:
 794 |             0 - not recognized
 795 |             1 - set
 796 |             2 - reset
 797 |             3 - permanently set
 798 |             4 - permanently reset
 799 | CSI ? Ps$ p
 800 |           Request DEC private mode (DECRQM).  For VT300 and up, reply is
 801 |             CSI ? Ps; Pm$ y
 802 |           where Ps is the mode number as in DECSET, Pm is the mode value
 803 |           as in the ANSI DECRQM.
 804 | CSI Ps ; Ps " p
 805 |           Set conformance level (DECSCL).  Valid values for the first
 806 |           parameter:
 807 |             Ps = 6 1  -> VT100.
 808 |             Ps = 6 2  -> VT200.
 809 |             Ps = 6 3  -> VT300.
 810 |           Valid values for the second parameter:
 811 |             Ps = 0  -> 8-bit controls.
 812 |             Ps = 1  -> 7-bit controls (always set for VT100).
 813 |             Ps = 2  -> 8-bit controls.
 814 | CSI Ps q  Load LEDs (DECLL).
 815 |             Ps = 0  -> Clear all LEDS (default).
 816 |             Ps = 1  -> Light Num Lock.
 817 |             Ps = 2  -> Light Caps Lock.
 818 |             Ps = 3  -> Light Scroll Lock.
 819 |             Ps = 2  1  -> Extinguish Num Lock.
 820 |             Ps = 2  2  -> Extinguish Caps Lock.
 821 |             Ps = 2  3  -> Extinguish Scroll Lock.
 822 | CSI Ps SP q
 823 |           Set cursor style (DECSCUSR, VT520).
 824 |             Ps = 0  -> blinking block.
 825 |             Ps = 1  -> blinking block (default).
 826 |             Ps = 2  -> steady block.
 827 |             Ps = 3  -> blinking underline.
 828 |             Ps = 4  -> steady underline.
 829 |             Ps = 5  -> blinking bar (xterm).
 830 |             Ps = 6  -> steady bar (xterm).
 831 | CSI Ps " q
 832 |           Select character protection attribute (DECSCA).  Valid values
 833 |           for the parameter:
 834 |             Ps = 0  -> DECSED and DECSEL can erase (default).
 835 |             Ps = 1  -> DECSED and DECSEL cannot erase.
 836 |             Ps = 2  -> DECSED and DECSEL can erase.
 837 | CSI Ps ; Ps r
 838 |           Set Scrolling Region [top;bottom] (default = full size of win-
 839 |           dow) (DECSTBM).
 840 | CSI ? Pm r
 841 |           Restore DEC Private Mode Values.  The value of Ps previously
 842 |           saved is restored.  Ps values are the same as for DECSET.
 843 | CSI Pt; Pl; Pb; Pr; Ps$ r
 844 |           Change Attributes in Rectangular Area (DECCARA), VT400 and up.
 845 |             Pt; Pl; Pb; Pr denotes the rectangle.
 846 |             Ps denotes the SGR attributes to change: 0, 1, 4, 5, 7.
 847 | CSI  Pl ; Pr s
 848 |           Set left and right margins (DECSLRM), available only when
 849 |           DECLRMM is enabled (VT420 and up).
 850 | CSI s     Save cursor (ANSI.SYS), available only when DECLRMM is dis-
 851 |           abled.
 852 | CSI ? Pm s
 853 |           Save DEC Private Mode Values.  Ps values are the same as for
 854 |           DECSET.
 855 | CSI Ps ; Ps ; Ps t
 856 |           Window manipulation (from dtterm, as well as extensions).
 857 |           These controls may be disabled using the allowWindowOps
 858 |           resource.  Valid values for the first (and any additional
 859 |           parameters) are:
 860 |             Ps = 1  -> De-iconify window.
 861 |             Ps = 2  -> Iconify window.
 862 |             Ps = 3  ;  x ;  y -> Move window to [x, y].
 863 |             Ps = 4  ;  height ;  width -> Resize the xterm window to
 864 |           given height and width in pixels.  Omitted parameters reuse
 865 |           the current height or width.  Zero parameters use the dis-
 866 |           play's height or width.
 867 |             Ps = 5  -> Raise the xterm window to the front of the stack-
 868 |           ing order.
 869 |             Ps = 6  -> Lower the xterm window to the bottom of the
 870 |           stacking order.
 871 |             Ps = 7  -> Refresh the xterm window.
 872 |             Ps = 8  ;  height ;  width -> Resize the text area to given
 873 |           height and width in characters.  Omitted parameters reuse the
 874 |           current height or width.  Zero parameters use the display's
 875 |           height or width.
 876 |             Ps = 9  ;  0  -> Restore maximized window.
 877 |             Ps = 9  ;  1  -> Maximize window (i.e., resize to screen
 878 |           size).
 879 |             Ps = 9  ;  2  -> Maximize window vertically.
 880 |             Ps = 9  ;  3  -> Maximize window horizontally.
 881 |             Ps = 1 0  ;  0  -> Undo full-screen mode.
 882 |             Ps = 1 0  ;  1  -> Change to full-screen.
 883 |             Ps = 1 0  ;  2  -> Toggle full-screen.
 884 |             Ps = 1 1  -> Report xterm window state.  If the xterm window
 885 |           is open (non-iconified), it returns CSI 1 t .  If the xterm
 886 |           window is iconified, it returns CSI 2 t .
 887 |             Ps = 1 3  -> Report xterm window position.
 888 |           Result is CSI 3 ; x ; y t
 889 |             Ps = 1 4  -> Report xterm window in pixels.
 890 |           Result is CSI  4  ;  height ;  width t
 891 |             Ps = 1 8  -> Report the size of the text area in characters.
 892 |           Result is CSI  8  ;  height ;  width t
 893 |             Ps = 1 9  -> Report the size of the screen in characters.
 894 |           Result is CSI  9  ;  height ;  width t
 895 |             Ps = 2 0  -> Report xterm window's icon label.
 896 |           Result is OSC  L  label ST
 897 |             Ps = 2 1  -> Report xterm window's title.
 898 |           Result is OSC  l  label ST
 899 |             Ps = 2 2  ;  0  -> Save xterm icon and window title on
 900 |           stack.
 901 |             Ps = 2 2  ;  1  -> Save xterm icon title on stack.
 902 |             Ps = 2 2  ;  2  -> Save xterm window title on stack.
 903 |             Ps = 2 3  ;  0  -> Restore xterm icon and window title from
 904 |           stack.
 905 |             Ps = 2 3  ;  1  -> Restore xterm icon title from stack.
 906 |             Ps = 2 3  ;  2  -> Restore xterm window title from stack.
 907 |             Ps >= 2 4  -> Resize to Ps lines (DECSLPP).
 908 | CSI Pt; Pl; Pb; Pr; Ps$ t
 909 |           Reverse Attributes in Rectangular Area (DECRARA), VT400 and
 910 |           up.
 911 |             Pt; Pl; Pb; Pr denotes the rectangle.
 912 |             Ps denotes the attributes to reverse, i.e.,  1, 4, 5, 7.
 913 | CSI > Ps; Ps t
 914 |           Set one or more features of the title modes.  Each parameter
 915 |           enables a single feature.
 916 |             Ps = 0  -> Set window/icon labels using hexadecimal.
 917 |             Ps = 1  -> Query window/icon labels using hexadecimal.
 918 |             Ps = 2  -> Set window/icon labels using UTF-8.
 919 |             Ps = 3  -> Query window/icon labels using UTF-8.  (See dis-
 920 |           cussion of "Title Modes")
 921 | CSI Ps SP t
 922 |           Set warning-bell volume (DECSWBV, VT520).
 923 |             Ps = 0  or 1  -> off.
 924 |             Ps = 2 , 3  or 4  -> low.
 925 |             Ps = 5 , 6 , 7 , or 8  -> high.
 926 | CSI u     Restore cursor (ANSI.SYS).
 927 | CSI Ps SP u
 928 |           Set margin-bell volume (DECSMBV, VT520).
 929 |             Ps = 1  -> off.
 930 |             Ps = 2 , 3  or 4  -> low.
 931 |             Ps = 0 , 5 , 6 , 7 , or 8  -> high.
 932 | CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v
 933 |           Copy Rectangular Area (DECCRA, VT400 and up).
 934 |             Pt; Pl; Pb; Pr denotes the rectangle.
 935 |             Pp denotes the source page.
 936 |             Pt; Pl denotes the target location.
 937 |             Pp denotes the target page.
 938 | CSI Pt ; Pl ; Pb ; Pr ' w
 939 |           Enable Filter Rectangle (DECEFR), VT420 and up.
 940 |           Parameters are [top;left;bottom;right].
 941 |           Defines the coordinates of a filter rectangle and activates
 942 |           it.  Anytime the locator is detected outside of the filter
 943 |           rectangle, an outside rectangle event is generated and the
 944 |           rectangle is disabled.  Filter rectangles are always treated
 945 |           as "one-shot" events.  Any parameters that are omitted default
 946 |           to the current locator position.  If all parameters are omit-
 947 |           ted, any locator motion will be reported.  DECELR always can-
 948 |           cels any prevous rectangle definition.
 949 | CSI Ps x  Request Terminal Parameters (DECREQTPARM).
 950 |           if Ps is a "0" (default) or "1", and xterm is emulating VT100,
 951 |           the control sequence elicits a response of the same form whose
 952 |           parameters describe the terminal:
 953 |             Ps -> the given Ps incremented by 2.
 954 |             Pn = 1  <- no parity.
 955 |             Pn = 1  <- eight bits.
 956 |             Pn = 1  <- 2  8  transmit 38.4k baud.
 957 |             Pn = 1  <- 2  8  receive 38.4k baud.
 958 |             Pn = 1  <- clock multiplier.
 959 |             Pn = 0  <- STP flags.
 960 | CSI Ps * x
 961 |           Select Attribute Change Extent (DECSACE).
 962 |             Ps = 0  -> from start to end position, wrapped.
 963 |             Ps = 1  -> from start to end position, wrapped.
 964 |             Ps = 2  -> rectangle (exact).
 965 | CSI Pi ; Pg ; Pt; Pl; Pb; Pr * y
 966 |           Request Checksum of Rectangular Area (DECRQCRA), VT420 and up.
 967 |           Response is
 968 |           DCS Pi ! x x x x ST
 969 |             Pi is the request id.
 970 |             Pg is the page number.
 971 |             Pt; Pl; Pb; Pr denotes the rectangle.
 972 |             The x's are hexadecimal digits 0-9 and A-F.
 973 | CSI Pc ; Pt ; Pl ; Pb ; Pr $ x
 974 |           Fill Rectangular Area (DECFRA), VT420 and up.
 975 |             Pc is the character to use.
 976 |             Pt; Pl; Pb; Pr denotes the rectangle.
 977 | CSI Ps ; Pu ' z
 978 |           Enable Locator Reporting (DECELR).
 979 |           Valid values for the first parameter:
 980 |             Ps = 0  -> Locator disabled (default).
 981 |             Ps = 1  -> Locator enabled.
 982 |             Ps = 2  -> Locator enabled for one report, then disabled.
 983 |           The second parameter specifies the coordinate unit for locator
 984 |           reports.
 985 |           Valid values for the second parameter:
 986 |             Pu = 0  <- or omitted -> default to character cells.
 987 |             Pu = 1  <- device physical pixels.
 988 |             Pu = 2  <- character cells.
 989 | CSI Pt; Pl; Pb; Pr$ z
 990 |           Erase Rectangular Area (DECERA), VT400 and up.
 991 |             Pt; Pl; Pb; Pr denotes the rectangle.
 992 | CSI Pm ' {
 993 |           Select Locator Events (DECSLE).
 994 |           Valid values for the first (and any additional parameters)
 995 |           are:
 996 |             Ps = 0  -> only respond to explicit host requests (DECRQLP).
 997 |                        (This is default).  It also cancels any filter
 998 |                        rectangle.
 999 |             Ps = 1  -> report button down transitions.
1000 |             Ps = 2  -> do not report button down transitions.
1001 |             Ps = 3  -> report button up transitions.
1002 |             Ps = 4  -> do not report button up transitions.
1003 | CSI Pt; Pl; Pb; Pr $ {
1004 |           Selective Erase Rectangular Area (DECSERA), VT400 and up.
1005 |             Pt; Pl; Pb; Pr denotes the rectangle.
1006 | CSI Ps ' |
1007 |           Request Locator Position (DECRQLP).
1008 |           Valid values for the parameter are:
1009 |             Ps = 0 , 1 or omitted -> transmit a single DECLRP locator
1010 |           report.
1011 | 
1012 |           If Locator Reporting has been enabled by a DECELR, xterm will
1013 |           respond with a DECLRP Locator Report.  This report is also
1014 |           generated on button up and down events if they have been
1015 |           enabled with a DECSLE, or when the locator is detected outside
1016 |           of a filter rectangle, if filter rectangles have been enabled
1017 |           with a DECEFR.
1018 | 
1019 |             -> CSI Pe ; Pb ; Pr ; Pc ; Pp &  w
1020 | 
1021 |           Parameters are [event;button;row;column;page].
1022 |           Valid values for the event:
1023 |             Pe = 0  -> locator unavailable - no other parameters sent.
1024 |             Pe = 1  -> request - xterm received a DECRQLP.
1025 |             Pe = 2  -> left button down.
1026 |             Pe = 3  -> left button up.
1027 |             Pe = 4  -> middle button down.
1028 |             Pe = 5  -> middle button up.
1029 |             Pe = 6  -> right button down.
1030 |             Pe = 7  -> right button up.
1031 |             Pe = 8  -> M4 button down.
1032 |             Pe = 9  -> M4 button up.
1033 |             Pe = 1 0  -> locator outside filter rectangle.
1034 |           The "button" parameter is a bitmask indicating which buttons
1035 |           are pressed:
1036 |             Pb = 0  <- no buttons down.
1037 |             Pb & 1  <- right button down.
1038 |             Pb & 2  <- middle button down.
1039 |             Pb & 4  <- left button down.
1040 |             Pb & 8  <- M4 button down.
1041 |           The "row" and "column" parameters are the coordinates of the
1042 |           locator position in the xterm window, encoded as ASCII deci-
1043 |           mal.
1044 |           The "page" parameter is not used by xterm.
1045 | CSI Pm ' }
1046 |           Insert Ps Column(s) (default = 1) (DECIC), VT420 and up.
1047 | CSI Pm ' ~
1048 |           Delete Ps Column(s) (default = 1) (DECDC), VT420 and up.
1049 | 
1050 | 
1051 |

Operating System Controls

1052 |
OSC Ps ; Pt ST
1053 | OSC Ps ; Pt BEL
1054 |           Set Text Parameters.  For colors and font, if Pt is a "?", the
1055 |           control sequence elicits a response which consists of the con-
1056 |           trol sequence which would set the corresponding value.  The
1057 |           dtterm control sequences allow you to determine the icon name
1058 |           and window title.
1059 |             Ps = 0  -> Change Icon Name and Window Title to Pt.
1060 |             Ps = 1  -> Change Icon Name to Pt.
1061 |             Ps = 2  -> Change Window Title to Pt.
1062 |             Ps = 3  -> Set X property on top-level window.  Pt should be
1063 |           in the form "prop=value", or just "prop" to delete the prop-
1064 |           erty
1065 |             Ps = 4 ; c; spec -> Change Color Number c to the color spec-
1066 |           ified by spec.  This can be a name or RGB specification as per
1067 |           XParseColor.  Any number of c/spec pairs may be given.  The
1068 |           color numbers correspond to the ANSI colors 0-7, their bright
1069 |           versions 8-15, and if supported, the remainder of the 88-color
1070 |           or 256-color table.
1071 | 
1072 |           If a "?" is given rather than a name or RGB specification,
1073 |           xterm replies with a control sequence of the same form which
1074 |           can be used to set the corresponding color.  Because more than
1075 |           one pair of color number and specification can be given in one
1076 |           control sequence, xterm can make more than one reply.
1077 | 
1078 |             Ps = 5 ; c; spec -> Change Special Color Number c to the
1079 |           color specified by spec.  This can be a name or RGB specifica-
1080 |           tion as per XParseColor.  Any number of c/spec pairs may be
1081 |           given.  The special colors can also be set by adding the maxi-
1082 |           mum number of colors to these codes in an OSC 4  control:
1083 | 
1084 |               Pc = 0  <- resource colorBD (BOLD).
1085 |               Pc = 1  <- resource colorUL (UNDERLINE).
1086 |               Pc = 2  <- resource colorBL (BLINK).
1087 |               Pc = 3  <- resource colorRV (REVERSE).
1088 |               Pc = 4  <- resource colorIT (ITALIC).
1089 | 
1090 |             Ps = 6 ; c; f -> Enable/disable Special Color Number c.  OSC
1091 |           6  is the same as OSC 1 0 6 .
1092 | 
1093 |           The 10 colors (below) which may be set or queried using 1 0
1094 |           through 1 9  are denoted dynamic colors, since the correspond-
1095 |           ing control sequences were the first means for setting xterm's
1096 |           colors dynamically, i.e., after it was started.  They are not
1097 |           the same as the ANSI colors.  These controls may be disabled
1098 |           using the allowColorOps resource.  At least one parameter is
1099 |           expected for Pt.  Each successive parameter changes the next
1100 |           color in the list.  The value of Ps tells the starting point
1101 |           in the list.  The colors are specified by name or RGB specifi-
1102 |           cation as per XParseColor.
1103 | 
1104 |           If a "?" is given rather than a name or RGB specification,
1105 |           xterm replies with a control sequence of the same form which
1106 |           can be used to set the corresponding dynamic color.  Because
1107 |           more than one pair of color number and specification can be
1108 |           given in one control sequence, xterm can make more than one
1109 |           reply.
1110 | 
1111 |             Ps = 1 0  -> Change VT100 text foreground color to Pt.
1112 |             Ps = 1 1  -> Change VT100 text background color to Pt.
1113 |             Ps = 1 2  -> Change text cursor color to Pt.
1114 |             Ps = 1 3  -> Change mouse foreground color to Pt.
1115 |             Ps = 1 4  -> Change mouse background color to Pt.
1116 |             Ps = 1 5  -> Change Tektronix foreground color to Pt.
1117 |             Ps = 1 6  -> Change Tektronix background color to Pt.
1118 |             Ps = 1 7  -> Change highlight background color to Pt.
1119 |             Ps = 1 8  -> Change Tektronix cursor color to Pt.
1120 |             Ps = 1 9  -> Change highlight foreground color to Pt.
1121 | 
1122 |             Ps = 4 6  -> Change Log File to Pt.  (This is normally dis-
1123 |           abled by a compile-time option).
1124 | 
1125 |             Ps = 5 0  -> Set Font to Pt.  These controls may be disabled
1126 |           using the allowFontOps resource.  If Pt begins with a "#",
1127 |           index in the font menu, relative (if the next character is a
1128 |           plus or minus sign) or absolute.  A number is expected but not
1129 |           required after the sign (the default is the current entry for
1130 |           relative, zero for absolute indexing).
1131 |           The same rule (plus or minus sign, optional number) is used
1132 |           when querying the font.  The remainder of Pt is ignored.
1133 |           A font can be specified after a "#" index expression, by
1134 |           adding a space and then the font specifier.
1135 |           If the "TrueType Fonts" menu entry is set (the renderFont
1136 |           resource), then this control sets/queries the faceName
1137 |           resource.
1138 | 
1139 |             Ps = 5 1  -> reserved for Emacs shell.
1140 | 
1141 |             Ps = 5 2  -> Manipulate Selection Data.  These controls may
1142 |           be disabled using the allowWindowOps resource.  The parameter
1143 |           Pt is parsed as
1144 |                Pc; Pd
1145 |           The first, Pc, may contain zero or more characters from the
1146 |           set c  p  s  0  1  2  3  4  5  6  7 .  It is used to construct
1147 |           a list of selection parameters for clipboard, primary, select,
1148 |           or cut buffers 0 through 7 respectively, in the order given.
1149 |           If the parameter is empty, xterm uses s 0 , to specify the
1150 |           configurable primary/clipboard selection and cut buffer 0.
1151 |           The second parameter, Pd, gives the selection data.  Normally
1152 |           this is a string encoded in base64.  The data becomes the new
1153 |           selection, which is then available for pasting by other appli-
1154 |           cations.
1155 |           If the second parameter is a ? , xterm replies to the host
1156 |           with the selection data encoded using the same protocol.
1157 |           If the second parameter is neither a base64 string nor ? ,
1158 |           then the selection is cleared.
1159 | 
1160 |             Ps = 1 0 4 ; c -> Reset Color Number c.  It is reset to the
1161 |           color specified by the corresponding X resource.  Any number
1162 |           of c parameters may be given.  These parameters correspond to
1163 |           the ANSI colors 0-7, their bright versions 8-15, and if sup-
1164 |           ported, the remainder of the 88-color or 256-color table.  If
1165 |           no parameters are given, the entire table will be reset.
1166 | 
1167 |             Ps = 1 0 5 ; c -> Reset Special Color Number c.  It is reset
1168 |           to the color specified by the corresponding X resource.  Any
1169 |           number of c parameters may be given.  These parameters corre-
1170 |           spond to the special colors which can be set using an OSC 5
1171 |           control (or by adding the maximum number of colors using an
1172 |           OSC 4  control).
1173 | 
1174 |             Ps = 1 0 6 ; c; f -> Enable/disable Special Color Number c.
1175 |           The second parameter tells xterm to enable the corresponding
1176 |           color mode if nonzero, disable it if zero.
1177 | 
1178 |               Pc = 0  <- resource colorBDMode (BOLD).
1179 |               Pc = 1  <- resource colorULMode (UNDERLINE).
1180 |               Pc = 2  <- resource colorBLMode (BLINK).
1181 |               Pc = 3  <- resource colorRVMode (REVERSE).
1182 |               Pc = 4  <- resource colorITMode (ITALIC).
1183 |               Pc = 5  <- resource colorAttrMode (Override ANSI).
1184 | 
1185 |           The dynamic colors can also be reset to their default
1186 |           (resource) values:
1187 |             Ps = 1 1 0  -> Reset VT100 text foreground color.
1188 |             Ps = 1 1 1  -> Reset VT100 text background color.
1189 |             Ps = 1 1 2  -> Reset text cursor color.
1190 |             Ps = 1 1 3  -> Reset mouse foreground color.
1191 |             Ps = 1 1 4  -> Reset mouse background color.
1192 |             Ps = 1 1 5  -> Reset Tektronix foreground color.
1193 |             Ps = 1 1 6  -> Reset Tektronix background color.
1194 |             Ps = 1 1 7  -> Reset highlight color.
1195 |             Ps = 1 1 8  -> Reset Tektronix cursor color.
1196 |             Ps = 1 1 9  -> Reset highlight foreground color.
1197 | 
1198 | 
1199 |

Privacy Message

1200 |
PM Pt ST  xterm implements no PM  functions; Pt is ignored.  Pt need not
1201 |           be printable characters.
1202 | 
1203 | 
1204 |

Alt and Meta Keys

1205 |
Many keyboards have keys labeled "Alt".  Few have keys labeled "Meta".
1206 | However, xterm's default translations use the Meta modifier.  Common
1207 | keyboard configurations assign the Meta modifier to an "Alt" key.  By
1208 | using xmodmap one may have the modifier assigned to a different key, and
1209 | have "real" alt and meta keys.  Here is an example:
1210 | 
1211 |      ! put meta on mod3 to distinguish it from alt
1212 |      keycode 64 = Alt_L
1213 |      clear mod1
1214 |      add mod1 = Alt_L
1215 |      keycode 115 = Meta_L
1216 |      clear mod3
1217 |      add mod3 = Meta_L
1218 | 
1219 | The metaSendsEscape resource (and altSendsEscape if altIsNotMeta is set)
1220 | can be used to control the way the Meta modifier applies to ordinary
1221 | keys unless the modifyOtherKeys resource is set:
1222 |           - prefix a key with the ESC  character.
1223 |           - shift the key from codes 0-127 to 128-255 by adding 128.
1224 | 
1225 | The table shows the result for a given character "x" with modifiers
1226 | according to the default translations with the resources set on or off.
1227 | This assumes altIsNotMeta is set:
1228 | 
1229 |        -----------------------------------------------------------
1230 |        key          altSendsEscape   metaSendsEscape   result
1231 |        -----------+----------------+-----------------+------------
1232 |        x          | off            | off             | x
1233 |        Meta-x     | off            | off             | shift
1234 |        Alt-x      | off            | off             | shift
1235 |        Alt+Meta-x | off            | off             | shift
1236 |        x          | ON             | off             | x
1237 |        Meta-x     | ON             | off             | shift
1238 |        Alt-x      | ON             | off             | ESC  x
1239 |        Alt+Meta-x | ON             | off             | ESC  shift
1240 |        x          | off            | ON              | x
1241 |        Meta-x     | off            | ON              | ESC  x
1242 |        Alt-x      | off            | ON              | shift
1243 |        Alt+Meta-x | off            | ON              | ESC  shift
1244 |        x          | ON             | ON              | x
1245 |        Meta-x     | ON             | ON              | ESC  x
1246 |        Alt-x      | ON             | ON              | ESC  x
1247 |        Alt+Meta-x | ON             | ON              | ESC  x
1248 |        -----------+----------------+-----------------+------------
1249 | 
1250 | 
1251 |

PC-Style Function Keys

1252 |
If xterm does minimal translation of the function keys, it usually does
1253 | this with a PC-style keyboard, so PC-style function keys result.  Sun
1254 | keyboards are similar to PC keyboards.  Both have cursor and scrolling
1255 | operations printed on the keypad, which duplicate the smaller cursor and
1256 | scrolling keypads.
1257 | 
1258 | X does not predefine NumLock (used for VT220 keyboards) or Alt (used as
1259 | an extension for the Sun/PC keyboards) as modifiers.  These keys are
1260 | recognized as modifiers when enabled by the numLock resource, or by the
1261 | "DECSET 1 0 3 5 " control sequence.
1262 | 
1263 | The cursor keys transmit the following escape sequences depending on the
1264 | mode specified via the DECCKM escape sequence.
1265 | 
1266 |                   Key            Normal     Application
1267 |                   -------------+----------+-------------
1268 |                   Cursor Up    | CSI A    | SS3 A
1269 |                   Cursor Down  | CSI B    | SS3 B
1270 |                   Cursor Right | CSI C    | SS3 C
1271 |                   Cursor Left  | CSI D    | SS3 D
1272 |                   -------------+----------+-------------
1273 | 
1274 | The home- and end-keys (unlike PageUp and other keys also on the 6-key
1275 | editing keypad) are considered "cursor keys" by xterm.  Their mode is
1276 | also controlled by the DECCKM escape sequence:
1277 | 
1278 |                     Key        Normal     Application
1279 |                     ---------+----------+-------------
1280 |                     Home     | CSI H    | SS3 H
1281 |                     End      | CSI F    | SS3 F
1282 |                     ---------+----------+-------------
1283 | 
1284 | The application keypad transmits the following escape sequences depend-
1285 | ing on the mode specified via the DECKPNM and DECKPAM escape sequences.
1286 | Use the NumLock key to override the application mode.
1287 | 
1288 | Not all keys are present on the Sun/PC keypad (e.g., PF1, Tab), but are
1289 | supported by the program.
1290 | 
1291 |       Key              Numeric    Application   Terminfo   Termcap
1292 |       ---------------+----------+-------------+----------+----------
1293 |       Space          | SP       | SS3 SP      | -        | -
1294 |       Tab            | TAB      | SS3 I       | -        | -
1295 |       Enter          | CR       | SS3 M       | kent     | @8
1296 |       PF1            | SS3 P    | SS3 P       | kf1      | k1
1297 |       PF2            | SS3 Q    | SS3 Q       | kf2      | k2
1298 |       PF3            | SS3 R    | SS3 R       | kf3      | k3
1299 |       PF4            | SS3 S    | SS3 S       | kf4      | k4
1300 |       * (multiply)   | *        | SS3 j       | -        | -
1301 |       + (add)        | +        | SS3 k       | -        | -
1302 |       , (comma)      | ,        | SS3 l       | -        | -
1303 |       - (minus)      | -        | SS3 m       | -        | -
1304 |       . (Delete)     | .        | CSI 3 ~     | -        | -
1305 |       / (divide)     | /        | SS3 o       | -        | -
1306 |       0 (Insert)     | 0        | CSI 2 ~     | -        | -
1307 |       1 (End)        | 1        | SS3 F       | kc1      | K4
1308 |       2 (DownArrow)  | 2        | CSI B       | -        | -
1309 |       3 (PageDown)   | 3        | CSI 6 ~     | kc3      | K5
1310 |       4 (LeftArrow)  | 4        | CSI D       | -        | -
1311 |       5 (Begin)      | 5        | CSI E       | kb2      | K2
1312 |       6 (RightArrow) | 6        | CSI C       | -        | -
1313 |       7 (Home)       | 7        | SS3 H       | ka1      | K1
1314 |       8 (UpArrow)    | 8        | CSI A       | -        | -
1315 |       9 (PageUp)     | 9        | CSI 5 ~     | ka3      | K3
1316 |       = (equal)      | =        | SS3 X       | -        | -
1317 |       ---------------+----------+-------------+----------+----------
1318 | 
1319 | They also provide 12 function keys, as well as a few other special-pur-
1320 | pose keys:
1321 | 
1322 |                        Key        Escape Sequence
1323 |                        ---------+-----------------
1324 |                        F1       | SS3 P
1325 |                        F2       | SS3 Q
1326 |                        F3       | SS3 R
1327 |                        F4       | SS3 S
1328 |                        F5       | CSI 1 5 ~
1329 |                        F6       | CSI 1 7 ~
1330 |                        F7       | CSI 1 8 ~
1331 |                        F8       | CSI 1 9 ~
1332 |                        F9       | CSI 2 0 ~
1333 |                        F10      | CSI 2 1 ~
1334 |                        F11      | CSI 2 3 ~
1335 |                        F12      | CSI 2 4 ~
1336 |                        ---------+-----------------
1337 | 
1338 | Note that F1 through F4 are prefixed with SS3 , while the other keys are
1339 | prefixed with CSI .  Older versions of xterm implement different escape
1340 | sequences for F1 through F4, with a CSI  prefix.  These can be activated
1341 | by setting the oldXtermFKeys resource.  However, since they do not cor-
1342 | respond to any hardware terminal, they have been deprecated.  (The DEC
1343 | VT220 reserves F1 through F5 for local functions such as Setup).
1344 | 
1345 |                        Key        Escape Sequence
1346 |                        ---------+-----------------
1347 |                        F1       | CSI 1 1 ~
1348 |                        F2       | CSI 1 2 ~
1349 |                        F3       | CSI 1 3 ~
1350 |                        F4       | CSI 1 4 ~
1351 |                        ---------+-----------------
1352 | 
1353 | In normal mode, i.e., a Sun/PC keyboard when the sunKeyboard resource is
1354 | false (and none of the other keyboard resources such as oldXtermFKeys
1355 | resource is set), xterm encodes function key modifiers as parameters
1356 | appended before the final character of the control sequence.  As a spe-
1357 | cial case, the SS3  sent before F1 through F4 is altered to CSI  when
1358 | sending a function key modifier as a parameter.
1359 | 
1360 |                     Code     Modifiers
1361 |                   ---------+---------------------------
1362 |                      2     | Shift
1363 |                      3     | Alt
1364 |                      4     | Shift + Alt
1365 |                      5     | Control
1366 |                      6     | Shift + Control
1367 |                      7     | Alt + Control
1368 |                      8     | Shift + Alt + Control
1369 |                      9     | Meta
1370 |                      10    | Meta + Shift
1371 |                      11    | Meta + Alt
1372 |                      12    | Meta + Alt + Shift
1373 |                      13    | Meta + Ctrl
1374 |                      14    | Meta + Ctrl + Shift
1375 |                      15    | Meta + Ctrl + Alt
1376 |                      16    | Meta + Ctrl + Alt + Shift
1377 |                   ---------+---------------------------
1378 | 
1379 | For example, shift-F5 would be sent as CSI 1 5 ; 2 ~
1380 | 
1381 | If the alwaysUseMods resource is set, the Meta modifier also is recog-
1382 | nized, making parameters 9 through 16.
1383 | 
1384 | 
1385 |

VT220-Style Function Keys

1386 |
However, xterm is most useful as a DEC VT102 or VT220 emulator.  Set the
1387 | sunKeyboard resource to true to force a Sun/PC keyboard to act like a
1388 | VT220 keyboard.
1389 | 
1390 | The VT102/VT220 application keypad transmits unique escape sequences in
1391 | application mode, which are distinct from the cursor and scrolling key-
1392 | pad:
1393 | 
1394 |                   Key            Numeric    Application
1395 |                   -------------+----------+-------------
1396 |                   Space        | SP       | SS3 SP
1397 |                   Tab          | TAB      | SS3 I
1398 |                   Enter        | CR       | SS3 M
1399 |                   PF1          | SS3 P    | SS3 P
1400 |                   PF2          | SS3 Q    | SS3 Q
1401 |                   PF3          | SS3 R    | SS3 R
1402 |                   PF4          | SS3 S    | SS3 S
1403 |                   * (multiply) | *        | SS3 j
1404 |                   + (add)      | +        | SS3 k
1405 |                   , (comma)    | ,        | SS3 l
1406 |                   - (minus)    | -        | SS3 m
1407 |                   . (period)   | .        | SS3 n
1408 |                   / (divide)   | /        | SS3 o
1409 |                   0            | 0        | SS3 p
1410 |                   1            | 1        | SS3 q
1411 |                   2            | 2        | SS3 r
1412 |                   3            | 3        | SS3 s
1413 |                   4            | 4        | SS3 t
1414 |                   5            | 5        | SS3 u
1415 |                   6            | 6        | SS3 v
1416 |                   7            | 7        | SS3 w
1417 |                   8            | 8        | SS3 x
1418 |                   9            | 9        | SS3 y
1419 |                   = (equal)    | =        | SS3 X
1420 |                   -------------+----------+-------------
1421 | 
1422 | The VT220 provides a 6-key editing keypad, which is analogous to that on
1423 | the PC keyboard.  It is not affected by DECCKM or DECKPNM/DECKPAM:
1424 | 
1425 |                    Key        Normal     Application
1426 |                    ---------+----------+-------------
1427 |                    Insert   | CSI 2 ~  | CSI 2 ~
1428 |                    Delete   | CSI 3 ~  | CSI 3 ~
1429 |                    Home     | CSI 1 ~  | CSI 1 ~
1430 |                    End      | CSI 4 ~  | CSI 4 ~
1431 |                    PageUp   | CSI 5 ~  | CSI 5 ~
1432 |                    PageDown | CSI 6 ~  | CSI 6 ~
1433 |                    ---------+----------+-------------
1434 | 
1435 | The VT220 provides 8 additional function keys.  With a Sun/PC keyboard,
1436 | access these keys by Control/F1 for F13, etc.
1437 | 
1438 |                        Key        Escape Sequence
1439 |                        ---------+-----------------
1440 |                        F13      | CSI 2 5 ~
1441 |                        F14      | CSI 2 6 ~
1442 |                        F15      | CSI 2 8 ~
1443 |                        F16      | CSI 2 9 ~
1444 |                        F17      | CSI 3 1 ~
1445 |                        F18      | CSI 3 2 ~
1446 |                        F19      | CSI 3 3 ~
1447 |                        F20      | CSI 3 4 ~
1448 |                        ---------+-----------------
1449 | 
1450 | 
1451 |

VT52-Style Function Keys

1452 |
A VT52 does not have function keys, but it does have a numeric keypad
1453 | and cursor keys.  They differ from the other emulations by the prefix.
1454 | Also, the cursor keys do not change:
1455 | 
1456 |                    Key            Normal/Application
1457 |                    -------------+--------------------
1458 |                    Cursor Up    | ESC A
1459 |                    Cursor Down  | ESC B
1460 |                    Cursor Right | ESC C
1461 |                    Cursor Left  | ESC D
1462 |                    -------------+--------------------
1463 | 
1464 | The keypad is similar:
1465 | 
1466 |                   Key            Numeric    Application
1467 |                   -------------+----------+-------------
1468 |                   Space        | SP       | ESC ? SP
1469 |                   Tab          | TAB      | ESC ? I
1470 |                   Enter        | CR       | ESC ? M
1471 |                   PF1          | ESC P    | ESC P
1472 |                   PF2          | ESC Q    | ESC Q
1473 |                   PF3          | ESC R    | ESC R
1474 |                   PF4          | ESC S    | ESC S
1475 |                   * (multiply) | *        | ESC ? j
1476 |                   + (add)      | +        | ESC ? k
1477 |                   , (comma)    | ,        | ESC ? l
1478 |                   - (minus)    | -        | ESC ? m
1479 |                   . (period)   | .        | ESC ? n
1480 |                   / (divide)   | /        | ESC ? o
1481 |                   0            | 0        | ESC ? p
1482 |                   1            | 1        | ESC ? q
1483 |                   2            | 2        | ESC ? r
1484 |                   3            | 3        | ESC ? s
1485 |                   4            | 4        | ESC ? t
1486 |                   5            | 5        | ESC ? u
1487 |                   6            | 6        | ESC ? v
1488 |                   7            | 7        | ESC ? w
1489 |                   8            | 8        | ESC ? x
1490 |                   9            | 9        | ESC ? y
1491 |                   = (equal)    | =        | ESC ? X
1492 |                   -------------+----------+-------------
1493 | 
1494 | 
1495 |

Sun-Style Function Keys

1496 |
The xterm program provides support for Sun keyboards more directly, by a
1497 | menu toggle that causes it to send Sun-style function key codes rather
1498 | than VT220.  Note, however, that the sun and VT100 emulations are not
1499 | really compatible.  For example, their wrap-margin behavior differs.
1500 | 
1501 | Only function keys are altered; keypad and cursor keys are the same.
1502 | The emulation responds identically.  See the xterm-sun terminfo entry
1503 | for details.
1504 | 
1505 | 
1506 |

HP-Style Function Keys

1507 |
Similarly, xterm can be compiled to support HP keyboards.  See the
1508 | xterm-hp terminfo entry for details.
1509 | 
1510 | 
1511 |

The Alternate Screen Buffer

1512 |
Xterm maintains two screen buffers.  The normal screen buffer allows you
1513 | to scroll back to view saved lines of output up to the maximum set by
1514 | the saveLines resource.  The alternate screen buffer is exactly as large
1515 | as the display, contains no additional saved lines.  When the alternate
1516 | screen buffer is active, you cannot scroll back to view saved lines.
1517 | Xterm provides control sequences and menu entries for switching between
1518 | the two.
1519 | 
1520 | Most full-screen applications use terminfo or termcap to obtain strings
1521 | used to start/stop full-screen mode, i.e., smcup and rmcup for terminfo,
1522 | or the corresponding ti and te for termcap.  The titeInhibit resource
1523 | removes the ti and te strings from the TERMCAP string which is set in
1524 | the environment for some platforms.  That is not done when xterm is
1525 | built with terminfo libraries because terminfo does not provide the
1526 | whole text of the termcap data in one piece.  It would not work for ter-
1527 | minfo anyway, since terminfo data is not passed in environment vari-
1528 | ables; setting an environment variable in this manner would have no
1529 | effect on the application's ability to switch between normal and alter-
1530 | nate screen buffers.  Instead, the newer private mode controls (such as
1531 | 1 0 4 9 ) for switching between normal and alternate screen buffers sim-
1532 | ply disable the switching.  They add other features such as clearing the
1533 | display for the same reason: to make the details of switching indepen-
1534 | dent of the application that requests the switch.
1535 | 
1536 | 
1537 |

Bracketed Paste Mode

1538 |
When bracketed paste mode is set, pasted text is bracketed with control
1539 | sequences so that the program can differentiate pasted text from typed-
1540 | in text.  When bracketed paste mode is set, the program will receive:
1541 |    ESC [ 2 0 0 ~ ,
1542 | followed by the pasted text, followed by
1543 |    ESC [ 2 0 1 ~ .
1544 | 
1545 | 
1546 |

Title Modes

1547 |
The window- and icon-labels can be set or queried using control
1548 | sequences.  As a VT220-emulator, xterm "should" limit the character
1549 | encoding for the corresponding strings to ISO-8859-1.  Indeed, it used
1550 | to be the case (and was documented) that window titles had to be
1551 | ISO-8859-1.  This is no longer the case.  However, there are many appli-
1552 | cations which still assume that titles are set using ISO-8859-1.  So
1553 | that is the default behavior.
1554 | 
1555 | If xterm is running with UTF-8 encoding, it is possible to use window-
1556 | and icon-labels encoded using UTF-8.  That is because the underlying X
1557 | libraries (and many, but not all) window managers support this feature.
1558 | 
1559 | The utf8Title X resource setting tells xterm to disable a reconversion
1560 | of the title string back to ISO-8859-1, allowing the title strings to be
1561 | interpreted as UTF-8.  The same feature can be enabled using the title
1562 | mode control sequence described in this summary.
1563 | 
1564 | Separate from the ability to set the titles, xterm provides the ability
1565 | to query the titles, returning them either in ISO-8859-1 or UTF-8.  This
1566 | choice is available only while xterm is using UTF-8 encoding.
1567 | 
1568 | Finally, the characters sent to, or returned by a title control are less
1569 | constrained than the rest of the control sequences.  To make them more
1570 | manageable (and constrained), for use in shell scripts, xterm has an
1571 | optional feature which decodes the string from hexadecimal (for setting
1572 | titles) or for encoding the title into hexadecimal when querying the
1573 | value.
1574 | 
1575 | 
1576 |

Mouse Tracking

1577 |
The VT widget can be set to send the mouse position and other informa-
1578 | tion on button presses.  These modes are typically used by editors and
1579 | other full-screen applications that want to make use of the mouse.
1580 | 
1581 | There are two sets of mutually exclusive modes:
1582 | o mouse protocol
1583 | o protocol encoding
1584 | 
1585 | The mouse protocols include DEC Locator mode, enabled by the DECELR CSI
1586 | Ps ; Ps  '  z control sequence, and is not described here (control
1587 | sequences are summarized above).  The remaining five modes of the mouse
1588 | protocols are each enabled (or disabled) by a different parameter in the
1589 | "DECSET CSI ? Pm h " or "DECRST CSI ? Pm l " control sequence.
1590 | 
1591 | Manifest constants for the parameter values are defined in xcharmouse.h
1592 | as follows:
1593 | 
1594 |      #define SET_X10_MOUSE               9
1595 |      #define SET_VT200_MOUSE             1000
1596 |      #define SET_VT200_HIGHLIGHT_MOUSE   1001
1597 |      #define SET_BTN_EVENT_MOUSE         1002
1598 |      #define SET_ANY_EVENT_MOUSE         1003
1599 | 
1600 |      #define SET_FOCUS_EVENT_MOUSE       1004
1601 | 
1602 |      #define SET_EXT_MODE_MOUSE          1005
1603 |      #define SET_SGR_EXT_MODE_MOUSE      1006
1604 |      #define SET_URXVT_EXT_MODE_MOUSE    1015
1605 | 
1606 |      #define SET_ALTERNATE_SCROLL        1007
1607 | 
1608 | The motion reporting modes are strictly xterm extensions, and are not
1609 | part of any standard, though they are analogous to the DEC VT200 DECELR
1610 | locator reports.
1611 | 
1612 | Normally, parameters (such as pointer position and button number) for
1613 | all mouse tracking escape sequences generated by xterm encode numeric
1614 | parameters in a single character as value+32.  For example, !  specifies
1615 | the value 1.  The upper left character position on the terminal is
1616 | denoted as 1,1.  This scheme dates back to X10, though the normal mouse-
1617 | tracking (from X11) is more elaborate.
1618 | 
1619 |

X10 compatbility mode

1620 |
X10 compatibility mode sends an escape sequence only on button press,
1621 | encoding the location and the mouse button pressed.  It is enabled by
1622 | specifying parameter 9 to DECSET.  On button press, xterm sends CSI M
1623 | CbCxCy (6 characters).
1624 | o Cb is button-1.
1625 | o Cx and Cy are the x and y coordinates of the mouse when the button was
1626 |   pressed.
1627 | 
1628 |

Normal tracking mode

1629 |
Normal tracking mode sends an escape sequence on both button press and
1630 | release.  Modifier key (shift, ctrl, meta) information is also sent.  It
1631 | is enabled by specifying parameter 1000 to DECSET.  On button press or
1632 | release, xterm sends CSI M CbCxCy.
1633 | o The low two bits of Cb encode button information: 0=MB1 pressed, 1=MB2
1634 |   pressed, 2=MB3 pressed, 3=release.
1635 | o The next three bits encode the modifiers which were down when the but-
1636 |   ton was pressed and are added together:  4=Shift, 8=Meta, 16=Control.
1637 |   Note however that the shift and control bits are normally unavailable
1638 |   because xterm uses the control modifier with mouse for popup menus,
1639 |   and the shift modifier is used in the default translations for button
1640 |   events.  The Meta modifier recognized by xterm is the mod1 mask, and
1641 |   is not necessarily the "Meta" key (see xmodmap).
1642 | o Cx and Cy are the x and y coordinates of the mouse event, encoded as
1643 |   in X10 mode.
1644 | 
1645 |

Wheel mice

1646 |
Wheel mice may return buttons 4 and 5.  Those buttons are represented by
1647 | the same event codes as buttons 1 and 2 respectively, except that 64 is
1648 | added to the event code.  Release events for the wheel buttons are not
1649 | reported.  By default, the wheel mouse events are translated to scroll-
1650 | back and scroll-forw actions.  Those actions normally scroll the whole
1651 | window, as if the scrollbar was used.  However if Alternate Scroll mode
1652 | is set, then cursor up/down controls are sent when the terminal is dis-
1653 | playing the alternate screen.  The initial state of Alternate Scroll
1654 | mode is set using the alternateScroll resource.
1655 | 
1656 |

Highlight tracking

1657 |
Mouse highlight tracking notifies a program of a button press, receives
1658 | a range of lines from the program, highlights the region covered by the
1659 | mouse within that range until button release, and then sends the program
1660 | the release coordinates.  It is enabled by specifying parameter 1001 to
1661 | DECSET.  Highlighting is performed only for button 1, though other but-
1662 | ton events can be received.
1663 | 
1664 | Warning: use of this mode requires a cooperating program or it will hang
1665 | xterm.
1666 | 
1667 | On button press, the same information as for normal tracking is gener-
1668 | ated; xterm then waits for the program to send mouse tracking informa-
1669 | tion.  All X events are ignored until the proper escape sequence is
1670 | received from the pty: CSI Ps ; Ps ; Ps ; Ps ; Ps T .  The parameters
1671 | are func, startx, starty, firstrow, and lastrow.  func is non-zero to
1672 | initiate highlight tracking and zero to abort.  startx and starty give
1673 | the starting x and y location for the highlighted region.  The ending
1674 | location tracks the mouse, but will never be above row firstrow and will
1675 | always be above row lastrow.  (The top of the screen is row 1.)  When
1676 | the button is released, xterm reports the ending position one of two
1677 | ways:
1678 | o if the start and end coordinates are the same locations:
1679 |   CSI t CxCy.
1680 | o otherwise:
1681 |   CSI T CxCyCxCyCxCy.
1682 |   The parameters are startx, starty, endx, endy, mousex, and mousey.
1683 |   - startx, starty, endx, and endy give the starting and ending charac-
1684 |     ter positions of the region.
1685 |   - mousex and mousey give the location of the mouse at button up, which
1686 |     may not be over a character.
1687 | 
1688 |

Button-event tracking

1689 |
Button-event tracking is essentially the same as normal tracking, but
1690 | xterm also reports button-motion events.  Motion events are reported
1691 | only if the mouse pointer has moved to a different character cell.  It
1692 | is enabled by specifying parameter 1002 to DECSET.  On button press or
1693 | release, xterm sends the same codes used by normal tracking mode.
1694 | o On button-motion events, xterm adds 32 to the event code (the third
1695 |   character, Cb).
1696 | o The other bits of the event code specify button and modifier keys as
1697 |   in normal mode.  For example, motion into cell x,y with button 1 down
1698 |   is reported as CSI M @ CxCy.  ( @  = 32 + 0 (button 1) + 32 (motion
1699 |   indicator) ).  Similarly, motion with button 3 down is reported as CSI
1700 |   M B CxCy.  ( B  = 32 + 2 (button 3) + 32 (motion indicator) ).
1701 | 
1702 |

Any-event tracking

1703 |
Any-event mode is the same as button-event mode, except that all motion
1704 | events are reported, even if no mouse button is down.  It is enabled by
1705 | specifying 1003 to DECSET.
1706 | 
1707 |

FocusIn/FocusOut

1708 |
FocusIn/FocusOut can be combined with any of the mouse events since it
1709 | uses a different protocol.  When set, it causes xterm to send CSI I
1710 | when the terminal gains focus, and CSI O  when it loses focus.
1711 | 
1712 |

Extended coordinates

1713 |
The original X10 mouse protocol limits the Cx and Cy ordinates to 223
1714 | (=255 - 32).  Xterm supports more than one scheme for extending this
1715 | range, by changing the protocol encoding:
1716 | UTF-8 (1005)
1717 |           This enables UTF-8 encoding for Cx and Cy under all tracking
1718 |           modes, expanding the maximum encodable position from 223 to
1719 |           2015.  For positions less than 95, the resulting output is
1720 |           identical under both modes.  Under extended mouse mode, posi-
1721 |           tions greater than 95 generate "extra" bytes which will con-
1722 |           fuse applications which do not treat their input as a UTF-8
1723 |           stream.  Likewise, Cb will be UTF-8 encoded, to reduce confu-
1724 |           sion with wheel mouse events.
1725 |           Under normal mouse mode, positions outside (160,94) result in
1726 |           byte pairs which can be interpreted as a single UTF-8 charac-
1727 |           ter; applications which do treat their input as UTF-8 will
1728 |           almost certainly be confused unless extended mouse mode is
1729 |           active.
1730 |           This scheme has the drawback that the encoded coordinates will
1731 |           not pass through luit unchanged, e.g., for locales using non-
1732 |           UTF-8 encoding.
1733 | SGR (1006)
1734 |           The normal mouse response is altered to use CSI < followed by
1735 |           semicolon-separated encoded button value, the Cx and Cy ordi-
1736 |           nates and a final character which is M  for button press and m
1737 |           for button release.
1738 |           o The encoded button value in this case does not add 32 since
1739 |             that was useful only in the X10 scheme for ensuring that the
1740 |             byte containing the button value is a printable code.
1741 |           o The modifiers are encoded in the same way.
1742 |           o A different final character is used for button release to
1743 |             resolve the X10 ambiguity regarding which button was
1744 |             released.
1745 |           The highlight tracking responses are also modified to an SGR-
1746 |           like format, using the same SGR-style scheme and button-encod-
1747 |           ings.
1748 | URXVT (1015)
1749 |           The normal mouse response is altered to use CSI followed by
1750 |           semicolon-separated encoded button value, the Cx and Cy ordi-
1751 |           nates and final character M .
1752 |           This uses the same button encoding as X10, but printing it as
1753 |           a decimal integer rather than as a single byte.
1754 |           However, CSI M  can be mistaken for DL (delete lines), while
1755 |           the highlight tracking CSI T  can be mistaken for SD (scroll
1756 |           down), and the Window manipulation controls.  For these rea-
1757 |           sons, the 1015 control is not recommended; it is not an
1758 |           improvement over 1005.
1759 | 
1760 | 
1761 |

Sixel Graphics

1762 |
If xterm is configured as VT240, VT241, VT330, VT340 or VT382 using the
1763 | decTerminalID resource, it supports Sixel Graphics controls, a palleted
1764 | bitmap graphics system using sets of six vertical pixels as the basic
1765 | element.
1766 | 
1767 | CSI Ps c  xterm responds to Send Device Attributes (Primary DA) with
1768 |           these additional codes:
1769 |             Ps = 4  -> Sixel graphics.
1770 | CSI ? Pm h
1771 |           xterm has these additional private Set Mode values:
1772 |             Ps = 8 0  -> Sixel scrolling.
1773 |             Ps = 1 0 7 0  -> use private color registers for each
1774 |           graphic.
1775 |             Ps = 8 4 5 2  -> Sixel scrolling leaves cursor to right of
1776 |           graphic.
1777 | DCS Pa; Pb; Ph q  Ps..Ps ST
1778 |           See
1779 | 
1780 |                http://vt100.net/docs/vt3xx-gp/chapter14.html
1781 | 
1782 |           The sixel data device control string has three positional
1783 |           parameters, following the q  with sixel data.
1784 |             Pa -> pixel aspect ratio
1785 |             Pb -> background color option
1786 |             Ph -> horizontal grid size (ignored).
1787 |             Ps -> sixel data
1788 | 
1789 | 
1790 |

ReGIS Graphics

1791 |
If xterm is configured as VT125, VT240, VT241, VT330 or VT340 using the
1792 | decTerminalID resource, it supports Remote Graphic Instruction Set, a
1793 | graphics description language.
1794 | 
1795 | CSI Ps c  xterm responds to Send Device Attributes (Primary DA) with
1796 |           these additional codes:
1797 |             Ps = 3  -> ReGIS graphics.
1798 | CSI ? Pm h
1799 |           xterm has these additional private Set Mode values:
1800 |             Ps = 1 0 7 0  -> use private color registers for each
1801 |           graphic.
1802 | DCS Pm p Pr..Pr ST
1803 |           See
1804 | 
1805 |                http://vt100.net/docs/vt3xx-gp/chapter1.html
1806 | 
1807 |           The ReGIS data device control string has one positional param-
1808 |           eter with four possible values:
1809 |             Pm = 0 -> resume command, use fullscreen mode
1810 |             Pm = 1 -> start new command, use fullscreen mode
1811 |             Pm = 2 -> resume command, use command display mode
1812 |             Pm = 3 -> start new command, use command display mode
1813 | 
1814 | 
1815 |

Tektronix 4014 Mode

1816 |
Most of these sequences are standard Tektronix 4014 control sequences.
1817 | Graph mode supports the 12-bit addressing of the Tektronix 4014.  The
1818 | major features missing are the write-through and defocused modes.  This
1819 | document does not describe the commands used in the various Tektronix
1820 | plotting modes but does describe the commands to switch modes.
1821 | 
1822 | BEL       Bell (Ctrl-G).
1823 | BS        Backspace (Ctrl-H).
1824 | TAB       Horizontal Tab (Ctrl-I).
1825 | LF        Line Feed or New Line (Ctrl-J).
1826 | VT        Cursor up (Ctrl-K).
1827 | FF        Form Feed or New Page (Ctrl-L).
1828 | CR        Carriage Return (Ctrl-M).
1829 | ESC ETX   Switch to VT100 Mode (ESC  Ctrl-C).
1830 | ESC ENQ   Return Terminal Status (ESC  Ctrl-E).
1831 | ESC FF    PAGE (Clear Screen) (ESC  Ctrl-L).
1832 | ESC SO    Begin 4015 APL mode (ESC  Ctrl-N).  (This is ignored by
1833 |           xterm).
1834 | ESC SI    End 4015 APL mode (ESC  Ctrl-O).  (This is ignored by xterm).
1835 | ESC ETB   COPY (Save Tektronix Codes to file COPYyyyy-mm-dd.hh:mm:ss).
1836 |             ETB  (end transmission block) is the same as Ctrl-W.
1837 | ESC CAN   Bypass Condition (ESC  Ctrl-X).
1838 | ESC SUB   GIN mode (ESC  Ctrl-Z).
1839 | ESC FS    Special Point Plot Mode (ESC  Ctrl-\).
1840 | ESC 8     Select Large Character Set.
1841 | ESC 9     Select #2 Character Set.
1842 | ESC :     Select #3 Character Set.
1843 | ESC ;     Select Small Character Set.
1844 | OSC Ps ; Pt BEL
1845 |           Set Text Parameters of VT window.
1846 |             Ps = 0  -> Change Icon Name and Window Title to Pt.
1847 |             Ps = 1  -> Change Icon Name to Pt.
1848 |             Ps = 2  -> Change Window Title to Pt.
1849 |             Ps = 4 6  -> Change Log File to Pt.  (This is normally dis-
1850 |           abled by a compile-time option).
1851 | ESC `     Normal Z Axis and Normal (solid) Vectors.
1852 | ESC a     Normal Z Axis and Dotted Line Vectors.
1853 | ESC b     Normal Z Axis and Dot-Dashed Vectors.
1854 | ESC c     Normal Z Axis and Short-Dashed Vectors.
1855 | ESC d     Normal Z Axis and Long-Dashed Vectors.
1856 | ESC h     Defocused Z Axis and Normal (solid) Vectors.
1857 | ESC i     Defocused Z Axis and Dotted Line Vectors.
1858 | ESC j     Defocused Z Axis and Dot-Dashed Vectors.
1859 | ESC k     Defocused Z Axis and Short-Dashed Vectors.
1860 | ESC l     Defocused Z Axis and Long-Dashed Vectors.
1861 | ESC p     Write-Thru Mode and Normal (solid) Vectors.
1862 | ESC q     Write-Thru Mode and Dotted Line Vectors.
1863 | ESC r     Write-Thru Mode and Dot-Dashed Vectors.
1864 | ESC s     Write-Thru Mode and Short-Dashed Vectors.
1865 | ESC t     Write-Thru Mode and Long-Dashed Vectors.
1866 | FS        Point Plot Mode (Ctrl-\).
1867 | GS        Graph Mode (Ctrl-]).
1868 | RS        Incremental Plot Mode (Ctrl-^).
1869 | US        Alpha Mode (Ctrl-_).
1870 | 
1871 | 
1872 |

VT52 Mode

1873 |
Parameters for cursor movement are at the end of the ESC Y  escape
1874 | sequence.  Each ordinate is encoded in a single character as value+32.
1875 | For example, !  is 1.  The screen coordinate system is 0-based.
1876 | 
1877 | ESC A     Cursor up.
1878 | ESC B     Cursor down.
1879 | ESC C     Cursor right.
1880 | ESC D     Cursor left.
1881 | ESC F     Enter graphics mode.
1882 | ESC G     Exit graphics mode.
1883 | ESC H     Move the cursor to the home position.
1884 | ESC I     Reverse line feed.
1885 | ESC J     Erase from the cursor to the end of the screen.
1886 | ESC K     Erase from the cursor to the end of the line.
1887 | ESC Y Ps Ps
1888 |           Move the cursor to given row and column.
1889 | ESC Z     Identify.
1890 |             -> ESC  /  Z  ("I am a VT52.").
1891 | ESC =     Enter alternate keypad mode.
1892 | ESC >     Exit alternate keypad mode.
1893 | ESC <     Exit VT52 mode (Enter VT100 mode).
1894 | 
1895 | 1933 | 1934 | 1935 | -------------------------------------------------------------------------------- /doc/ctlseqs(ms)_files/man2html.css: -------------------------------------------------------------------------------- 1 | body { 2 | /* Verdana, - too wide */ 3 | /* Lucida Grande, - cluttered */ 4 | /* Droid Serif - ? */ 5 | /* Optima, - maybe - seems light */ 6 | /* Verdana, - large */ 7 | /* Tahoma, - not bad */ 8 | font-family: Tahoma, Georgia, "Times New Roman", Times, serif; 9 | } 10 | 11 | h1,h2,h3,h4 { 12 | font-family: Helvetica, Geneva, Arial, SunSans-Regular, sans-serif; 13 | margin: 0px; 14 | line-height: 100%; 15 | } 16 | 17 | h3,h4 { 18 | margin-left: 30px; 19 | } 20 | 21 | pre, 22 | code, 23 | kbd, 24 | samp, 25 | tt{ 26 | /* font-family:monospace,monospace; */ 27 | font-family: "Andale Mono", "Monotype.com", monospace; 28 | font-size:1em; 29 | padding: 0; 30 | margin: 0; 31 | padding: 0; 32 | } 33 | 34 | *.no-header { 35 | visibility:hidden; 36 | overflow:hidden; 37 | float:left; 38 | clear: both; 39 | width: 1px; 40 | height: 1px; 41 | } 42 | 43 | pre { 44 | white-space: pre-wrap; /* CSS 3 */ 45 | white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ 46 | white-space: -pre-wrap; /* Opera 4-6 */ 47 | white-space: -o-pre-wrap; /* Opera 7 */ 48 | word-wrap: break-word; /* Internet Explorer 5.5+ */ 49 | } 50 | -------------------------------------------------------------------------------- /gui/__init__.py: -------------------------------------------------------------------------------- 1 | from .terminal import TerminalWidget 2 | -------------------------------------------------------------------------------- /gui/font.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtGui import QFont, QFontMetricsF 2 | 3 | class MonoFont: 4 | def __init__(self, name, size): 5 | self.font = QFont(name, size) 6 | self.font.setKerning(False) 7 | self.ascent = int(QFontMetricsF(self.font).ascent()) 8 | self.charWidth = QFontMetricsF(self.font).width("X") 9 | self.charHeight = int(QFontMetricsF(self.font).height()) 10 | self.charOffset = 0 # can introduce extra linespacing here 11 | 12 | self.bold = QFont(self.font) 13 | self.bold.setBold(True) 14 | 15 | self.under = QFont(self.font) 16 | self.under.setUnderline(True) 17 | 18 | # align character width properly 19 | if self.charWidth % 1.0 < 0.5: 20 | adjust = -(self.charWidth % 1.0) 21 | else: 22 | adjust = 1.0 - (self.charWidth % 1.0) 23 | 24 | self.charWidth += adjust 25 | self.font.setLetterSpacing(QFont.AbsoluteSpacing, adjust) 26 | self.bold.setLetterSpacing(QFont.AbsoluteSpacing, adjust) 27 | self.under.setLetterSpacing(QFont.AbsoluteSpacing, adjust) 28 | 29 | 30 | -------------------------------------------------------------------------------- /gui/terminal.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import * 2 | from PyQt5.QtGui import * 3 | from PyQt5.QtWidgets import QAbstractScrollArea, QFrame 4 | 5 | from . import font 6 | from terminal import emulator, process, screen, rendition 7 | 8 | class TerminalWidget(QAbstractScrollArea): 9 | def __init__(self, parent): 10 | super(TerminalWidget, self).__init__(parent) 11 | 12 | self.setFrameStyle(QFrame.NoFrame) 13 | self.historySize = 0 14 | self.cols, self.rows = 80, 25 15 | 16 | cmd = "/bin/bash" 17 | self.process = process.TerminalProcessThread(self.rows, self.cols, cmd) 18 | self.process.emulator.set_update_callback(self.update_screen) 19 | self.process.emulator.set_data_callback(self.update_data) 20 | self.process.emulator.set_title_callback(self.update_title) 21 | self.process.start() 22 | 23 | self.font = font.MonoFont("Monospace", 14) 24 | 25 | self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) 26 | self.setViewportMargins(2, 2, 2, 2) 27 | 28 | p = QPalette(self.palette()) 29 | p.setColor(QPalette.Background, Qt.black) 30 | self.setPalette(p) 31 | self.setAutoFillBackground(True) 32 | 33 | # XXX platform dependent 34 | self.ctrl = Qt.ControlModifier 35 | 36 | self.cursorRow = 0 37 | self.blink = False 38 | self.cursorBlink = QTimer() 39 | self.cursorBlink.setInterval(500) 40 | self.cursorBlink.setSingleShot(False) 41 | self.cursorBlink.timeout.connect(self.cursorBlinkEvent) 42 | self.cursorBlink.start() 43 | self.caretVisible = False 44 | 45 | def renderCursor(self): 46 | self.viewport().update(0, self.cursorRow * self.font.charHeight, 47 | self.viewport().size().width(), self.font.charHeight) 48 | self.cursorRow = self.process.emulator.cursor.y 49 | self.viewport().update(0, self.cursorRow * self.font.charHeight, 50 | self.viewport().size().width(), self.font.charHeight) 51 | 52 | def cursorBlinkEvent(self): 53 | self.blink = not self.blink 54 | self.renderCursor() 55 | 56 | def update_screen(self): 57 | self.viewport().update() 58 | 59 | def update_title(self, title): 60 | pass 61 | 62 | def update_data(self, data): 63 | pass 64 | 65 | def event(self, event): 66 | t = event.type() 67 | if t == QEvent.KeyPress and (event.key() == Qt.Key_Tab or event.key() == Qt.Key_Backtab): 68 | self.keyPressEvent(event) 69 | return True 70 | if t == QEvent.ShortcutOverride and event.key() >= Qt.Key_A and event.key() <= Qt.Key_Z: 71 | if (event.modifiers() & (self.ctrl | Qt.AltModifier | Qt.ShiftModifier)) == self.ctrl: 72 | event.accept() 73 | return True 74 | return super(TerminalWidget, self).event(event) 75 | 76 | def getKeyModifierString(self, mod): 77 | if (mod & (self.ctrl | Qt.ShiftModifier | Qt.AltModifier)) == (Qt.ShiftModifier): 78 | return ";2" 79 | if (mod & (self.ctrl | Qt.ShiftModifier | Qt.AltModifier)) == (Qt.AltModifier): 80 | return ";3" 81 | if (mod & (self.ctrl | Qt.ShiftModifier | Qt.AltModifier)) == (Qt.ShiftModifier | Qt.AltModifier): 82 | return ";4" 83 | if (mod & (self.ctrl | Qt.ShiftModifier | Qt.AltModifier)) == (self.ctrl): 84 | return ";5" 85 | if (mod & (self.ctrl | Qt.ShiftModifier | Qt.AltModifier)) == (Qt.ShiftModifier | self.ctrl): 86 | return ";6" 87 | if (mod & (self.ctrl | Qt.ShiftModifier | Qt.AltModifier)) == (Qt.AltModifier | self.ctrl): 88 | return ";7" 89 | if (mod & (self.ctrl | Qt.ShiftModifier | Qt.AltModifier)) == (Qt.ShiftModifier | Qt.AltModifier | self.ctrl): 90 | return ";8" 91 | return "" 92 | 93 | def keyPressEvent(self, event): 94 | key_data = { 95 | Qt.Key_F5:"15", 96 | Qt.Key_F6:"17", 97 | Qt.Key_F7:"18", 98 | Qt.Key_F8:"19", 99 | Qt.Key_F9:"20", 100 | Qt.Key_F10:"21", 101 | Qt.Key_F11:"23", 102 | Qt.Key_F12:"24", 103 | Qt.Key_Delete:"3", 104 | } 105 | arrow_keys = { 106 | Qt.Key_Up:"A", 107 | Qt.Key_Down:"B", 108 | Qt.Key_Right:"C", 109 | Qt.Key_Left:"D" 110 | } 111 | ctrl = self.ctrl 112 | alt = Qt.AltModifier 113 | shift = Qt.ShiftModifier 114 | mods = event.modifiers() 115 | modstr = self.getKeyModifierString(mods) 116 | key = event.key() 117 | text = event.text() 118 | data = None 119 | if key in arrow_keys: 120 | if mods & (ctrl|alt|shift): 121 | data = "\033[%s%c" % (modstr, arrow_keys[key]) 122 | else: 123 | data = "\033[%c" % arrow_keys[key] 124 | #XXX if cursor_keys option set 125 | 126 | if key in key_data: 127 | data = "\033[%s%s~" % (key_data[key], modstr) 128 | elif key == Qt.Key_Backspace: 129 | data = "\x7f" 130 | elif key == Qt.Key_Tab: 131 | data = "\t" 132 | elif key == Qt.Key_Backtab: 133 | data = "\033[Z" 134 | elif key >= Qt.Key_A and key <= Qt.Key_Z and (mods & (ctrl|alt|shift))==ctrl: 135 | data = "%c" % (chr(key - Qt.Key_A) + 1) 136 | elif len(text) > 0: 137 | data = event.text() 138 | if len(text) == 1 and text >= ' ' and text <= '~' and mods & alt: 139 | data = "\033" + data 140 | 141 | if not data: 142 | return 143 | 144 | self.process.input(data) 145 | #self.verticalScrollBar().setValue(0) 146 | 147 | def mousePressEvent(self, event): 148 | pass 149 | 150 | def mouseMoveEvent(self, event): 151 | pass 152 | 153 | def mouseReleaseEvent(self, event): 154 | pass 155 | 156 | def mouseDoubleClickEvent(self, event): 157 | pass 158 | 159 | def focusInEvent(self, event): 160 | self.caretVisible = True 161 | self.blink = True 162 | self.cursorBlink.stop() 163 | self.cursorBlink.start() 164 | self.renderCursor() 165 | 166 | def focusOutEvent(self, event): 167 | self.caretVisible = False 168 | self.renderCursor() 169 | 170 | def get_colors(self, gfx): 171 | fg, bg = rendition.get_colors(gfx) 172 | fg = QColor(*fg) if fg else Qt.white 173 | bg = QColor(*bg) if bg else Qt.black 174 | return fg, bg 175 | 176 | def paintRow(self, y, row, rowgfx): 177 | p = QPainter(self.viewport()) 178 | p.setFont(self.font.font) 179 | 180 | bg = Qt.black 181 | fg = Qt.white 182 | length = 0 183 | current = None 184 | x = 0 185 | for i in range(0, self.cols): 186 | gfx = rowgfx[i] 187 | 188 | if self.blink and self.caretVisible and self.process.emulator.cursor.visible and \ 189 | self.process.emulator.cursor.y == y and self.process.emulator.cursor.x == i: 190 | gfx ^= screen.GFX_INV 191 | 192 | 193 | if gfx != current: 194 | if length > 0: 195 | p.fillRect(x * self.font.charWidth, y * self.font.charHeight, 196 | length * self.font.charWidth, self.font.charHeight, bg) 197 | x = x + length 198 | length = 0 199 | current = gfx 200 | fg, bg = self.get_colors(gfx) 201 | length = length + 1 202 | 203 | if length > 0: 204 | p.fillRect(x * self.font.charWidth, y * self.font.charHeight, 205 | length * self.font.charWidth, self.font.charHeight, bg) 206 | 207 | length = 0 208 | current = None 209 | x = 0 210 | for i in range(0, self.cols): 211 | gfx = rowgfx[i] 212 | if gfx != current: 213 | if length > 0: 214 | line = "".join(row[x:i]) 215 | p.setPen(fg) 216 | p.drawText(x * self.font.charWidth, y * self.font.charHeight + self.font.charOffset + self.font.ascent, line) 217 | if gfx & screen.GFX_BOLD: 218 | p.setFont(self.font.bold) 219 | elif gfx & screen.GFX_UL: 220 | p.setFont(self.font.under) 221 | else: 222 | p.setFont(self.font.font) 223 | x = x + length 224 | length = 0 225 | current = gfx 226 | fg, bg = self.get_colors(gfx) 227 | length = length + 1 228 | 229 | if length > 0: 230 | line = "".join(row[x:i]) 231 | p.setPen(fg) 232 | p.drawText(x * self.font.charWidth, y * self.font.charHeight + self.font.charOffset + self.font.ascent, line) 233 | 234 | if not self.caretVisible and self.process.emulator.cursor.y == y: 235 | fg, bg = self.get_colors(rowgfx[self.process.emulator.cursor.x]) 236 | p.setPen(fg) 237 | p.drawRect(x * self.font.charWidth, y * self.font.charHeight, self.font.charWidth -1, self.font.charHeight - 1) 238 | 239 | 240 | def paintEvent(self, event): 241 | p = QPainter(self.viewport()) 242 | p.setFont(self.font.font) 243 | p.fillRect(event.rect(), Qt.black) 244 | 245 | yofs = self.verticalScrollBar().value() 246 | y = event.rect().y() 247 | bot = y + event.rect().height() 248 | top = int(y / self.font.charHeight) 249 | bot = int((bot / self.font.charHeight) + 1) 250 | 251 | screen = self.process.emulator.screen 252 | for y in range(0, self.rows): 253 | self.paintRow(y, screen.cells[y], screen.gfx[y]) 254 | 255 | def resizeEvent(self, event): 256 | sz = event.size() 257 | self.resize(sz.width(), sz.height()) 258 | 259 | def resize(self, w, h): 260 | self.cols = int(w / self.font.charWidth) 261 | self.rows = int(h / self.font.charHeight) 262 | #self.verticalScrollBar().setPageStep(self.rows) 263 | #self.verticalScrollBar().setRange(-self.historySize, 0) 264 | self.process.resize(self.rows, self.cols) 265 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | from PyQt5.QtCore import * 6 | from PyQt5.QtGui import * 7 | from PyQt5.QtWidgets import QApplication, QMainWindow, QMenu, QTabWidget 8 | 9 | import terminal 10 | import gui 11 | 12 | class Main(QMainWindow): 13 | def __init__(self, parent=None): 14 | super(Main, self).__init__(parent) 15 | self.setWindowTitle("blabla") 16 | 17 | self.fileMenu = QMenu("&File", self) 18 | self.menuBar().addMenu(self.fileMenu) 19 | 20 | self.tabs = QTabWidget(self) 21 | self.tabs.setDocumentMode(True) 22 | self.tabs.setTabsClosable(True) 23 | self.tabs.setMovable(True) 24 | 25 | frame = gui.TerminalWidget(self) 26 | self.tabs.addTab(frame, 'Terminal #1') 27 | frame = gui.TerminalWidget(self) 28 | self.tabs.addTab(frame, 'Terminal #2') 29 | frame = gui.TerminalWidget(self) 30 | self.tabs.addTab(frame, 'Terminal #3') 31 | 32 | self.setCentralWidget(self.tabs) 33 | 34 | self.show() 35 | 36 | def sizeHint(self): 37 | return QSize(800, 600) 38 | 39 | if __name__ == "__main__": 40 | app = QApplication(sys.argv) 41 | main = Main() 42 | app.exec_() 43 | -------------------------------------------------------------------------------- /src/gui/__init__.py: -------------------------------------------------------------------------------- 1 | from .terminal import TerminalWidget 2 | -------------------------------------------------------------------------------- /src/gui/font.py: -------------------------------------------------------------------------------- 1 | from PySide.QtGui import QFont, QFontMetricsF 2 | 3 | class MonoFont: 4 | def __init__(self, name, size): 5 | self.font = QFont(name, size) 6 | self.font.setKerning(False) 7 | self.ascent = int(QFontMetricsF(self.font).ascent()) 8 | self.charWidth = QFontMetricsF(self.font).width("X") 9 | self.charHeight = int(QFontMetricsF(self.font).height()) 10 | self.charOffset = 0 # can introduce extra linespacing here 11 | 12 | self.bold = QFont(self.font) 13 | self.bold.setBold(True) 14 | 15 | self.under = QFont(self.font) 16 | self.under.setUnderline(True) 17 | 18 | # align character width properly 19 | if self.charWidth % 1.0 < 0.5: 20 | adjust = -(self.charWidth % 1.0) 21 | else: 22 | adjust = 1.0 - (self.charWidth % 1.0) 23 | 24 | self.charWidth += adjust 25 | self.font.setLetterSpacing(QFont.AbsoluteSpacing, adjust) 26 | self.bold.setLetterSpacing(QFont.AbsoluteSpacing, adjust) 27 | self.under.setLetterSpacing(QFont.AbsoluteSpacing, adjust) 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/gui/terminal.py: -------------------------------------------------------------------------------- 1 | from PySide.QtCore import * 2 | from PySide.QtGui import * 3 | 4 | from . import font 5 | from terminal import emulator, screen, rendition 6 | 7 | 8 | class TerminalWidget(QWidget): 9 | def __init__(self, parent, cmd="/bin/sh"): 10 | QWidget.__init__(self, parent) 11 | layout = QBoxLayout(QBoxLayout.TopToBottom) 12 | self.setLayout(layout) 13 | self.w = TerminalRenderWidget(self, cmd) 14 | layout.addWidget(self.w) 15 | self.b = QStatusBar() 16 | layout.addWidget(self.b) 17 | l = QLabel("wut") 18 | #l.setPixmap(QPixmap("exit.png")) 19 | self.b.addPermanentWidget(l) 20 | layout.setContentsMargins(1, 1, 1, 1) 21 | 22 | def update_title(self, title): 23 | print("!!!%s"% title) 24 | return 25 | self.b.showMessage(title) 26 | 27 | class TerminalRenderWidget(QAbstractScrollArea): 28 | 29 | def __init__(self, parent=None, cmd="/bin/sh"): 30 | super(TerminalRenderWidget, self).__init__(parent) 31 | 32 | self.setFrameStyle(QFrame.NoFrame) 33 | self.historySize = 0 34 | 35 | self.rows, self.cols = 25, 80 36 | self.emulator = emulator.Emulator(self.rows, self.cols) 37 | self.emulator.set_update_callback(self.update_screen) 38 | self.emulator.set_title_callback(parent.update_title) 39 | self.emulator.set_data_callback(self.update_data) 40 | self.terminal_id = QApplication.instance().td.startTerminal("/bin/sh", [], self) 41 | 42 | 43 | self.font = font.MonoFont("Monospace", 10) 44 | 45 | self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) 46 | self.setViewportMargins(2, 2, 2, 2) 47 | 48 | p = QPalette(self.palette()) 49 | p.setColor(QPalette.Background, Qt.black) 50 | self.setPalette(p) 51 | self.setAutoFillBackground(True) 52 | 53 | # XXX platform dependent 54 | self.ctrl = Qt.ControlModifier 55 | 56 | self.cursorRow = 0 57 | self.blink = False 58 | self.cursorBlink = QTimer() 59 | self.cursorBlink.setInterval(500) 60 | self.cursorBlink.setSingleShot(False) 61 | self.cursorBlink.timeout.connect(self.cursorBlinkEvent) 62 | self.cursorBlink.start() 63 | self.caretVisible = False 64 | self.blink = False 65 | 66 | def exited(self, ok): 67 | print("process exited!!?") 68 | 69 | def renderCursor(self): 70 | self.viewport().update(0, self.cursorRow * self.font.charHeight, 71 | self.viewport().size().width(), self.font.charHeight) 72 | self.cursorRow = self.emulator.cursor.y 73 | self.viewport().update(0, self.cursorRow * self.font.charHeight, 74 | self.viewport().size().width(), self.font.charHeight) 75 | 76 | def cursorBlinkEvent(self): 77 | self.blink = not self.blink 78 | self.renderCursor() 79 | 80 | def update_screen(self): 81 | self.viewport().update() 82 | 83 | def update_data(self, data): 84 | pass 85 | 86 | def event(self, event): 87 | t = event.type() 88 | if t == QEvent.KeyPress and (event.key() == Qt.Key_Tab or event.key() == Qt.Key_Backtab): 89 | self.keyPressEvent(event) 90 | return True 91 | if t == QEvent.ShortcutOverride and event.key() >= Qt.Key_A and event.key() <= Qt.Key_Z: 92 | if (event.modifiers() & (self.ctrl | Qt.AltModifier | Qt.ShiftModifier)) == self.ctrl: 93 | event.accept() 94 | return True 95 | return super(TerminalRenderWidget, self).event(event) 96 | 97 | def getKeyModifierString(self, mod): 98 | if (mod & (self.ctrl | Qt.ShiftModifier | Qt.AltModifier)) == (Qt.ShiftModifier): 99 | return ";2" 100 | if (mod & (self.ctrl | Qt.ShiftModifier | Qt.AltModifier)) == (Qt.AltModifier): 101 | return ";3" 102 | if (mod & (self.ctrl | Qt.ShiftModifier | Qt.AltModifier)) == (Qt.ShiftModifier | Qt.AltModifier): 103 | return ";4" 104 | if (mod & (self.ctrl | Qt.ShiftModifier | Qt.AltModifier)) == (self.ctrl): 105 | return ";5" 106 | if (mod & (self.ctrl | Qt.ShiftModifier | Qt.AltModifier)) == (Qt.ShiftModifier | self.ctrl): 107 | return ";6" 108 | if (mod & (self.ctrl | Qt.ShiftModifier | Qt.AltModifier)) == (Qt.AltModifier | self.ctrl): 109 | return ";7" 110 | if (mod & (self.ctrl | Qt.ShiftModifier | Qt.AltModifier)) == (Qt.ShiftModifier | Qt.AltModifier | self.ctrl): 111 | return ";8" 112 | return "" 113 | 114 | def keyPressEvent(self, event): 115 | key_data = { 116 | Qt.Key_F5:"15", 117 | Qt.Key_F6:"17", 118 | Qt.Key_F7:"18", 119 | Qt.Key_F8:"19", 120 | Qt.Key_F9:"20", 121 | Qt.Key_F10:"21", 122 | Qt.Key_F11:"23", 123 | Qt.Key_F12:"24", 124 | Qt.Key_Delete:"3", 125 | } 126 | arrow_keys = { 127 | Qt.Key_Up:"A", 128 | Qt.Key_Down:"B", 129 | Qt.Key_Right:"C", 130 | Qt.Key_Left:"D" 131 | } 132 | ctrl = self.ctrl 133 | alt = Qt.AltModifier 134 | shift = Qt.ShiftModifier 135 | mods = event.modifiers() 136 | modstr = self.getKeyModifierString(mods) 137 | key = event.key() 138 | text = event.text() 139 | data = None 140 | if key in arrow_keys: 141 | if mods & (ctrl|alt|shift): 142 | data = "\033[%s%c" % (modstr, arrow_keys[key]) 143 | else: 144 | data = "\033[%c" % arrow_keys[key] 145 | #XXX if cursor_keys option set 146 | 147 | if key in key_data: 148 | data = "\033[%s%s~" % (key_data[key], modstr) 149 | elif key == Qt.Key_Backspace: 150 | data = "\x7f" 151 | elif key == Qt.Key_Tab: 152 | data = "\t" 153 | elif key == Qt.Key_Backtab: 154 | data = "\033[Z" 155 | elif key >= Qt.Key_A and key <= Qt.Key_Z and (mods & (ctrl|alt|shift))==ctrl: 156 | try: 157 | data = "%c" % (chr(key-ord('A')+1)) 158 | #data = "%c" % (chr(key - Qt.Key_A) + 1) 159 | except Exception as e: 160 | print(e) 161 | print(key - Qt.Key_A) 162 | print(key, ord('A'), key-ord('A')+1, chr(key-ord('A')+1)) 163 | elif len(text) > 0: 164 | data = event.text() 165 | if len(text) == 1 and text >= ' ' and text <= '~' and mods & alt: 166 | data = "\033" + data 167 | 168 | self.send_input(data) 169 | if not data: 170 | return 171 | 172 | #self.verticalScrollBar().setValue(0) 173 | 174 | def send_input(self, data): 175 | QApplication.instance().td.sendInput(self.terminal_id, data) 176 | self.update_screen() 177 | 178 | def data(self, data): 179 | self.emulator.input_data(data) 180 | self.update_screen() 181 | 182 | def mousePressEvent(self, event): 183 | pass 184 | 185 | def mouseMoveEvent(self, event): 186 | pass 187 | 188 | def mouseReleaseEvent(self, event): 189 | pass 190 | 191 | def mouseDoubleClickEvent(self, event): 192 | pass 193 | 194 | def focusInEvent(self, event): 195 | self.caretVisible = True 196 | self.blink = True 197 | self.cursorBlink.stop() 198 | self.cursorBlink.start() 199 | self.renderCursor() 200 | 201 | def focusOutEvent(self, event): 202 | self.caretVisible = False 203 | self.renderCursor() 204 | 205 | def get_colors(self, gfx): 206 | fg, bg = rendition.get_colors(gfx) 207 | fg = QColor(*fg) if fg else Qt.white 208 | bg = QColor(*bg) if bg else Qt.black 209 | return fg, bg 210 | 211 | def paintRow(self, y, row, rowgfx): 212 | p = QPainter(self.viewport()) 213 | p.setFont(self.font.font) 214 | 215 | # render background 216 | bg, fg = Qt.black, Qt.white 217 | length = 0 218 | current = None 219 | x = 0 220 | for i in range(0, self.cols): 221 | gfx = rowgfx[i] 222 | 223 | # invert colors when rendering the cursor 224 | if self.blink and self.caretVisible and self.emulator.cursor.visible and \ 225 | self.emulator.cursor.y == y and self.emulator.cursor.x == i: 226 | gfx ^= rendition.GFX_INV 227 | 228 | if gfx != current: 229 | if length > 0: 230 | p.fillRect(x * self.font.charWidth, y * self.font.charHeight, 231 | length * self.font.charWidth, self.font.charHeight, bg) 232 | x = x + length 233 | length = 0 234 | current = gfx 235 | fg, bg = self.get_colors(gfx) 236 | length = length + 1 237 | if length > 0: 238 | p.fillRect(x * self.font.charWidth, y * self.font.charHeight, 239 | length * self.font.charWidth, self.font.charHeight, bg) 240 | 241 | # render foreground 242 | bg, fg = Qt.black, Qt.white 243 | length = 0 244 | current = None 245 | x = 0 246 | for i in range(0, self.cols): 247 | gfx = rowgfx[i] 248 | if gfx != current: 249 | if length > 0: 250 | line = "".join(row[x:i]) 251 | p.setPen(fg) 252 | p.drawText(x * self.font.charWidth, y * self.font.charHeight + self.font.charOffset + self.font.ascent, line) 253 | if gfx & rendition.GFX_BOLD: 254 | p.setFont(self.font.bold) 255 | elif gfx & rendition.GFX_UL: 256 | p.setFont(self.font.under) 257 | else: 258 | p.setFont(self.font.font) 259 | x = x + length 260 | length = 0 261 | current = gfx 262 | fg, bg = self.get_colors(gfx) 263 | length = length + 1 264 | if length > 0: 265 | line = "".join(row[x:i]) 266 | p.setPen(fg) 267 | p.drawText(x * self.font.charWidth, y * self.font.charHeight + self.font.charOffset + self.font.ascent, line) 268 | 269 | # draw disabled cursor as the screen's not active right now 270 | if not self.caretVisible and self.emulator.cursor.y == y: 271 | 272 | if self.emulator.cursor.x == len(rowgfx): 273 | fg, bg = self.get_colors(rowgfx[self.emulator.cursor.x-1]) 274 | elif self.emulator.cursor.x > len(rowgfx): 275 | print(self.emulator.cursor.x, len(rowgfx)) 276 | print(rowgfx) 277 | raise Exception("") 278 | else: 279 | fg, bg = self.get_colors(rowgfx[self.emulator.cursor.x]) 280 | p.setPen(fg) 281 | p.drawRect(x * self.font.charWidth, y * self.font.charHeight, self.font.charWidth -1, self.font.charHeight - 1) 282 | 283 | 284 | def paintEvent(self, event): 285 | p = QPainter(self.viewport()) 286 | p.setFont(self.font.font) 287 | p.fillRect(event.rect(), Qt.black) 288 | 289 | yofs = self.verticalScrollBar().value() 290 | y = event.rect().y() 291 | bot = y + event.rect().height() 292 | top = int(y / self.font.charHeight) 293 | bot = int((bot / self.font.charHeight) + 1) 294 | 295 | screen = self.emulator.screen 296 | for y in range(0, self.rows): 297 | self.paintRow(y, screen.cells[y], screen.gfx[y]) 298 | 299 | def closeRequest(self): 300 | print("clooooooooose") 301 | #self.process.kill() 302 | 303 | def resizeEvent(self, event): 304 | sz = event.size() 305 | self.resize(sz.width(), sz.height()) 306 | 307 | def resize(self, w, h): 308 | self.cols = int(w / self.font.charWidth) 309 | self.rows = int(h / self.font.charHeight) 310 | #self.verticalScrollBar().setPageStep(self.rows) 311 | #self.verticalScrollBar().setRange(-self.historySize, 0) 312 | self.emulator.resize(self.rows, self.cols) 313 | QApplication.instance().td.resizeTerminal(self.terminal_id, self.rows, self.cols) 314 | -------------------------------------------------------------------------------- /src/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys, argparse 4 | 5 | from PySide.QtCore import * 6 | from PySide.QtGui import * 7 | 8 | import terminal 9 | import gui 10 | 11 | arg_ns = None 12 | 13 | class Main(QMainWindow): 14 | def __init__(self, parent=None): 15 | super(Main, self).__init__(parent) 16 | self.setWindowTitle("blabla") 17 | 18 | self.fileMenu = QMenu("&File", self) 19 | self.menuBar().addMenu(self.fileMenu) 20 | 21 | self.tabs = QTabWidget(self) 22 | self.tabs.setDocumentMode(True) 23 | self.tabs.setTabsClosable(True) 24 | self.tabs.setMovable(True) 25 | 26 | global arg_ns 27 | if arg_ns.terminal_enabled: 28 | frame = gui.TerminalWidget(self, "/bin/sh") 29 | self.tabs.addTab(frame, 'Terminal #1') 30 | #frame = gui.TerminalWidget(self, "/bin/sh") 31 | #self.tabs.addTab(frame, 'Terminal #2') 32 | 33 | self.splitter = QSplitter() 34 | 35 | self.splitter.addWidget(self.tabs) 36 | 37 | self.tabs2 = QTabWidget(self) 38 | self.tabs2.setDocumentMode(True) 39 | self.tabs2.setTabsClosable(True) 40 | self.tabs2.setMovable(True) 41 | self.splitter.addWidget(self.tabs2) 42 | 43 | if arg_ns.terminal_enabled: 44 | frame = gui.TerminalWidget(self, "/usr/bin/vim") 45 | self.tabs2.addTab(frame, 'Terminal #3') 46 | 47 | #self.setCentralWidget(self.tabs) 48 | self.setCentralWidget(self.splitter) 49 | self.splitter.setOrientation(Qt.Vertical) 50 | self.splitter.setSizes([1, 1]) 51 | 52 | self.show() 53 | 54 | def sizeHint(self): 55 | return QSize(800, 600) 56 | 57 | def run(): 58 | parser = argparse.ArgumentParser(description="Santarago Labs Pentest Framework") 59 | parser.add_argument("--disable-terminal", help="disable terminal feature", action="store_false", dest="terminal_enabled") 60 | global arg_ns 61 | arg_ns = parser.parse_args() 62 | 63 | if arg_ns.terminal_enabled: 64 | td = terminal.driver.TerminalDriver() 65 | 66 | app = QApplication(sys.argv) 67 | 68 | if arg_ns.terminal_enabled: 69 | app.td = td 70 | 71 | main = Main() 72 | app.exec_() 73 | 74 | if __name__ == "__main__": 75 | run() 76 | -------------------------------------------------------------------------------- /src/terminal/__init__.py: -------------------------------------------------------------------------------- 1 | from . import emulator 2 | from . import driver 3 | 4 | -------------------------------------------------------------------------------- /src/terminal/ctrl.py: -------------------------------------------------------------------------------- 1 | NUL = 0x0 # NULL 2 | SP = 0x20 # space 3 | BEL = 0x07 # ^G) beeps; 4 | BS = 0x08 # ^H) backspaces one column (but not past the beginning of the line); 5 | HT = 0x09 # ^I) goes to the next tab stop or to the end of the line if there is no earlier tab stop; 6 | LF = 0x0A # ^J) 7 | VT = 0x0B # ^K) and FF (0x0C, ^L) all give a linefeed, and if LF/NL (new-line mode) is set also a carriage return; 8 | FF = 0x0C # see VT 9 | CR = 0x0D # ^M) gives a carriage return; 10 | SO = 0x0E # ^N) activates the G1 character set; 11 | SI = 0x0F # ^O) activates the G0 character set; 12 | CAN = 0x18 # ^X) and SUB (0x1A, ^Z) interrupt escape sequences; 13 | SUB = 0x1A # see CAN 14 | ESC = 0x1B # ^[) starts an escape sequence; 15 | DEL = 0x7F # is ignored; 16 | CSI = 0x9B # is equivalent to ESC [. 17 | -------------------------------------------------------------------------------- /src/terminal/cursor.py: -------------------------------------------------------------------------------- 1 | class Cursor: 2 | def __init__(self, x, y, visible = True): 3 | self.x = x 4 | self.y = y 5 | self.visible = visible 6 | -------------------------------------------------------------------------------- /src/terminal/driver.py: -------------------------------------------------------------------------------- 1 | import os, pty, select, threading, signal 2 | import queue 3 | import multiprocessing 4 | import termios, struct, fcntl 5 | 6 | START = 0x1 7 | EXITED = 0x2 8 | DATA = 0x3 9 | RESIZE = 0x4 10 | 11 | class TerminalDriverProcess(multiprocessing.Process): 12 | def __init__(self, transport, queue, daemon=True): 13 | multiprocessing.Process.__init__(self, daemon=daemon) 14 | self.transport = transport 15 | self.queue = queue 16 | self.terminals = {} 17 | self.todelete = [] 18 | self.stopped = False 19 | 20 | def sigchild(self, sig, frame): 21 | todelete = [] 22 | for pid in self.terminals: 23 | ret = os.waitpid(pid, os.WNOHANG) 24 | if ret[0] == pid and ret[0] != 0: 25 | self.queue.put((pid, EXITED, None)) 26 | self.todelete.append(pid) 27 | 28 | def startTerminal(self, cmd, args=[]): 29 | signal.signal(signal.SIGCHLD, self.sigchild) 30 | pid, fd = pty.fork() 31 | if pid == 0: 32 | args = [cmd] if len(args) == 0 else args 33 | os.execv(cmd, args) 34 | os._exit(1) 35 | 36 | self.terminals[pid] = fd 37 | return pid 38 | 39 | def resizeTerminal(self, pid, rows, cols): 40 | data = struct.pack("HHHH", rows, cols, 0, 0) 41 | fd = self.terminals[pid] 42 | fcntl.ioctl(fd, termios.TIOCSWINSZ, data) 43 | attr = termios.tcgetattr(fd) 44 | termios.tcsetattr(fd, termios.TCSAFLUSH, attr) 45 | 46 | def _run(self): 47 | for pid in self.todelete: 48 | del self.terminals[pid] 49 | self.todelete = [] 50 | fds = [x for x in self.terminals.values()] 51 | transport_fd = self.transport.fileno() 52 | fds.append(transport_fd) 53 | 54 | i, o, e = select.select(fds, [], [], 0.01) 55 | 56 | if transport_fd in i: 57 | msg, cmd, args = self.transport.recv() 58 | if msg == START: 59 | pid = self.startTerminal(cmd, args) 60 | self.transport.send(pid) 61 | if cmd not in self.terminals: 62 | pass 63 | elif msg == DATA: 64 | fd = self.terminals[cmd] 65 | os.write(fd, args) 66 | elif msg == RESIZE: 67 | self.resizeTerminal(cmd, *args) 68 | 69 | for pid in self.terminals: 70 | fd = self.terminals[pid] 71 | if fd in i: 72 | try: 73 | data = os.read(fd, 4096) 74 | if len(data) == 0: 75 | continue 76 | self.queue.put((pid, DATA, data)) 77 | except OSError: 78 | pass 79 | 80 | def run(self): 81 | while not self.stopped: 82 | self._run() 83 | 84 | class TerminalCallbackThread(threading.Thread): 85 | def __init__(self, queue, queue2): 86 | threading.Thread.__init__(self) 87 | self.proc_queue = queue 88 | self.thread_queue = queue2 89 | self.callbacks = {} 90 | self.stopped = False 91 | 92 | def _run(self): 93 | try: 94 | pid, msg, data = self.proc_queue.get(0.01) 95 | if msg == EXITED: 96 | self.thread_queue.put((pid, EXITED, data)) 97 | elif msg == DATA: 98 | if pid in self.callbacks: 99 | #$self.callbacks[pid].data(data) 100 | self.thread_queue.put((pid, DATA, data)) 101 | except queue.Empty: 102 | pass 103 | 104 | try: 105 | pid, msg, data = self.thread_queue.get(0.01) 106 | if pid not in self.callbacks: 107 | if msg == START: 108 | self.callbacks[pid] = data 109 | return 110 | if msg == EXITED: 111 | self.callbacks[pid].exited(data) 112 | del self.callbacks[pid] 113 | elif msg == DATA: 114 | if pid in self.callbacks: 115 | self.callbacks[pid].data(data) 116 | except queue.Empty: 117 | pass 118 | 119 | def run(self): 120 | while not self.stopped: 121 | self._run() 122 | 123 | class TerminalDriver: 124 | def __init__(self): 125 | self.pipe = multiprocessing.Pipe() 126 | self.queue = multiprocessing.Queue() 127 | self.proc = TerminalDriverProcess(self.pipe[0], self.queue) 128 | self.proc.start() 129 | self.queue2 = queue.Queue() 130 | self.cb = TerminalCallbackThread(self.queue, self.queue2) 131 | self.cb.start() 132 | 133 | def startTerminal(self, cmd, args, cb): 134 | p = self.pipe[1] 135 | p.send((START, cmd, args)) 136 | pid = int(p.recv()) 137 | self.queue2.put((pid, START, cb)) 138 | return pid 139 | 140 | def sendInput(self, terminal_id, data): 141 | p = self.pipe[1] 142 | if not data: 143 | data = "" 144 | data = data.encode("utf8") 145 | p.send((DATA, terminal_id, data)) 146 | 147 | def resizeTerminal(self, terminal_id, rows, cols): 148 | p = self.pipe[1] 149 | p.send((RESIZE, terminal_id, (rows,cols))) 150 | 151 | """ 152 | class Test: 153 | def __init__(self): 154 | pass 155 | 156 | def exited(self, data): 157 | print("CALLBACK exited", data) 158 | 159 | def data(self, data): 160 | print("CALLBACK data", data) 161 | 162 | test1 = Test() 163 | 164 | td = TerminalDriver() 165 | terminal_id = td.startTerminal("/bin/sh", [], test1) 166 | td.sendInput(terminal_id, "ls -lha\n") 167 | td.resizeTerminal(terminal_id, 30, 100) 168 | 169 | import time 170 | time.sleep(10) 171 | print("done") 172 | """ 173 | -------------------------------------------------------------------------------- /src/terminal/emulator.py: -------------------------------------------------------------------------------- 1 | from . import ctrl, esc, cursor, screen, rendition 2 | 3 | class Emulator: 4 | def __init__(self, rows=80, cols=25, debug=True): 5 | # configure two supported screens and cursors 6 | self.cols, self.rows = cols, rows 7 | self.screens = [screen.Screen(rows, cols), screen.Screen(rows, cols)] 8 | self.cursors = [cursor.Cursor(0,0), cursor.Cursor(0, 0)] 9 | 10 | # set currently active screen, cursor, scroll region and graphics rendition settings 11 | self.screen = self.screens[0] 12 | self.cursor = self.cursors[0] 13 | self.scroll_bottom = rows - 1 14 | self.scroll_top = 0 15 | self.gfx = 0 16 | 17 | # vars for parser state machine of escape sequences etc 18 | self.escape_str = "" 19 | self.in_escape = False # in escape sequence 20 | self.in_csi = False # in Control Sequence Introducer 21 | 22 | # xterm set title support 23 | self.current_title = None # currently set title 24 | self.set_title = False # set window title 25 | self.ignore_title = True # ignore setting of window title 26 | 27 | # misc settings 28 | self.tabstop = 8 # amount of spaces in a tab 29 | self.draw_lines = False # line drawing mode 30 | self.insert_mode = False # insert mode for drawing characters 31 | self.cursor_keys = False # interpet cursor keys on numpad as keys or not 32 | 33 | # references to callback functions 34 | self.callback_data = None # respond with data to f.e. a specific CSI sequence 35 | self.callback_update = None # let caller know there's new data available 36 | self.callback_title = None # inform caller of updated window title 37 | 38 | # debug log support 39 | self.debug = debug 40 | self.debuglog = [] 41 | self.debugloglen = 256 # maximum number of lines stored in self.debuglog 42 | 43 | # control character dispatch 44 | self.ctrl_dispatch = { 45 | ctrl.BEL : self.bell, 46 | ctrl.BS : self.backspace, 47 | ctrl.HT : self.htab, 48 | ctrl.LF : self.lf, 49 | ctrl.VT : self.lf, 50 | ctrl.FF : self.lf, 51 | ctrl.CR : self.cr, 52 | ctrl.SO : self.shift_out, 53 | ctrl.SI : self.shift_in, 54 | } 55 | 56 | # escape sequence dispatcher for CSI escape sequences as per VT102 57 | self.csi_dispatch = { 58 | esc.ICH : self.insert_chars, 59 | esc.CUU : self.cursor_up, 60 | esc.CUD : self.cursor_down, 61 | esc.CUF : self.cursor_forward, 62 | esc.CUB : self.cursor_back, 63 | esc.CNL : self.cursor_next_line, 64 | esc.CPL : self.cursor_prev_line, 65 | esc.CHA : self.cursor_halign, 66 | esc.CUP : self.cursor_set, 67 | esc.ED : self.erase_data, 68 | esc.EL : self.erase_in_line, 69 | esc.IL : self.insert_lines, 70 | esc.DL : self.delete_lines, 71 | esc.DCH : self.delete_characters, 72 | esc.ECH : self.erase_characters, 73 | esc.HPR : self.cursor_forward, 74 | esc.DA : self.report_da, 75 | esc.VPA : self.cursor_set, 76 | #esc.VPR : self.vertical_position_relative, 77 | #esc.HVP : self.hvposition, 78 | esc.TBC : self.tabulation_clear, 79 | esc.SM : self.set_mode, 80 | esc.RM : self.reset_mode, 81 | esc.SGR : self.select_gfx, 82 | esc.DSR : self.report_status, 83 | esc.DECSTBM : self.scroll_region, 84 | esc.HPA : self.cursor_halign, 85 | #esc.RIS : self.reset, 86 | #esc.IND : self.index, 87 | #esc.RI : self.rindex, 88 | #esc.NEL : self.nextline, 89 | esc.DECSC : self.cursor_save, 90 | esc.DECRC : self.cursor_restore, 91 | } 92 | 93 | # charset setting identifiers used for non "standard" escape sequences etc 94 | self.charset = [" ", "#", "%", "(", ")", "*", "+"] 95 | 96 | # replace key chars with values when in line drawing mode 97 | self.line_draw_map = { 98 | u"j": u"\xe2\x94\x98", 99 | u"k": u"\xe2\x94\x90", 100 | u"l": u"\xe2\x94\x8c", 101 | u"m": u"\xe2\x94\x94", 102 | u"n": u"\xe2\x94\xbc", 103 | u"q": u"\xe2\x94\x80", 104 | u"t": u"\xe2\x94\x9c", 105 | u"u": u"\xe2\x94\xa4", 106 | u"v": u"\xe2\x94\xb4", 107 | u"w": u"\xe2\x94\xac", 108 | u"x": u"\xe2\x94\x82", 109 | } 110 | 111 | def set_update_callback(self, cb): 112 | self.callback_update = cb 113 | 114 | def set_data_callback(self, cb): 115 | self.callback_data = cb 116 | 117 | def set_title_callback(self, cb): 118 | self.callback_title = cb 119 | 120 | def update_callback(self): 121 | if self.callback_update: 122 | self.callback_update() 123 | 124 | def data_callback(self, data): 125 | if self.callback_data: 126 | self.callback_data(data) 127 | 128 | def title_callback(self, title): 129 | if title == self.current_title: 130 | return 131 | self.current_title = title 132 | if self.callback_title: 133 | self.callback_title(title) 134 | 135 | def shift_in(self): 136 | raise Exception("shift in") 137 | 138 | def shift_out(self): 139 | raise Exception("shift out") 140 | 141 | def bell(self): 142 | pass 143 | 144 | def backspace(self): 145 | if self.cursor.x > 0: 146 | self.cursor.x = self.cursor.x - 1 147 | 148 | def htab(self): 149 | self.cursor.x = self.cursor.x + self.tabstop - (self.cursor.x % self.tabstop) 150 | if self.cursor.x > self.cols: 151 | self.cursor.x = self.cols 152 | 153 | def cursor_save(self, *params): 154 | print("Save cursor1") 155 | #raise Exception("save cursor") 156 | 157 | def cursor_restore(self, *params): 158 | print("Save cursor2") 159 | #raise Exception("restore cursor") 160 | 161 | def insert_lines(self, count=None): 162 | pass 163 | 164 | def insert_chars(self, count=None): 165 | #raise Exception("todo") 166 | pass 167 | 168 | def cursor_up(self, count=None): 169 | self.cursor.y += count or 1 170 | self.fix_cursors() 171 | 172 | def cursor_down(self, count=None): 173 | self.cursor.y -= count or 1 174 | self.fix_cursors() 175 | 176 | def cursor_forward(self, count=None): 177 | self.cursor.x += count or 1 178 | self.fix_cursors() 179 | 180 | def cursor_back(self, count=None): 181 | self.cursor.x -= count or 1 182 | self.fix_cursors() 183 | 184 | def cursor_next_line(self, count=None): 185 | self.cursor_down(count) 186 | self.cursor.x = 0 187 | 188 | def cursor_prev_line(self, count=None): 189 | self.cursor_up(count) 190 | self.cursor.x = 0 191 | 192 | def cursor_halign(self, param=None): 193 | raise Exception("!!!!", param) 194 | if param: 195 | self.cursor.x = param - 1 196 | self.fix_cursors() 197 | 198 | def cursor_set(self, y = None, x = None): 199 | x = 0 if not x or x == 0 else x - 1 200 | y = 0 if not y or y == 0 else y - 1 201 | self.cursor.x = x 202 | self.cursor.y = y 203 | self.fix_cursors() 204 | 205 | def fix_cursor_bounds(self, cursor): 206 | if cursor.x > self.cols: 207 | cursor.x = self.cols 208 | if cursor.y >= self.rows: 209 | cursor.y = self.rows - 1 210 | 211 | def fix_cursors(self): 212 | self.fix_cursor_bounds(self.cursors[0]) 213 | self.fix_cursor_bounds(self.cursors[1]) 214 | 215 | def delete_lines(self, count): 216 | raise Exception("delete lines") 217 | 218 | def delete_characters(self, *params): 219 | raise Exception("delete characters") 220 | 221 | def report_da(self, *params): 222 | self.data_callback("\033[?1;2c") 223 | 224 | def is_alternative_screen(self): 225 | return self.screen == self.screens[1] 226 | 227 | def set_mode(self, *params): 228 | if len(params) < 0: 229 | return 230 | private = False 231 | if params[-1] == "?": 232 | private = True 233 | params = params[:-1] 234 | for p in params: 235 | if p == 4: 236 | self.insert_mode = True 237 | elif p == 1049 or p == 47 and not self.is_alternative_screen(): 238 | self.screen = self.screen[1] 239 | self.cursor = self.cursor[1] 240 | elif p == 1: 241 | self.cursor_keys = True 242 | elif p == 2: 243 | pass 244 | elif p == 7: 245 | pass 246 | elif p == 12: 247 | pass 248 | elif p == 25: 249 | raise Exception("visible cursor") 250 | self.cursor.visible = True 251 | elif p == 0: 252 | pass 253 | else: 254 | raise Exception("set mode unkonwn: %s" % p) 255 | 256 | 257 | def reset_mode(self, *params): 258 | if len(params) < 0: 259 | return 260 | private = False 261 | if params[-1] == "?": 262 | private = True 263 | params = params[:-1] 264 | for p in params: 265 | if p == 4: 266 | self.insert_mode = False 267 | elif p == 1049 or p == 47 and self.is_alternative_screen(): 268 | self.screen = self.screen[0] 269 | self.cursor = self.cursor[0] 270 | elif p == 1: 271 | self.cursor_keys = False 272 | elif p == 2: 273 | pass 274 | elif p == 7: 275 | pass 276 | elif p == 12: 277 | pass 278 | elif p == 25: 279 | raise Exception("not visible cursor") 280 | self.cursor.visible = False 281 | elif p == 0: 282 | pass 283 | else: 284 | raise Exception("set mode unkonwn: %s" % p) 285 | 286 | def report_status(self, param=None): 287 | if not param or param not in [5, 6]: 288 | return 289 | if param == 5: 290 | self.data_callback("\033[0n") 291 | elif param == 6: 292 | self.data_callback("\033[%d;%dR" % (self.cursor.y + 1, self.cursor.x + 1)) 293 | 294 | def scroll_region(self, *params): 295 | if len(params) < 2: 296 | return 297 | 298 | self.scroll_top = params[0] - 1 299 | self.scroll_bottom = params[1] - 1 300 | if self.scroll_top < 0: 301 | self.scroll_top = 0 302 | elif self.scroll_top >= self.rows: 303 | self.scroll_top = self.rows - 1 304 | if self.scroll_bottom < 0: 305 | self.scroll_bottom = 0 306 | elif self.scroll_bottom >= self.rows: 307 | self.scroll_bottom = self.rows - 1 308 | 309 | def select_gfx(self, *params): 310 | i = 0 311 | lp = len(params) 312 | # ISO-8613-3 support for 256-colors is implemented 313 | # 24-bit color support is not implemented 314 | if (lp == 0): 315 | raise Exception("no args to gfx") 316 | while i < lp: 317 | p = params[i] 318 | if p == 0: 319 | # default graphics rendition 320 | self.gfx = 0 321 | elif p >= 1 and p <= 9: 322 | # set a style 323 | self.gfx &= ~0xff 324 | self.gfx |= 1 << (p - 1) 325 | elif p >= 21 and p <= 29: 326 | # clear a style 327 | self.gfx &= ~(1 << (p - 21)) 328 | elif p >= 30 and p <= 37: 329 | self.gfx &= ~(0x00FF0000 | rendition.GFX_FG) 330 | self.gfx |= ((p - 29) << 16) 331 | elif p == 38 and i + 2 < len(params): 332 | if params[i+1] == 5: 333 | self.gfx &= ~0x00ff0000 334 | self.gfx |= rendition.GFX_FG 335 | self.gfx |= (params[i+2] & 0xff) << 16 336 | i = i + 2 337 | elif p == 39: 338 | self.gfx &= ~(0x00ff0000 | rendition.GFX_FG) 339 | elif p >= 40 and p <= 47: 340 | self.gfx &= ~(0xFF000000 | rendition.GFX_BG) 341 | self.gfx |= ((p - 39) << 24) 342 | elif p == 48 and i + 2 < len(params): 343 | if params[i+1] == 5: 344 | self.gfx &= ~0x00ff0000 345 | self.gfx |= rendition.GFX_BG 346 | self.gfx |= (params[i+2] & 0xff) << 24 347 | i = i + 2 348 | elif p == 49: 349 | self.gfx &= ~(0xff000000 | rendition.GFX_BG) 350 | elif p >= 90 and p <= 97: 351 | self.gfx &= ~(0x00ff0000 | rendition.GFX_FG) 352 | self.gfx |= ((p - 81) << 16) 353 | elif p >= 100 and p <= 107: 354 | self.gfx &= ~(0xff000000 | rendition.GFX_BG) 355 | self.gfx |= ((p - 91) << 16) 356 | else: 357 | raise Exception("unsupported gfx rendition %i" % p) 358 | i = i + 1 359 | 360 | def tabulation_clear(self, param = 0): 361 | if param == 0: 362 | self.tabstops.discard(self.cursor.x) 363 | elif param == 3: 364 | self.tabstops = set() 365 | 366 | def erase_characters(self, count=None): 367 | if not count or count == 0: 368 | count = 1 369 | self.screen.erase_rectangle(self.cursor.y, self.cursor.x, self.cursor.y + 1, self.x + count, self.gfx) 370 | 371 | def erase_in_line(self, param = None): 372 | if not param: 373 | param = 0 374 | if param == 0: 375 | self.screen.erase_rectangle(self.cursor.y, self.cursor.x, self.cursor.y + 1, self.cols, self.gfx) 376 | elif param == 1: 377 | self.screen.erase_rectangle(self.cursor.y, 0, self.cursor.y + 1, self.cursor.x + 1, self.gfx) 378 | elif param == 2: 379 | self.screen.erase_rectangle(self.cursor.y, 0, self.cursor.y + 1, self.cols, self.gfx) 380 | 381 | def erase_data(self, param = None): 382 | if not param: 383 | param = 0 384 | if param == 0: 385 | self.screen.erase_rectangle(self.cursor.y, self.cursor.x, self.cursor.y + 1, self.cols, self.gfx) 386 | self.screen.erase_rectangle(self.cursor.y + 1, 0, self.rows, self.cols, self.gfx) 387 | elif param == 1: 388 | self.screen.erase_rectangle(0, 0, self.cursor.y, self.cols, self.gfx) 389 | self.screen.erase_rectangle(self.cursor.y, 0, self.cursor.y + 1, self.cursor.x + 1, self.gfx) 390 | elif param == 2: 391 | self.screen.erase_rectangle(0, 0, self.rows, self.cols, self.gfx) 392 | self.cursor.x, self.cursor.y = 0, 0 393 | 394 | def resize(self, rows, cols): 395 | if rows == self.rows and cols == self.cols: 396 | return 397 | self.screens[0].resize(rows, cols) 398 | self.screens[1].resize(rows, cols) 399 | self.scroll_top = 0 400 | self.scroll_bottom = rows - 1 401 | self.rows = rows 402 | self.cols = cols 403 | self.fix_cursors() 404 | 405 | def lf(self): 406 | if self.cursor.y >= self.scroll_bottom: 407 | self.screen.scroll_up(self.scroll_top, self.scroll_bottom, self.is_alternative_screen(), self.gfx) 408 | else: 409 | self.cursor.y += 1 410 | 411 | def cr(self): 412 | self.cursor.x = 0 413 | 414 | def newline(self): 415 | self.lf() 416 | self.cursor.x = 0 417 | 418 | def write_char(self, ch): 419 | if self.cursor.x >= self.cols: 420 | self.newline() 421 | 422 | if self.draw_lines: 423 | if ch in self.linemap: 424 | ch = self.linemap[ch] 425 | 426 | if self.insert_mode: 427 | self.insert_chars([1]) 428 | 429 | self.screen.write_char(self.cursor, ch, self.gfx) 430 | self.cursor.x += 1 431 | 432 | self.update_callback() 433 | 434 | def parse_escape_sequence(self, data): 435 | l = len(data) 436 | if l == 0: 437 | # XXX log 438 | raise Exception("unhandled escape seq") 439 | return 440 | 441 | if data[0] != "[": 442 | # ignore numpad handling 443 | if data[0] in ["=", ">"]: 444 | return 445 | else: 446 | raise Exception("unhandled data %s" % data) 447 | 448 | seq = data[1:-1] 449 | mode = ord(data[-1]) 450 | option = None 451 | if len(seq) > 1 and seq[0] in ["?", ">", "!"]: 452 | option = seq[0] 453 | seq = seq[1] 454 | try: 455 | if len(seq) > 0: 456 | params = [int(x) for x in seq.split(";")] 457 | else: 458 | params = [0] 459 | except Exception as e: 460 | params = [0] 461 | 462 | if mode not in self.csi_dispatch: 463 | s="".join(["%x " % ord(x) for x in data]) 464 | s2="".join(["%c " % ord(x) for x in data]) 465 | self.write_debug_logdata("! unknown CSI: %s [%s]" % (s2, s)) 466 | return 467 | 468 | if not option: 469 | self.csi_dispatch[mode](*params) 470 | else: 471 | self.csi_dispatch[mode](*params, option) 472 | self.write_debug_logdata("ESC %s -> %s" % (data, self.csi_dispatch[mode])) 473 | 474 | def write_debug_logdata(self, data): 475 | if not self.debug: 476 | return 477 | data = data.splitlines() 478 | for line in data: 479 | self.debuglog.append(line) 480 | ld = len(self.debuglog) 481 | if ld > self.debugloglen: 482 | self.debuglog = self.debuglog[ld - self.debugloglen:] 483 | 484 | def parse_data(self, data): 485 | for c in data: 486 | oc = ord(c) 487 | if self.set_title: 488 | if oc != ctrl.BEL: 489 | self.escape_str += c 490 | continue 491 | if self.ignore_title == False: 492 | self.title_callback(self.escape_str) 493 | self.escape_str = "" 494 | self.set_title = False 495 | continue 496 | elif oc in self.ctrl_dispatch: 497 | self.ctrl_dispatch[oc]() 498 | continue 499 | elif self.in_escape and not self.in_csi: 500 | self.escape_str += c 501 | l = len(self.escape_str) 502 | if l == 1 and c == "[": 503 | self.in_csi = True 504 | continue 505 | elif l == 1 and c != "[" and c != "]" and c not in self.charset: 506 | self.parse_escape_sequence(self.escape_str) 507 | self.escape_str = "" 508 | self.in_escape = False 509 | continue 510 | elif l == 2 and self.escape_str[0] in self.charset: 511 | if self.escape_str == "(0": 512 | self.draw_lines = True 513 | else: 514 | self.draw_lines = False 515 | self.escape_str = "" 516 | self.in_escape = False 517 | continue 518 | elif l > 1 and self.escape_str[0] == "]" and c == ";": 519 | self.set_title = True 520 | try: 521 | param = [int(x) for x in self.escape_str[1:-1].split(";")] 522 | except: 523 | param = [0] 524 | if len(param) == 0 or param[0]==0 or param[0] == 2: 525 | self.ignore_title = False 526 | else: 527 | self.ignore_title = True 528 | self.in_escape = False 529 | self.escape_str = "" 530 | continue 531 | elif self.in_csi: 532 | self.escape_str += c 533 | if oc >= ord("@") and oc <= ord("~"): 534 | self.parse_escape_sequence(self.escape_str) 535 | self.in_csi = False 536 | self.in_escape = False 537 | self.escape_str = "" 538 | continue 539 | elif oc == ctrl.ESC: 540 | self.in_escape = True 541 | continue 542 | else: 543 | self.write_char(c) 544 | 545 | def input_data(self, data): 546 | try: 547 | data = data.decode(encoding="utf8") 548 | self.parse_data(data) 549 | except Exception as e: 550 | self.write_debug_logdata(e) 551 | -------------------------------------------------------------------------------- /src/terminal/esc.py: -------------------------------------------------------------------------------- 1 | # Taken from: VT102 User Guide 2 | # found http://vt100.net/docs/vt102-ug/chapter5.html 3 | ICH = 64 # "@" -- Insert Blank Characters 4 | CUU = 65 # "A" -- Cursur Up 5 | CUD = 66 # "B" -- Cursor Down 6 | CUF = 67 # "C" -- Cursor Forward 7 | CUB = 68 # "D" -- Cursor Backward 8 | CNL = 69 # "E" -- Cursor Next line 9 | CPL = 70 # "F" -- Cursor Previous Line 10 | CHA = 71 # "G" -- Cursor Horizontal Align 11 | CUP = 72 # "H" -- Cursor Position 12 | ED = 74 # "J" -- Erase data 13 | EL = 75 # "K" -- Erase in line 14 | IL = 76 # "L" -- Insert line 15 | DL = 77 # "M" -- Delete line 16 | DCH = 80 # "P" -- Delete character 17 | ECH = 88 # "X" -- Erase character 18 | HPR = 97 # "a" -- Horizontal Postion Relative 19 | DA = 99 # "c" -- Device Attributes 20 | VPA = 100 # "d" -- Vertial Position Adjust 21 | VPR = 101 # "e" -- Vertical Position Relative 22 | HVP = 102 # "f" -- Horizontal / Vertical postion 23 | TBC = 103 # "g" -- Tabulation Clear 24 | SM = 104 # "h" -- Set Mode 25 | RM = 108 # "l" -- Reset Mode" 26 | SGR = 109 # "m" -- Select Graphics rendition" 27 | DSR = 110 # "n" -- Device Status Report" 28 | DECSTBM = 114 # "r" -- Select Top and Bottom Margins 29 | HPA = 39 # "'" -- Horizontal Position Adjust 30 | RIS = 99 # "c" -- Reset to Initial State 31 | IND = 68 # "D" -- Index 32 | RI = 77 # "M" -- Reverse Index 33 | NEL = 69 # "E" -- Next Line 34 | DECSC = 55 # "7" -- Save Cursor 35 | DECRC = 56 # "8" -- Restore Cursor 36 | -------------------------------------------------------------------------------- /src/terminal/rendition.py: -------------------------------------------------------------------------------- 1 | # color scheme generated by gen-term-colors.py 2 | 3 | colors = [ 4 | ( 46, 52, 54), (204, 0, 0), ( 78,154, 6), (196,160, 0), ( 52,101,164), 5 | (117, 80,123), ( 6,152,154), (211,215,207), ( 85, 87, 83), (239, 41, 41), 6 | (138,226, 52), (252,233, 79), (114,159,207), (173,127,168), ( 52,226,226), 7 | (255,255,255), ( 0, 0, 0), ( 0, 0, 95), ( 0, 0,135), ( 0, 0,175), 8 | ( 0, 0,215), ( 0, 0,255), ( 0, 95, 0), ( 0, 95, 95), ( 0, 95,135), 9 | ( 0, 95,175), ( 0, 95,215), ( 0, 95,255), ( 0,135, 0), ( 0,135, 95), 10 | ( 0,135,135), ( 0,135,175), ( 0,135,215), ( 0,135,255), ( 0,175, 0), 11 | ( 0,175, 95), ( 0,175,135), ( 0,175,175), ( 0,175,215), ( 0,175,255), 12 | ( 0,215, 0), ( 0,215, 95), ( 0,215,135), ( 0,215,175), ( 0,215,215), 13 | ( 0,215,255), ( 0,255, 0), ( 0,255, 95), ( 0,255,135), ( 0,255,175), 14 | ( 0,255,215), ( 0,255,255), ( 95, 0, 0), ( 95, 0, 95), ( 95, 0,135), 15 | ( 95, 0,175), ( 95, 0,215), ( 95, 0,255), ( 95, 95, 0), ( 95, 95, 95), 16 | ( 95, 95,135), ( 95, 95,175), ( 95, 95,215), ( 95, 95,255), ( 95,135, 0), 17 | ( 95,135, 95), ( 95,135,135), ( 95,135,175), ( 95,135,215), ( 95,135,255), 18 | ( 95,175, 0), ( 95,175, 95), ( 95,175,135), ( 95,175,175), ( 95,175,215), 19 | ( 95,175,255), ( 95,215, 0), ( 95,215, 95), ( 95,215,135), ( 95,215,175), 20 | ( 95,215,215), ( 95,215,255), ( 95,255, 0), ( 95,255, 95), ( 95,255,135), 21 | ( 95,255,175), ( 95,255,215), ( 95,255,255), (135, 0, 0), (135, 0, 95), 22 | (135, 0,135), (135, 0,175), (135, 0,215), (135, 0,255), (135, 95, 0), 23 | (135, 95, 95), (135, 95,135), (135, 95,175), (135, 95,215), (135, 95,255), 24 | (135,135, 0), (135,135, 95), (135,135,135), (135,135,175), (135,135,215), 25 | (135,135,255), (135,175, 0), (135,175, 95), (135,175,135), (135,175,175), 26 | (135,175,215), (135,175,255), (135,215, 0), (135,215, 95), (135,215,135), 27 | (135,215,175), (135,215,215), (135,215,255), (135,255, 0), (135,255, 95), 28 | (135,255,135), (135,255,175), (135,255,215), (135,255,255), (175, 0, 0), 29 | (175, 0, 95), (175, 0,135), (175, 0,175), (175, 0,215), (175, 0,255), 30 | (175, 95, 0), (175, 95, 95), (175, 95,135), (175, 95,175), (175, 95,215), 31 | (175, 95,255), (175,135, 0), (175,135, 95), (175,135,135), (175,135,175), 32 | (175,135,215), (175,135,255), (175,175, 0), (175,175, 95), (175,175,135), 33 | (175,175,175), (175,175,215), (175,175,255), (175,215, 0), (175,215, 95), 34 | (175,215,135), (175,215,175), (175,215,215), (175,215,255), (175,255, 0), 35 | (175,255, 95), (175,255,135), (175,255,175), (175,255,215), (175,255,255), 36 | (215, 0, 0), (215, 0, 95), (215, 0,135), (215, 0,175), (215, 0,215), 37 | (215, 0,255), (215, 95, 0), (215, 95, 95), (215, 95,135), (215, 95,175), 38 | (215, 95,215), (215, 95,255), (215,135, 0), (215,135, 95), (215,135,135), 39 | (215,135,175), (215,135,215), (215,135,255), (215,175, 0), (215,175, 95), 40 | (215,175,135), (215,175,175), (215,175,215), (215,175,255), (215,215, 0), 41 | (215,215, 95), (215,215,135), (215,215,175), (215,215,215), (215,215,255), 42 | (215,255, 0), (215,255, 95), (215,255,135), (215,255,175), (215,255,215), 43 | (215,255,255), (255, 0, 0), (255, 0, 95), (255, 0,135), (255, 0,175), 44 | (255, 0,215), (255, 0,255), (255, 95, 0), (255, 95, 95), (255, 95,135), 45 | (255, 95,175), (255, 95,215), (255, 95,255), (255,135, 0), (255,135, 95), 46 | (255,135,135), (255,135,175), (255,135,215), (255,135,255), (255,175, 0), 47 | (255,175, 95), (255,175,135), (255,175,175), (255,175,215), (255,175,255), 48 | (255,215, 0), (255,215, 95), (255,215,135), (255,215,175), (255,215,215), 49 | (255,215,255), (255,255, 0), (255,255, 95), (255,255,135), (255,255,175), 50 | (255,255,215), (255,255,255), ( 8, 8, 8), ( 18, 18, 18), ( 28, 28, 28), 51 | ( 38, 38, 38), ( 48, 48, 48), ( 58, 58, 58), ( 68, 68, 68), ( 78, 78, 78), 52 | ( 88, 88, 88), ( 98, 98, 98), (108,108,108), (118,118,118), (128,128,128), 53 | (138,138,138), (148,148,148), (158,158,158), (168,168,168), (178,178,178), 54 | (188,188,188), (198,198,198), (208,208,208), (218,218,218), (228,228,228), 55 | (238,238,238) 56 | ] 57 | 58 | back_colors = [ 59 | ( 0, 0, 0), ( 46, 52, 54), (204, 0, 0), ( 78,154, 6), (196,160, 0), 60 | ( 52,101,164), (117, 80,123), ( 6,152,154), (211,215,207), ( 85, 87, 83), 61 | (239, 41, 41), (138,226, 52), (252,233, 79), (114,159,207), (173,127,168), 62 | ( 52,226,226), (255,255,255) 63 | ] 64 | 65 | fore_colors = [ 66 | (255,255,255), ( 0, 0, 0), (135, 0, 0), ( 0,135, 0), (135,135, 0), 67 | ( 0, 0,135), (135, 0,135), ( 0,135,135), (135,135,135), ( 46, 52, 54), 68 | (204, 0, 0), ( 78,154, 6), (196,160, 0), ( 52,101,164), (117, 80,123), 69 | ( 6,152,154), (211,215,207), ( 85, 87, 83), (239, 41, 41), (138,226, 52), 70 | (252,233, 79), (114,159,207), (173,127,168), ( 52,226,226), (255,255,255), 71 | ( 85, 87, 83), (239, 41, 41), (138,226, 52), (252,233, 79), (114,159,207), 72 | (173,127,168), ( 52,226,226), (255,255,255) 73 | ] 74 | 75 | # graphics rendition settings for bold, dim, underlined, 76 | # inverse, hidden, fgcolor, bgcolor respectively 77 | GFX_BOLD = 0x001 78 | GFX_DIM = 0x002 79 | GFX_UL = 0x008 80 | GFX_INV = 0x040 81 | GFX_HIDE = 0x080 82 | GFX_FG = 0x100 83 | GFX_BG = 0x200 84 | 85 | # special for detecting line wrap when selecting text 86 | GFX_WRITTEN = 0x400 87 | 88 | def get_colors(rendition): 89 | fg = bg = None 90 | if rendition & GFX_BG: 91 | bg = colors[(rendition >> 24) & 0xff] 92 | else: 93 | bg = back_colors[(rendition >> 24) & 0x1f] 94 | if rendition & GFX_FG: 95 | if ((rendition >> 16) & 0xff) < 16: 96 | if rendition & GFX_BOLD: 97 | fg = fore_colors[((rendition >> 16)&7)+17] 98 | else: 99 | fg = fore_colors[((rendition >> 16) & 0xf) + 9] 100 | else: 101 | fg = colors[(rendition >> 16) & 0xff] 102 | elif (rendition & 0x1f0000) == 0 or (rendition & GFX_DIM): 103 | fg = fore_colors[(rendition >> 16) & 0x1f] 104 | elif rendition & GFX_BOLD: 105 | fg = fore_colors[((rendition >> 16) & 0x1f) + 16] 106 | else: 107 | fg = fore_colors[((rendition >> 16) & 0x1f) + 8] 108 | if rendition & GFX_INV: 109 | fg, bg = bg, fg 110 | return fg, bg 111 | -------------------------------------------------------------------------------- /src/terminal/screen.py: -------------------------------------------------------------------------------- 1 | import array 2 | 3 | from . import rendition 4 | 5 | class Screen: 6 | def __init__(self, rows, cols): 7 | self.reset(rows, cols) 8 | 9 | def reset(self, rows, cols): 10 | self.cols = cols 11 | self.rows = rows 12 | self.cells = [] 13 | self.gfx = [] 14 | self.empty_line = array.array("u", u" "*cols) 15 | self.empty_gfx = array.array("I", [0]*cols) 16 | 17 | for i in range(0, rows): 18 | self.cells.append(array.array("u", self.empty_line)) 19 | self.gfx.append(array.array("I", self.empty_gfx)) 20 | 21 | def scroll_up(self, scroll_top, scroll_bottom, alt, current_gfx): 22 | top_screen = self.cells.pop(scroll_top) 23 | top_gfx = self.gfx.pop(scroll_top) 24 | if scroll_top == 0 and scroll_bottom == self.rows -1 and alt: 25 | top_screen = array.array("u", self.empty_line) 26 | top_gfx = array.array("I", self.empty_gfx) 27 | else: 28 | top_screen[0:self.cols] = array.array("u", self.empty_line) 29 | top_gfx[0:self.cols] = array.array("I", self.empty_gfx) 30 | for i in range(0, self.cols): 31 | top_gfx[i] = current_gfx 32 | self.cells.insert(scroll_bottom, top_screen) 33 | self.gfx.insert(scroll_bottom, top_gfx) 34 | 35 | def resize(self, rows, cols): 36 | if rows > self.rows: 37 | for row in range(self.rows, rows): 38 | self.cells.append(array.array("u", self.empty_line)) 39 | self.gfx.append(array.array("I", self.empty_gfx)) 40 | elif rows < self.rows: 41 | self.cells = self.cells[:rows] 42 | self.gfx = self.gfx[:rows] 43 | if cols > self.cols: 44 | for row in range(0, rows): 45 | for col in range(self.cols, cols): 46 | self.cells[row].append(u" ") 47 | self.gfx[row].append(0) 48 | self.empty_line = array.array("u", u" "*cols) 49 | self.empty_gfx = array.array("I", [0]*cols) 50 | elif cols < self.cols: 51 | for row in range(0, rows): 52 | self.cells[row] = self.cells[row][0:cols] 53 | self.gfx[row] = self.gfx[row][0:cols] 54 | self.empty_line = self.empty_line[0:cols] 55 | self.empty_gfx = self.empty_gfx[0:cols] 56 | self.rows = rows 57 | self.cols = cols 58 | 59 | def write_char(self, cursor, ch, gfx): 60 | self.cells[cursor.y][cursor.x] = ch 61 | self.gfx[cursor.y][cursor.x] = gfx | rendition.GFX_WRITTEN 62 | 63 | def erase_rectangle(self, top_row, left_col, bot_row, right_col, gfx=0): # XXX: need to pass in active rendition 64 | for y in range(top_row, bot_row): 65 | if y < 0 or y >= self.rows: 66 | continue 67 | for x in range(left_col, right_col): 68 | if x < 0 or x >= self.cols: 69 | continue 70 | self.cells[y][x] = u" " 71 | self.gfx[y][x] = gfx 72 | -------------------------------------------------------------------------------- /support/gen-term-colors.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | def generate_colors(): 4 | # System colors 5 | dim_colors = [(0,0,0), (135, 0, 0), (0, 135, 0), (135, 135, 0), 6 | (0, 0, 135), (135, 0, 135), (0, 135, 135), (135, 135, 135)] 7 | normal_colors = [(46, 52, 54), (204, 0, 0), (78, 154, 6), (196, 160, 0), 8 | (52, 101, 164), (117, 80, 123), (6, 152, 154), (211, 215, 207)] 9 | bright_colors = [(85, 87, 83), (239, 41, 41), (138, 226, 52), (252, 233, 79), 10 | (114, 159, 207), (173, 127, 168), (52, 226, 226), (255,255,255)] 11 | 12 | # Create color arrays for normal mode 13 | fore_colors = [(255,255,255)] + dim_colors + normal_colors + bright_colors + bright_colors 14 | back_colors = [(0,0,0)] + normal_colors + bright_colors 15 | 16 | # Create color array for 256-color mode 17 | colors = normal_colors + bright_colors 18 | 19 | values = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff] 20 | for red in values: 21 | for green in values: 22 | for blue in values: 23 | color = (red, green, blue) 24 | colors.append(color) 25 | 26 | values = [0x08, 0x12, 0x1c, 0x26, 0x30, 0x3a, 0x44, 0x4e, 0x58, 0x62, 0x6c, 0x76, 0x80, 0x8a, 0x94, 0x9e, 27 | 0xa8, 0xb2, 0xbc, 0xc6, 0xd0, 0xda, 0xe4, 0xee] 28 | for gray in values: 29 | color = (gray, gray, gray) 30 | colors.append(color) 31 | 32 | def genstringforcolors(colors): 33 | s2 = [] 34 | i = 0 35 | for c in colors: 36 | if i > 0 and i % 5 == 0: 37 | s2.append("\n\t") 38 | s2.append("(%3i,%3i,%3i), " % (c[0],c[1],c[2])) 39 | i = i + 1 40 | return "".join(s2)[:-2] 41 | 42 | print("colors = [\n\t%s\n]" % genstringforcolors(colors)) 43 | print("back_colors = [\n\t%s\n]" % genstringforcolors(back_colors)) 44 | print("fore_colors = [\n\t%s\n]" % genstringforcolors(fore_colors)) 45 | 46 | generate_colors() 47 | -------------------------------------------------------------------------------- /terminal/__init__.py: -------------------------------------------------------------------------------- 1 | from . import emulator 2 | 3 | -------------------------------------------------------------------------------- /terminal/ctrl.py: -------------------------------------------------------------------------------- 1 | NUL = 0x0 # NULL 2 | SP = 0x20 # space 3 | BEL = 0x07 # ^G) beeps; 4 | BS = 0x08 # ^H) backspaces one column (but not past the beginning of the line); 5 | HT = 0x09 # ^I) goes to the next tab stop or to the end of the line if there is no earlier tab stop; 6 | LF = 0x0A # ^J) 7 | VT = 0x0B # ^K) and FF (0x0C, ^L) all give a linefeed, and if LF/NL (new-line mode) is set also a carriage return; 8 | FF = 0x0C # see VT 9 | CR = 0x0D # ^M) gives a carriage return; 10 | SO = 0x0E # ^N) activates the G1 character set; 11 | SI = 0x0F # ^O) activates the G0 character set; 12 | CAN = 0x18 # ^X) and SUB (0x1A, ^Z) interrupt escape sequences; 13 | SUB = 0x1A # see CAN 14 | ESC = 0x1B # ^[) starts an escape sequence; 15 | DEL = 0x7F # is ignored; 16 | CSI = 0x9B # is equivalent to ESC [. 17 | -------------------------------------------------------------------------------- /terminal/cursor.py: -------------------------------------------------------------------------------- 1 | class Cursor: 2 | def __init__(self, x, y, visible = True): 3 | self.x = x 4 | self.y = y 5 | self.visible = visible 6 | -------------------------------------------------------------------------------- /terminal/emulator.py: -------------------------------------------------------------------------------- 1 | from . import ctrl, esc, cursor, screen 2 | 3 | class Emulator: 4 | def __init__(self, rows=80, cols=25, debug=True): 5 | 6 | # configure two supported screens and cursors 7 | self.cols, self.rows = cols, rows 8 | self.screens = [screen.Screen(rows, cols), screen.Screen(rows, cols)] 9 | self.cursors = [cursor.Cursor(0,0), cursor.Cursor(0, 0)] 10 | 11 | # set currently active screen, cursor, scroll region and graphics rendition settings 12 | self.screen = self.screens[0] 13 | self.cursor = self.cursors[0] 14 | self.scroll_bottom = rows - 1 15 | self.scroll_top = 0 16 | self.gfx = 0 17 | 18 | # vars for parser state machine of escape sequences etc 19 | self.escape_str = "" 20 | self.in_escape = False # in escape sequence 21 | self.in_csi = False # in Control Sequence Introducer 22 | 23 | # xterm set title support 24 | self.current_title = None # currently set title 25 | self.set_title = False # set window title 26 | self.ignore_title = True # ignore setting of window title 27 | 28 | # misc settings 29 | self.tabstop = 8 # amount of spaces in a tab 30 | self.draw_lines = False # line drawing mode 31 | self.insert_mode = False # insert mode for drawing characters 32 | self.cursor_keys = False # interpet cursor keys on numpad as keys or not 33 | 34 | # references to callback functions 35 | self.callback_data = None # respond with data to f.e. a specific CSI sequence 36 | self.callback_update = None # let caller know there's new data available 37 | self.callback_title = None # inform caller of updated window title 38 | 39 | # debug log support 40 | self.debug = debug 41 | self.debuglog = [] 42 | self.debugloglen = 256 # maximum number of lines stored in self.debuglog 43 | 44 | # control character dispatch 45 | self.ctrl_dispatch = { 46 | ctrl.BEL : self.bell, 47 | ctrl.BS : self.backspace, 48 | ctrl.HT : self.htab, 49 | ctrl.LF : self.lf, 50 | ctrl.VT : self.lf, 51 | ctrl.FF : self.lf, 52 | ctrl.CR : self.cr, 53 | ctrl.SO : self.shift_out, 54 | ctrl.SI : self.shift_in, 55 | } 56 | 57 | # escape sequence dispatcher for CSI escape sequences as per VT102 58 | self.csi_dispatch = { 59 | esc.ICH : self.insert_chars, 60 | esc.CUU : self.cursor_up, 61 | esc.CUD : self.cursor_down, 62 | esc.CUF : self.cursor_forward, 63 | esc.CUB : self.cursor_back, 64 | esc.CNL : self.cursor_next_line, 65 | esc.CPL : self.cursor_prev_line, 66 | esc.CHA : self.cursor_halign, 67 | esc.CUP : self.cursor_set, 68 | esc.ED : self.erase_data, 69 | esc.EL : self.erase_in_line, 70 | esc.IL : self.insert_lines, 71 | esc.DL : self.delete_lines, 72 | esc.DCH : self.delete_characters, 73 | esc.ECH : self.erase_characters, 74 | esc.HPR : self.cursor_forward, 75 | esc.DA : self.report_da, 76 | esc.VPA : self.cursor_set, 77 | #esc.VPR : self.vertical_position_relative, 78 | #esc.HVP : self.hvposition, 79 | esc.TBC : self.tabulation_clear, 80 | esc.SM : self.set_mode, 81 | esc.RM : self.reset_mode, 82 | esc.SGR : self.select_gfx, 83 | esc.DSR : self.report_status, 84 | esc.DECSTBM : self.scroll_region, 85 | esc.HPA : self.cursor_halign, 86 | #esc.RIS : self.reset, 87 | #esc.IND : self.index, 88 | #esc.RI : self.rindex, 89 | #esc.NEL : self.nextline, 90 | esc.DECSC : self.cursor_save, 91 | esc.DECRC : self.cursor_restore, 92 | } 93 | 94 | # charset setting identifiers used for non "standard" escape sequences etc 95 | self.charset = [" ", "#", "%", "(", ")", "*", "+"] 96 | 97 | # replace key chars with values when in line drawing mode 98 | self.line_draw_map = { 99 | u"j": u"\xe2\x94\x98", 100 | u"k": u"\xe2\x94\x90", 101 | u"l": u"\xe2\x94\x8c", 102 | u"m": u"\xe2\x94\x94", 103 | u"n": u"\xe2\x94\xbc", 104 | u"q": u"\xe2\x94\x80", 105 | u"t": u"\xe2\x94\x9c", 106 | u"u": u"\xe2\x94\xa4", 107 | u"v": u"\xe2\x94\xb4", 108 | u"w": u"\xe2\x94\xac", 109 | u"x": u"\xe2\x94\x82", 110 | } 111 | 112 | def set_update_callback(self, cb): 113 | self.callback_update = cb 114 | 115 | def set_data_callback(self, cb): 116 | self.callback_data = cb 117 | 118 | def set_title_callback(self, cb): 119 | self.callback_title = cb 120 | 121 | def update_callback(self): 122 | if self.callback_update: 123 | self.callback_update() 124 | 125 | def data_callback(self, data): 126 | if self.callback_data: 127 | self.callback_data(data) 128 | 129 | def title_callback(self, title): 130 | if title == self.current_title: 131 | return 132 | self.current_title = title 133 | if self.callback_title: 134 | self.callback_title(self.current_title) 135 | 136 | def shift_in(self): 137 | raise Exception("shift in") 138 | 139 | def shift_out(self): 140 | raise Exception("shift out") 141 | 142 | def bell(self): 143 | pass 144 | 145 | def backspace(self): 146 | if self.cursor.x > 0: 147 | self.cursor.x = self.cursor.x - 1 148 | 149 | def htab(self): 150 | self.cursor.x = self.cursor.x + self.tabstop - (self.cursor.x % self.tabstop) 151 | if self.cursor.x > self.cols: 152 | self.cursor.x = self.cols 153 | 154 | def cursor_save(self, *params): 155 | print("Save cursor1") 156 | #raise Exception("save cursor") 157 | 158 | def cursor_restore(self, *params): 159 | print("Save cursor2") 160 | #raise Exception("restore cursor") 161 | 162 | def insert_lines(self, count=None): 163 | pass 164 | 165 | def insert_chars(self, count=None): 166 | #raise Exception("todo") 167 | pass 168 | 169 | def cursor_up(self, count=None): 170 | self.cursor.y += count or 1 171 | self.fix_cursors() 172 | 173 | def cursor_down(self, count=None): 174 | self.cursor.y -= count or 1 175 | self.fix_cursors() 176 | 177 | def cursor_forward(self, count=None): 178 | self.cursor.x += count or 1 179 | self.fix_cursors() 180 | 181 | def cursor_back(self, count=None): 182 | self.cursor.x -= count or 1 183 | self.fix_cursors() 184 | 185 | def cursor_next_line(self, count=None): 186 | self.cursor_down(count) 187 | self.cursor.x = 0 188 | 189 | def cursor_prev_line(self, count=None): 190 | self.cursor_up(count) 191 | self.cursor.x = 0 192 | 193 | def cursor_halign(self, param=None): 194 | raise Exception("!!!!", param) 195 | if param: 196 | self.cursor.x = param - 1 197 | self.fix_cursors() 198 | 199 | def cursor_set(self, y = None, x = None): 200 | x = 0 if not x or x == 0 else x - 1 201 | y = 0 if not y or y == 0 else y - 1 202 | self.cursor.x = x 203 | self.cursor.y = y 204 | self.fix_cursors() 205 | 206 | def fix_cursor_bounds(self, cursor): 207 | if cursor.x > self.cols: 208 | cursor.x = self.cols 209 | if cursor.y >= self.rows: 210 | cursor.y = self.rows - 1 211 | 212 | def fix_cursors(self): 213 | self.fix_cursor_bounds(self.cursors[0]) 214 | self.fix_cursor_bounds(self.cursors[1]) 215 | 216 | def delete_lines(self, count): 217 | raise Exception("delete lines") 218 | 219 | def delete_characters(self, *params): 220 | raise Exception("delete characters") 221 | 222 | def report_da(self, *params): 223 | self.data_callback("\033[?1;2c") 224 | 225 | def is_alternative_screen(self): 226 | return self.screen == self.screens[1] 227 | 228 | def set_mode(self, *params): 229 | if len(params) < 0: 230 | return 231 | private = False 232 | if params[-1] == "?": 233 | private = True 234 | params = params[:-1] 235 | for p in params: 236 | if p == 4: 237 | self.insert_mode = True 238 | elif p == 1049 or p == 47 and not self.is_alternative_screen(): 239 | self.screen = self.screen[1] 240 | self.cursor = self.cursor[1] 241 | elif p == 1: 242 | self.cursor_keys = True 243 | elif p == 2: 244 | pass 245 | elif p == 7: 246 | pass 247 | elif p == 12: 248 | pass 249 | elif p == 25: 250 | raise Exception("visible cursor") 251 | self.cursor.visible = True 252 | elif p == 0: 253 | pass 254 | else: 255 | raise Exception("set mode unkonwn: %s" % p) 256 | 257 | 258 | def reset_mode(self, *params): 259 | if len(params) < 0: 260 | return 261 | private = False 262 | if params[-1] == "?": 263 | private = True 264 | params = params[:-1] 265 | for p in params: 266 | if p == 4: 267 | self.insert_mode = False 268 | elif p == 1049 or p == 47 and self.is_alternative_screen(): 269 | self.screen = self.screen[0] 270 | self.cursor = self.cursor[0] 271 | elif p == 1: 272 | self.cursor_keys = False 273 | elif p == 2: 274 | pass 275 | elif p == 7: 276 | pass 277 | elif p == 12: 278 | pass 279 | elif p == 25: 280 | raise Exception("not visible cursor") 281 | self.cursor.visible = False 282 | elif p == 0: 283 | pass 284 | else: 285 | raise Exception("set mode unkonwn: %s" % p) 286 | 287 | def report_status(self, param=None): 288 | if not param or param not in [5, 6]: 289 | return 290 | if param == 5: 291 | self.data_callback("\033[0n") 292 | elif param == 6: 293 | self.data_callback("\033[%d;%dR" % (self.cursor.y + 1, self.cursor.x + 1)) 294 | 295 | def scroll_region(self, *params): 296 | if len(params) < 2: 297 | return 298 | 299 | self.scroll_top = params[0] - 1 300 | self.scroll_bottom = params[1] - 1 301 | if self.scroll_top < 0: 302 | self.scroll_top = 0 303 | elif self.scroll_top >= self.rows: 304 | self.scroll_top = self.rows - 1 305 | if self.scroll_bottom < 0: 306 | self.scroll_bottom = 0 307 | elif self.scroll_bottom >= self.rows: 308 | self.scroll_bottom = self.rows - 1 309 | 310 | def select_gfx(self, *params): 311 | i = 0 312 | lp = len(params) 313 | # ISO-8613-3 support for 256-colors is implemented 314 | # 24-bit color support is not implemented 315 | if (lp == 0): 316 | raise Exception("no args to gfx") 317 | while i < lp: 318 | p = params[i] 319 | if p == 0: 320 | # default graphics rendition 321 | self.gfx = 0 322 | elif p >= 1 and p <= 9: 323 | # set a style 324 | self.gfx &= ~0xff 325 | self.gfx |= 1 << (p - 1) 326 | elif p >= 21 and p <= 29: 327 | # clear a style 328 | self.gfx &= ~(1 << (p - 21)) 329 | elif p >= 30 and p <= 37: 330 | self.gfx &= ~(0x00FF0000 | screen.GFX_FG) 331 | self.gfx |= ((p - 29) << 16) 332 | elif p == 38 and i + 2 < len(params): 333 | if params[i+1] == 5: 334 | self.gfx &= ~0x00ff0000 335 | self.gfx |= screen.GFX_FG 336 | self.gfx |= (params[i+2] & 0xff) << 16 337 | i = i + 2 338 | elif p == 39: 339 | self.gfx &= ~(0x00ff0000 | screen.GFX_FG) 340 | elif p >= 40 and p <= 47: 341 | self.gfx &= ~(0xFF000000 | screen.GFX_BG) 342 | self.gfx |= ((p - 39) << 24) 343 | elif p == 48 and i + 2 < len(params): 344 | if params[i+1] == 5: 345 | self.gfx &= ~0x00ff0000 346 | self.gfx |= screen.GFX_BG 347 | self.gfx |= (params[i+2] & 0xff) << 24 348 | i = i + 2 349 | elif p == 49: 350 | self.gfx &= ~(0xff000000 | screen.GFX_BG) 351 | elif p >= 90 and p <= 97: 352 | self.gfx &= ~(0x00ff0000 | screen.GFX_FG) 353 | self.gfx |= ((p - 81) << 16) 354 | elif p >= 100 and p <= 107: 355 | self.gfx &= ~(0xff000000 | screen.GFX_BG) 356 | self.gfx |= ((p - 91) << 16) 357 | else: 358 | raise Exception("unsupported gfx rendition %i" % p) 359 | i = i + 1 360 | 361 | def tabulation_clear(self, param = 0): 362 | if param == 0: 363 | self.tabstops.discard(self.cursor.x) 364 | elif param == 3: 365 | self.tabstops = set() 366 | 367 | def erase_characters(self, count=None): 368 | if not count or count == 0: 369 | count = 1 370 | self.screen.erase_rectangle(self.cursor.y, self.cursor.x, self.cursor.y + 1, self.x + count, self.gfx) 371 | 372 | def erase_in_line(self, param = None): 373 | if not param: 374 | param = 0 375 | if param == 0: 376 | self.screen.erase_rectangle(self.cursor.y, self.cursor.x, self.cursor.y + 1, self.cols, self.gfx) 377 | elif param == 1: 378 | self.screen.erase_rectangle(self.cursor.y, 0, self.cursor.y + 1, self.cursor.x + 1, self.gfx) 379 | elif param == 2: 380 | self.screen.erase_rectangle(self.cursor.y, 0, self.cursor.y + 1, self.cols, self.gfx) 381 | 382 | def erase_data(self, param = None): 383 | if not param: 384 | param = 0 385 | if param == 0: 386 | self.screen.erase_rectangle(self.cursor.y, self.cursor.x, self.cursor.y + 1, self.cols, self.gfx) 387 | self.screen.erase_rectangle(self.cursor.y + 1, 0, self.rows, self.cols, self.gfx) 388 | elif param == 1: 389 | self.screen.erase_rectangle(0, 0, self.cursor.y, self.cols, self.gfx) 390 | self.screen.erase_rectangle(self.cursor.y, 0, self.cursor.y + 1, self.cursor.x + 1, self.gfx) 391 | elif param == 2: 392 | self.screen.erase_rectangle(0, 0, self.rows, self.cols, self.gfx) 393 | self.cursor.x, self.cursor.y = 0, 0 394 | 395 | def resize(self, rows, cols): 396 | if rows == self.rows and cols == self.cols: 397 | return 398 | self.screens[0].resize(rows, cols) 399 | self.screens[1].resize(rows, cols) 400 | self.scroll_top = 0 401 | self.scroll_bottom = rows - 1 402 | self.rows = rows 403 | self.cols = cols 404 | self.fix_cursors() 405 | 406 | def lf(self): 407 | if self.cursor.y >= self.scroll_bottom: 408 | self.screen.scroll_up(self.scroll_top, self.scroll_bottom, self.is_alternative_screen(), self.gfx) 409 | else: 410 | self.cursor.y += 1 411 | 412 | def cr(self): 413 | self.cursor.x = 0 414 | 415 | def newline(self): 416 | self.lf() 417 | self.cursor.x = 0 418 | 419 | def write_char(self, ch): 420 | if self.cursor.x >= self.cols: 421 | self.newline() 422 | 423 | if self.draw_lines: 424 | if ch in self.linemap: 425 | ch = self.linemap[ch] 426 | 427 | if self.insert_mode: 428 | self.insert_chars([1]) 429 | 430 | self.screen.write_char(self.cursor, ch, self.gfx) 431 | self.cursor.x += 1 432 | 433 | self.update_callback() 434 | 435 | def parse_escape_sequence(self, data): 436 | l = len(data) 437 | if l == 0: 438 | # XXX log 439 | raise Exception("unhandled escape seq") 440 | return 441 | 442 | if data[0] != "[": 443 | # ignore numpad handling 444 | if data[0] in ["=", ">"]: 445 | return 446 | else: 447 | raise Exception("unhandled data %s" % data) 448 | 449 | seq = data[1:-1] 450 | mode = ord(data[-1]) 451 | option = None 452 | if len(seq) > 1 and seq[0] in ["?", ">", "!"]: 453 | option = seq[0] 454 | seq = seq[1] 455 | try: 456 | if len(seq) > 0: 457 | params = [int(x) for x in seq.split(";")] 458 | else: 459 | params = [0] 460 | except Exception as e: 461 | params = [0] 462 | 463 | if mode not in self.csi_dispatch: 464 | s="".join(["%x " % ord(x) for x in data]) 465 | s2="".join(["%c " % ord(x) for x in data]) 466 | self.write_debug_logdata("! unknown CSI: %s [%s]" % (s2, s)) 467 | return 468 | 469 | if not option: 470 | self.csi_dispatch[mode](*params) 471 | else: 472 | self.csi_dispatch[mode](*params, option) 473 | self.write_debug_logdata("ESC %s -> %s" % (data, self.csi_dispatch[mode])) 474 | 475 | def write_debug_logdata(self, data): 476 | if not self.debug: 477 | return 478 | data = data.splitlines() 479 | for line in data: 480 | self.debuglog.append(line) 481 | ld = len(self.debuglog) 482 | if ld > self.debugloglen: 483 | self.debuglog = self.debuglog[ld - self.debugloglen:] 484 | 485 | def parse_data(self, data): 486 | for c in data: 487 | oc = ord(c) 488 | if self.set_title: 489 | if oc != ctrl.BEL: 490 | self.escape_str += c 491 | continue 492 | if self.ignore_title == False: 493 | self.title_callback(self.escape_str) 494 | self.escape_str = "" 495 | self.set_title = False 496 | continue 497 | elif oc in self.ctrl_dispatch: 498 | self.ctrl_dispatch[oc]() 499 | continue 500 | elif self.in_escape and not self.in_csi: 501 | self.escape_str += c 502 | l = len(self.escape_str) 503 | if l == 1 and c == "[": 504 | self.in_csi = True 505 | continue 506 | elif l == 1 and c != "[" and c != "]" and c not in self.charset: 507 | self.parse_escape_sequence(self.escape_str) 508 | self.escape_str = "" 509 | self.in_escape = False 510 | continue 511 | elif l == 2 and self.escape_str[0] in self.charset: 512 | if self.escape_str == "(0": 513 | self.draw_lines = True 514 | else: 515 | self.draw_lines = False 516 | self.escape_str = "" 517 | self.in_escape = False 518 | continue 519 | elif l > 1 and self.escape_str[0] == "]" and c == ";": 520 | self.set_title = True 521 | try: 522 | param = [int(x) for x in self.escape_str[1:-1].split(";")] 523 | except: 524 | param = [0] 525 | if len(param) == 0 or param[0]==0 or param[0] == 2: 526 | self.ignore_title = False 527 | else: 528 | self.ignore_title = True 529 | self.in_escape = False 530 | self.escape_str = "" 531 | continue 532 | elif self.in_csi: 533 | self.escape_str += c 534 | if oc >= ord("@") and oc <= ord("~"): 535 | self.parse_escape_sequence(self.escape_str) 536 | self.in_csi = False 537 | self.in_escape = False 538 | self.escape_str = "" 539 | continue 540 | elif oc == ctrl.ESC: 541 | self.in_escape = True 542 | continue 543 | else: 544 | self.write_char(c) 545 | 546 | def input_data(self, data): 547 | try: 548 | data = data.decode(encoding="utf8") 549 | self.parse_data(data) 550 | except Exception as e: 551 | self.write_debug_logdata(e) 552 | -------------------------------------------------------------------------------- /terminal/esc.py: -------------------------------------------------------------------------------- 1 | # Taken from: VT102 User Guide 2 | # found http://vt100.net/docs/vt102-ug/chapter5.html 3 | ICH = 64 # "@" -- Insert Blank Characters 4 | CUU = 65 # "A" -- Cursur Up 5 | CUD = 66 # "B" -- Cursor Down 6 | CUF = 67 # "C" -- Cursor Forward 7 | CUB = 68 # "D" -- Cursor Backward 8 | CNL = 69 # "E" -- Cursor Next line 9 | CPL = 70 # "F" -- Cursor Previous Line 10 | CHA = 71 # "G" -- Cursor Horizontal Align 11 | CUP = 72 # "H" -- Cursor Position 12 | ED = 74 # "J" -- Erase data 13 | EL = 75 # "K" -- Erase in line 14 | IL = 76 # "L" -- Insert line 15 | DL = 77 # "M" -- Delete line 16 | DCH = 80 # "P" -- Delete character 17 | ECH = 88 # "X" -- Erase character 18 | HPR = 97 # "a" -- Horizontal Postion Relative 19 | DA = 99 # "c" -- Device Attributes 20 | VPA = 100 # "d" -- Vertial Position Adjust 21 | VPR = 101 # "e" -- Vertical Position Relative 22 | HVP = 102 # "f" -- Horizontal / Vertical postion 23 | TBC = 103 # "g" -- Tabulation Clear 24 | SM = 104 # "h" -- Set Mode 25 | RM = 108 # "l" -- Reset Mode" 26 | SGR = 109 # "m" -- Select Graphics rendition" 27 | DSR = 110 # "n" -- Device Status Report" 28 | DECSTBM = 114 # "r" -- Select Top and Bottom Margins 29 | HPA = 39 # "'" -- Horizontal Position Adjust 30 | RIS = 99 # "c" -- Reset to Initial State 31 | IND = 68 # "D" -- Index 32 | RI = 77 # "M" -- Reverse Index 33 | NEL = 69 # "E" -- Next Line 34 | DECSC = 55 # "7" -- Save Cursor 35 | DECRC = 56 # "8" -- Restore Cursor 36 | -------------------------------------------------------------------------------- /terminal/process.py: -------------------------------------------------------------------------------- 1 | import pty, os, subprocess, fcntl, termios 2 | import struct, select, threading 3 | 4 | from . import emulator 5 | 6 | class TerminalProcessThread(threading.Thread): 7 | def __init__(self, rows, cols, cmd="/bin/sh"): 8 | super(TerminalProcessThread, self).__init__() 9 | 10 | self.pipes = os.pipe() 11 | self.pid, self.fd = pty.fork() 12 | if self.pid == 0: 13 | os.environ["TERM"] = "xterm-256color" 14 | ret = subprocess.call(cmd, close_fds=True) 15 | os.write(self.pipes[1], "\x00") 16 | os._exit(1) 17 | os.close(self.pipes[1]) 18 | self.stopped = False 19 | 20 | self.emulator = emulator.Emulator(rows, cols) 21 | self.set_rowcol_pty() 22 | 23 | def input(self, data): 24 | ret = False 25 | try: 26 | ret = os.write(self.fd, bytes(data, encoding="utf-8")) 27 | except Exception as e: 28 | print(e) 29 | 30 | def stop(self): 31 | self.stopped = True 32 | 33 | def _run(self): 34 | timeout = 0.01 35 | i, o, e = select.select([self.fd, self.pipes[0]], [], [], timeout) 36 | if self.fd in i: 37 | try: 38 | data = os.read(self.fd, 4096) 39 | self.emulator.input_data(data) 40 | except: 41 | pass 42 | 43 | if self.pipes[0] in i: 44 | try: 45 | data = os.read(self.pipes[0], 1) 46 | except: 47 | pass 48 | self.stop() 49 | 50 | def run(self): 51 | while not self.stopped: 52 | self._run() 53 | 54 | os.close(self.fd) 55 | os.close(self.pipes[0]) 56 | 57 | def set_rowcol_pty(self): 58 | data = struct.pack("HHHH", self.emulator.rows, self.emulator.cols, 0, 0) 59 | fcntl.ioctl(self.fd, termios.TIOCSWINSZ, data) 60 | attribute = termios.tcgetattr(self.fd) 61 | termios.tcsetattr(self.fd, termios.TCSAFLUSH, attribute) 62 | 63 | def resize(self, rows, cols): 64 | # prevent unnecessary updates 65 | if rows == self.emulator.rows and cols == self.emulator.cols: 66 | return 67 | self.emulator.resize(rows, cols) 68 | self.set_rowcol_pty() 69 | -------------------------------------------------------------------------------- /terminal/rendition.py: -------------------------------------------------------------------------------- 1 | """ 2 | generate the color scheme with the code below 3 | 4 | def generate_colors(): 5 | # System colors 6 | dim_colors = [(0,0,0), (135, 0, 0), (0, 135, 0), (135, 135, 0), 7 | (0, 0, 135), (135, 0, 135), (0, 135, 135), (135, 135, 135)] 8 | normal_colors = [(46, 52, 54), (204, 0, 0), (78, 154, 6), (196, 160, 0), 9 | (52, 101, 164), (117, 80, 123), (6, 152, 154), (211, 215, 207)] 10 | bright_colors = [(85, 87, 83), (239, 41, 41), (138, 226, 52), (252, 233, 79), 11 | (114, 159, 207), (173, 127, 168), (52, 226, 226), (255,255,255)] 12 | 13 | # Create color arrays for normal mode 14 | fore_colors = [(255,255,255)] + dim_colors + normal_colors + bright_colors + bright_colors 15 | back_colors = [(0,0,0)] + normal_colors + bright_colors 16 | 17 | # Create color array for 256-color mode 18 | colors = normal_colors + bright_colors 19 | 20 | values = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff] 21 | for red in values: 22 | for green in values: 23 | for blue in values: 24 | color = (red, green, blue) 25 | colors.append(color) 26 | 27 | values = [0x08, 0x12, 0x1c, 0x26, 0x30, 0x3a, 0x44, 0x4e, 0x58, 0x62, 0x6c, 0x76, 0x80, 0x8a, 0x94, 0x9e, 28 | 0xa8, 0xb2, 0xbc, 0xc6, 0xd0, 0xda, 0xe4, 0xee] 29 | for gray in values: 30 | color = (gray, gray, gray) 31 | colors.append(color) 32 | 33 | def genstringforcolors(colors): 34 | s2 = [] 35 | i = 0 36 | for c in colors: 37 | if i > 0 and i % 5 == 0: 38 | s2.append("\n\t") 39 | s2.append("(%3i,%3i,%3i), " % (c[0],c[1],c[2])) 40 | i = i + 1 41 | return "".join(s2)[:-2] 42 | 43 | print "colors = [\n\t%s\n]" % genstringforcolors(colors) 44 | print "back_colors = [\n\t%s\n]" % genstringforcolors(back_colors) 45 | print "fore_colors = [\n\t%s\n]" % genstringforcolors(fore_colors) 46 | 47 | generate_colors() 48 | """ 49 | colors = [ 50 | ( 46, 52, 54), (204, 0, 0), ( 78,154, 6), (196,160, 0), ( 52,101,164), 51 | (117, 80,123), ( 6,152,154), (211,215,207), ( 85, 87, 83), (239, 41, 41), 52 | (138,226, 52), (252,233, 79), (114,159,207), (173,127,168), ( 52,226,226), 53 | (255,255,255), ( 0, 0, 0), ( 0, 0, 95), ( 0, 0,135), ( 0, 0,175), 54 | ( 0, 0,215), ( 0, 0,255), ( 0, 95, 0), ( 0, 95, 95), ( 0, 95,135), 55 | ( 0, 95,175), ( 0, 95,215), ( 0, 95,255), ( 0,135, 0), ( 0,135, 95), 56 | ( 0,135,135), ( 0,135,175), ( 0,135,215), ( 0,135,255), ( 0,175, 0), 57 | ( 0,175, 95), ( 0,175,135), ( 0,175,175), ( 0,175,215), ( 0,175,255), 58 | ( 0,215, 0), ( 0,215, 95), ( 0,215,135), ( 0,215,175), ( 0,215,215), 59 | ( 0,215,255), ( 0,255, 0), ( 0,255, 95), ( 0,255,135), ( 0,255,175), 60 | ( 0,255,215), ( 0,255,255), ( 95, 0, 0), ( 95, 0, 95), ( 95, 0,135), 61 | ( 95, 0,175), ( 95, 0,215), ( 95, 0,255), ( 95, 95, 0), ( 95, 95, 95), 62 | ( 95, 95,135), ( 95, 95,175), ( 95, 95,215), ( 95, 95,255), ( 95,135, 0), 63 | ( 95,135, 95), ( 95,135,135), ( 95,135,175), ( 95,135,215), ( 95,135,255), 64 | ( 95,175, 0), ( 95,175, 95), ( 95,175,135), ( 95,175,175), ( 95,175,215), 65 | ( 95,175,255), ( 95,215, 0), ( 95,215, 95), ( 95,215,135), ( 95,215,175), 66 | ( 95,215,215), ( 95,215,255), ( 95,255, 0), ( 95,255, 95), ( 95,255,135), 67 | ( 95,255,175), ( 95,255,215), ( 95,255,255), (135, 0, 0), (135, 0, 95), 68 | (135, 0,135), (135, 0,175), (135, 0,215), (135, 0,255), (135, 95, 0), 69 | (135, 95, 95), (135, 95,135), (135, 95,175), (135, 95,215), (135, 95,255), 70 | (135,135, 0), (135,135, 95), (135,135,135), (135,135,175), (135,135,215), 71 | (135,135,255), (135,175, 0), (135,175, 95), (135,175,135), (135,175,175), 72 | (135,175,215), (135,175,255), (135,215, 0), (135,215, 95), (135,215,135), 73 | (135,215,175), (135,215,215), (135,215,255), (135,255, 0), (135,255, 95), 74 | (135,255,135), (135,255,175), (135,255,215), (135,255,255), (175, 0, 0), 75 | (175, 0, 95), (175, 0,135), (175, 0,175), (175, 0,215), (175, 0,255), 76 | (175, 95, 0), (175, 95, 95), (175, 95,135), (175, 95,175), (175, 95,215), 77 | (175, 95,255), (175,135, 0), (175,135, 95), (175,135,135), (175,135,175), 78 | (175,135,215), (175,135,255), (175,175, 0), (175,175, 95), (175,175,135), 79 | (175,175,175), (175,175,215), (175,175,255), (175,215, 0), (175,215, 95), 80 | (175,215,135), (175,215,175), (175,215,215), (175,215,255), (175,255, 0), 81 | (175,255, 95), (175,255,135), (175,255,175), (175,255,215), (175,255,255), 82 | (215, 0, 0), (215, 0, 95), (215, 0,135), (215, 0,175), (215, 0,215), 83 | (215, 0,255), (215, 95, 0), (215, 95, 95), (215, 95,135), (215, 95,175), 84 | (215, 95,215), (215, 95,255), (215,135, 0), (215,135, 95), (215,135,135), 85 | (215,135,175), (215,135,215), (215,135,255), (215,175, 0), (215,175, 95), 86 | (215,175,135), (215,175,175), (215,175,215), (215,175,255), (215,215, 0), 87 | (215,215, 95), (215,215,135), (215,215,175), (215,215,215), (215,215,255), 88 | (215,255, 0), (215,255, 95), (215,255,135), (215,255,175), (215,255,215), 89 | (215,255,255), (255, 0, 0), (255, 0, 95), (255, 0,135), (255, 0,175), 90 | (255, 0,215), (255, 0,255), (255, 95, 0), (255, 95, 95), (255, 95,135), 91 | (255, 95,175), (255, 95,215), (255, 95,255), (255,135, 0), (255,135, 95), 92 | (255,135,135), (255,135,175), (255,135,215), (255,135,255), (255,175, 0), 93 | (255,175, 95), (255,175,135), (255,175,175), (255,175,215), (255,175,255), 94 | (255,215, 0), (255,215, 95), (255,215,135), (255,215,175), (255,215,215), 95 | (255,215,255), (255,255, 0), (255,255, 95), (255,255,135), (255,255,175), 96 | (255,255,215), (255,255,255), ( 8, 8, 8), ( 18, 18, 18), ( 28, 28, 28), 97 | ( 38, 38, 38), ( 48, 48, 48), ( 58, 58, 58), ( 68, 68, 68), ( 78, 78, 78), 98 | ( 88, 88, 88), ( 98, 98, 98), (108,108,108), (118,118,118), (128,128,128), 99 | (138,138,138), (148,148,148), (158,158,158), (168,168,168), (178,178,178), 100 | (188,188,188), (198,198,198), (208,208,208), (218,218,218), (228,228,228), 101 | (238,238,238) 102 | ] 103 | 104 | back_colors = [ 105 | ( 0, 0, 0), ( 46, 52, 54), (204, 0, 0), ( 78,154, 6), (196,160, 0), 106 | ( 52,101,164), (117, 80,123), ( 6,152,154), (211,215,207), ( 85, 87, 83), 107 | (239, 41, 41), (138,226, 52), (252,233, 79), (114,159,207), (173,127,168), 108 | ( 52,226,226), (255,255,255) 109 | ] 110 | 111 | fore_colors = [ 112 | (255,255,255), ( 0, 0, 0), (135, 0, 0), ( 0,135, 0), (135,135, 0), 113 | ( 0, 0,135), (135, 0,135), ( 0,135,135), (135,135,135), ( 46, 52, 54), 114 | (204, 0, 0), ( 78,154, 6), (196,160, 0), ( 52,101,164), (117, 80,123), 115 | ( 6,152,154), (211,215,207), ( 85, 87, 83), (239, 41, 41), (138,226, 52), 116 | (252,233, 79), (114,159,207), (173,127,168), ( 52,226,226), (255,255,255), 117 | ( 85, 87, 83), (239, 41, 41), (138,226, 52), (252,233, 79), (114,159,207), 118 | (173,127,168), ( 52,226,226), (255,255,255) 119 | ] 120 | 121 | from . import screen 122 | 123 | def get_colors(rendition): 124 | fg = bg = None 125 | if rendition & screen.GFX_BG: 126 | bg = colors[(rendition >> 24) & 0xff] 127 | else: 128 | bg = back_colors[(rendition >> 24) & 0x1f] 129 | if rendition & screen.GFX_FG: 130 | if ((rendition >> 16) & 0xff) < 16: 131 | if rendition & screen.GFX_BOLD: 132 | fg = fore_colors[((rendition >> 16)&7)+17] 133 | else: 134 | fg = fore_colors[((rendition >> 16) & 0xf) + 9] 135 | else: 136 | fg = colors[(rendition >> 16) & 0xff] 137 | elif (rendition & 0x1f0000) == 0 or (rendition & screen.GFX_DIM): 138 | fg = fore_colors[(rendition >> 16) & 0x1f] 139 | elif rendition & screen.GFX_BOLD: 140 | fg = fore_colors[((rendition >> 16) & 0x1f) + 16] 141 | else: 142 | fg = fore_colors[((rendition >> 16) & 0x1f) + 8] 143 | if rendition & screen.GFX_INV: 144 | fg, bg = bg, fg 145 | return fg, bg 146 | -------------------------------------------------------------------------------- /terminal/screen.py: -------------------------------------------------------------------------------- 1 | import array 2 | 3 | # graphics rendition settings for bold, dim, underlined, 4 | # inverse, hidden, fgcolor, bgcolor respectively 5 | GFX_BOLD = 0x001 6 | GFX_DIM = 0x002 7 | GFX_UL = 0x008 8 | GFX_INV = 0x040 9 | GFX_HIDE = 0x080 10 | GFX_FG = 0x100 11 | GFX_BG = 0x200 12 | 13 | # special for detecting line wrap when selecting text 14 | GFX_WRITTEN = 0x400 15 | 16 | class Screen: 17 | def __init__(self, rows, cols): 18 | self.reset(rows, cols) 19 | 20 | def reset(self, rows, cols): 21 | self.cols = cols 22 | self.rows = rows 23 | self.cells = [] 24 | self.gfx = [] 25 | self.empty_line = array.array("u", u" "*cols) 26 | self.empty_gfx = array.array("I", [0]*cols) 27 | 28 | for i in range(0, rows): 29 | self.cells.append(array.array("u", self.empty_line)) 30 | self.gfx.append(array.array("I", self.empty_gfx)) 31 | 32 | def scroll_up(self, scroll_top, scroll_bottom, alt, current_gfx): 33 | top_screen = self.cells.pop(scroll_top) 34 | top_gfx = self.gfx.pop(scroll_top) 35 | if scroll_top == 0 and scroll_bottom == self.rows -1 and alt: 36 | top_screen = array.array("u", self.empty_line) 37 | top_gfx = array.array("I", self.empty_gfx) 38 | else: 39 | top_screen[0:self.cols] = array.array("u", self.empty_line) 40 | top_gfx[0:self.cols] = array.array("I", self.empty_gfx) 41 | for i in range(0, self.cols): 42 | top_gfx[i] = current_gfx 43 | self.cells.insert(scroll_bottom, top_screen) 44 | self.gfx.insert(scroll_bottom, top_gfx) 45 | 46 | def resize(self, rows, cols): 47 | if rows > self.rows: 48 | for row in range(self.rows, rows): 49 | self.cells.append(array.array("u", self.empty_line)) 50 | self.gfx.append(array.array("I", self.empty_gfx)) 51 | elif rows < self.rows: 52 | self.cells = self.cells[:rows] 53 | self.gfx = self.gfx[:rows] 54 | if cols > self.cols: 55 | for row in range(0, rows): 56 | for col in range(self.cols, cols): 57 | self.cells[row].append(u" ") 58 | self.gfx[row].append(0) 59 | self.empty_line = array.array("u", u" "*cols) 60 | self.empty_gfx = array.array("I", [0]*cols) 61 | elif cols < self.cols: 62 | for row in range(0, rows): 63 | self.cells[row] = self.cells[row][0:cols] 64 | self.gfx[row] = self.gfx[row][0:cols] 65 | self.empty_line = self.empty_line[0:cols] 66 | self.empty_gfx = self.empty_gfx[0:cols] 67 | self.rows = rows 68 | self.cols = cols 69 | 70 | def write_char(self, cursor, ch, rendition): 71 | self.cells[cursor.y][cursor.x] = ch 72 | self.gfx[cursor.y][cursor.x] = rendition | GFX_WRITTEN 73 | 74 | def erase_rectangle(self, top_row, left_col, bot_row, right_col, rendition=0): # XXX: need to pass in active rendition 75 | for y in range(top_row, bot_row): 76 | if y < 0 or y >= self.rows: 77 | continue 78 | for x in range(left_col, right_col): 79 | if x < 0 or x >= self.cols: 80 | continue 81 | self.cells[y][x] = u" " 82 | self.gfx[y][x] = rendition 83 | --------------------------------------------------------------------------------