The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Terminal::Control - Perl extension with methods for the control of the terminal window

SYNOPSIS

The usage of

  use Terminal::Control;

or the usage of

  use Terminal::Control qw(:DEFAULT);

allows the import of the standard methods.

  # Clear or reset the terminal window.

  clear_screen();
  reset_screen();

  # Get the terminal window size using Perl header 'sys/ioctl.ph'.

  ($rows, $cols, $xpix, $ypix) = winsize();
  ($rows, $cols) = chars();
  ($xpix, $ypix) = pixels();

  # Get and set the cursor position on the terminal window.

  ($row, $col) = get_cursor_position();
  set_cursor_position($row, $col);

  # Realise cursor movement on the terminal window.

  cursor_up();
  cursor_down(); 
  cursor_forward(); 
  cursor_backward(); 

  # Show or hide the cursor on the terminal window.
  
  cursor_on();
  cursor_off();   

  # Turn the terminal character echo on or off.  

  echo_on();
  echo_off();

  # Get the terminal in use.

  which_terminal();   

qw(:DEFAULT) imports all methods which are declared in @EXPORT in the module.

The usage of

  use Terminal::Control qw(
     :DEFAULT TermColor TermType TermName TermPath WinSize
     window_size_chars window_size_pixels screen_size_chars screen_size_pixels
  );

or the usage of

  use Terminal::Control qw(
     TermColor TermType TermName TermPath WinSize
     window_size_chars window_size_pixels screen_size_chars screen_size_pixels
  );

allows the import of the optional methods which are declared in @EXPORT_OK in the module and the import of standard methods. Without entry :DEFAULT only optional methods are imported.

  # Get the terminal window size using Xterm control sequences. 

  ($rows, $cols) = window_size_chars([$timeout]);  
  ($xpix, $ypix) = windows_size_pixels([$timeout]);
  ($rows, $cols) = screen_size_chars([$timeout]); 
  ($xpix, $ypix) = screen_size_pixels([$timeout]);

  # Get the terminal window size using C header 'sys/ioctl.h'.

  ($rows, $cols, $xpix, $ypix) = WinSize();

  # Get informations about the terminal.

  TermColor();
  TermType();  
  TermName();  
  TermPath();

Variables in square brackets in the method call are optional. They are in the related method predefined.

In general every method is still accessible from outside the module using the syntax Terminal::Control::method_name.

DESCRIPTION

Preface

There are two main areas of application for the methods presented. They are useful in the terminal or in the console. The terminal is a terminal emulator installed on current operating systems. The console is the system console of the operating system itself. It provides basic functions that may be of general interest.

Methods summary

The module contains a collection of methods to control a terminal window. The basic methods are used to delete or reset a terminal window and to query the current window size. Other methods showed or suppressed the input echo. Showing or hiding the cursor is achieved by other methods.

List of methods

The following methods have been implemented so far within the module. The methods below are sorted according to their logical relationship.

Standard methods

  • clear_screen()

  • reset_screen()

  • winsize()

  • chars()

  • pixels()

  • get_cursor_position()

  • set_cursor_position($rows, $cols)

  • cursor_up()

  • cursor_down()

  • cursor_forward()

  • cursor_backward()

  • cursor_on()

  • cursor_off()

  • echo_on()

  • echo_off()

  • which_terminal()

Optional methods

  • WinSize()

  • screen_size_chars($timeout)

  • screen_size_pixels($timeout)

  • window_size_chars($timeout)

  • windows_size_pixels($timeout)

  • TermColor()

  • TermType()

  • TermName()

  • TermPath()

METHODS

clear_screen()

Clear the terminal window. The method is using Perls syswrite for printing ANSI escape sequences to STDOUT. The standard terminal window is STDOUT for the output of Perl. This command has the same effect like calling the Perl command system("clear").

reset_screen()

Reset the terminal window. The method is using Perls syswrite for printing ANSI escape sequences to STDOUT. The standard terminal window is STDOUT for the output of Perl. This command has the same effect like calling the Perl command system("reset").

winsize()

Get the window size. The method is using the Perl-header for the system call ioctl and the call or command TIOCGWINSZ. The call returns the winsize in rows and cols and xpix and ypix.

chars()

Get the window size in chars. The method extract chars (rows and cols) from the former winsize.

pixels()

Get the window size in pixels. The method pixels extract pixels (xpix and ypix) from the former winsize.

window_size_chars([$timeout]);

Get the window size in chars. The methods gets the window size in chars using Xterm control sequences.

windows_size_pixels([$timeout]);

Get the window size in pixels. The methods gets the window size in pixels using Xterm control sequences.

screen_size_chars([$timeout]);

Get the screen size in chars. The methods gets the screen size in chars using Xterm control sequences.

screen_size_pixels([$timeout]);

Get the screen size in pixels. The methods gets the screen size in pixels using Xterm control sequences.

WinSize()

Get the window size in chars and pixels. The method is using in The Inline C code the C-header for the system call ioctl and the call or command TIOCGWINSZ. The call returns the winsize in rows, cols, xpix and ypix.

get_cursor_position()

Get the cursor position. The method gets the current cursor position in the terminal window.

set_cursor_position($row, $col)

Set the cursor position. The method gets the current cursor position in the terminal window.

cursor_on()

Turn the cursor on. The cursor is enabled by using ANSI escape sequences in the method.

cursor_off()

Turn the cursor off. The cursor is disabled by using ANSI escape sequences in the method.

echo_on()

Turn the echo on. The method uses for the moment the Shell command stty for turning the echo of (user) input on.

echo_off()

Turn the echo off. The method uses for the moment the Shell command stty for turning the echo of (user) input off.

cursor_up()

Moves the cursor 1 char up.

cursor_down()

Moves the Cursor 1 char down.

cursor_forward()

Moves the cursor 1 char forward.

cursor_backward()

Move the cursor 1 char backward.

TermColor()

Get the color capabilities of the terminal, e.g 24bit, truecolor.

TermType()

Get the terminal capabilities in general, e.g. xterm, xterm-color or xterm-256color.

TermName()

Get name of the terminal like '/dev/tty'.

TermPath()

Get the path to the terminal like '/dev/pts/1'.

which_terminal()

Get the name of the terminal emulator, which is in use by the user. First the method tries to fetch the login shell. Next the path to the terminal is determined. Based on this informations the related process to login shell and terminal path is identified. Evaluation of the PPID results in the parents process ID. The command related to this PID is the name of the terminal in use.

Variables in square brackets in the method call are optional. They are in the related method predefined.

ERROR CODES

The error codes of methods which are related to getting the window or sreen size are as follows:

  -1  ->  Unspecific common error
  -2  ->  Data from response not valid
  -3  ->  Execution block timed out

EXAMPLES

Terminal window clear and reset

  # Clear the terminal window using ANSI escape sequences.
  clear_screen();

  # Reset the terminal window using ANSI escape sequences.
  reset_screen();

Standard terminal window size

  # Declare the variables.
  my ($rows, $cols, $xpix, $ypix) = undef;

  # Get the window size calling ioctl and output the result on the screen.
  ($rows, $cols, $xpix, $ypix) = winsize();
  printf ("%s\n%s\n%s\n%s\n", $rows, $cols, $xpix, $ypix);

  # Get the chars from the window size and output the result on the screen.
  ($rows, $cols) = chars();
  printf ("%s\n%s\n", $rows, $cols);

  # Get the pixels from the window size and output the result on the screen.
  ($xpix, $ypix) = pixels();
  printf ("%s\n%s\n", $xpix, $ypix);

Optional terminal window size

  # Load the required module.
  use Terminal::Control qw(
     window_size_chars
     window_size_pixels
     screen_size_chars
     screen_size_pixels
     WinSize
  );

  # Set the timeout for reading from STDIN in microseconds.
  my $timeout = 1000000;

  # Get the window and the screen size using Xterm control sequences.
  # $timeout is optional. If not set 1000000 microseconds (1 second) are used.
  ($rows, $cols) = window_size_chars($timeout);
  ($xpix, $ypix) = windows_size_pixels($timeout);
  ($rows, $cols) = screen_size_chars($timeout);
  ($xpix, $ypix) = screen_size_pixels($timeout);

  # Get the window size using Inline C code.
  ($rows, $cols, $xpix, $ypix) = Terminal::Control::WinSize();
  printf ("%s\n%s\n%s\n%s\n", $rows, $cols, $xpix, $ypix);

Getter and setter for the cursor position

  # Declare the variables.
  my ($row, $col) = undef;

  # Get the cursor position in chars (not in pixels) using ANSI escape sequences.
  ($row, $col) = get_cursor_position();
  printf ("%s\n%s\n", $row, $col);

  # Set the cursor position in chars (not in pixels) using ANSI escape sequences.
  $row = 20; 
  $col = 80; 
  # $row and $col are required and must be set by the user.
  set_cursor_position($row, $col);

Cursor on / off

  # Enable visibility of the cursor using ANSI escape sequences.
  cursor_on();

  # Disable visibility of the cursor using ANSI escape sequences.
  cursor_off();

Echo on / off

  # Enable echoing of commands using stty. 
  echo_on();

  # Disable echoing of commands using stty. 
  echo_off();

Cursor movement on the terminal window

The script works as follows. The terminal window is reseted. Then the position of the cursor is set to (20, 40) on the terminal window. Now the user can use the the arrow keys on the keyboard to move the cursor on the terminal window. Pressing 'q' quits the loop and set the cursor position to (1, 1) which is be the home position.

  # Load the required module.
  use Terminal::Control;

  # Initialise variable $chr.
  my $chr = '';

  # Reset the terminal window.
  reset();

  # Set the initial cursor position.
  set_cursor_position(20, 40); 

  # Set some terminal attributes.
  system("stty -echo -icanon -isig");

  # Run loop until 'q' was pressed.
  while ($chr ne "q") {
      $chr = getc(STDIN);
      if (ord($chr) == 65) {
          cursor_up();
      } elsif (ord($chr) == 66) {
          cursor_down();
      } elsif (ord($chr) == 67) {
          cursor_forward();
      } elsif (ord($chr) == 68) {
          cursor_backward();
      };
  };

  # Reset some terminal attributes.
  system("stty echo icanon isig");

  # Reset the cursor to home.
  set_cursor_position(1,1); 

It is planned for the near future to exchange the Perl system command which calls stty by a C function. The basic knowledge is given, but this takes a bit time to do it the right way. Such a method has to be easy to use and flexible in turning on and off of the attributes the same time.

VARIABLES EXPLANATION

The x-direction is corresponding to window width and the y-direction is corresponding to window height.

  $row     => Row (y-position) of terminal window as char position
  $col     => Column (x-position) of terminal window as char position
  $rows    => Rows (height) of terminal window as chars
  $cols    => Columns (width) of terminal window as chars
  $ypix    => Rows (y-direction or height) of terminal window as pixels
  $xpix    => Coulumns (x-direction or width) of terminal window as pixels
  $timeout => Timeout for reading from STDIN in microseconds

The predefined value of $timeout is 1000000 microseconds (1 second). The value of the parameter $timeout has to be given in microseconds.

NOTES

Development

The idea for the necessity of the module arises from the fact that especially the call of the Perl command system system("reset") of the Shell command reset is noticeably slow.

By using so-called ANSI escape sequences instead of calling a Shell command a significant acceleration can be achieved. The logical consequence is the programming of a Perl command that replaces the call of the Perl command system to reset the terminal window.

A single method is the best way to realise this for the terminal reset and several other commands. There is no need to implement a class with a bunch of methods to achive this.

Prove of concept

Exemplary comparison of time of execution:

  system("reset")  =>  1.026892 Seconds = 1026,892 Milliseconds = 1026892 Microseconds
  
  reset_screen()   =>  0.000076 Seconds =    0,076 Milliseconds = 76 Microseconds

Using reset on the command line and the Perl command system("reset") have nearly the same result in time of execution. Detailed comparison is outstanding. This one example already shows a significant advantage of the new routine.

SYSTEM COMPATIBILITY

Three things must be fulfilled in order to use the full functionality of the module.

On operating systems that support ANSI escape sequences, individual methods will work out of the box. Some methods still use the Shell command stty. The Shell command stty must be available accordingly. Some methods are using the system call ioctl, which is somehow optional with respect to the functionality of the module. The restriction under Perl is explained further below.

The above requirements are fulfilled in principle by all Unix or Unix-like systems.

FUNCTIONALITY REQUIREMENT

The Perl header sys/ioctl.ph is required for the ioctl call of the function TIOCGWINSZ to get the window size. The equivalent C/C++ header is sys/ioctl.h. The Perl command h2ph converts .h C/C++ header files to .ph Perl header files.

In contrast to modules in general, the module installation process cannot be told to create a sys/ioctl.ph. This is necessary manually via the h2ph command.

To prevent tests within CPAN from failing due to a missing sys/ioctl.ph, a fallback solution based on the Shell command stty is implemented.

PORTABILITY

The module should work on Linux as well as Unix or Unix-like operating systems in general until something else was shown.

CONTROL SEQUENCES

ANSI escape sequences are widely known. Less well known are the so-called Xterm control sequences.

ANSI escape sequences

Escape sequences used by the module:

  CSI n ; m H   =>  Set Cursor Position  =>  Moves the cursor to row n and column m 
  CSI 6n        =>  Get Cursor Position  =>  Cursor position report (CPR) by
                                             sending ESC [ n ; m R, where
                                             n is the row and m is the column

  CSI n A       =>  Cursor Up 
  CSI n B       =>  Cursor Down
  CSI n C       =>  Cursor Forward
  CSI n D       =>  Cursor Backward 

  Moves the cursor n (default is 1) chars in the given direction up, down, forward or backward.
  If the cursor is already at the one edge of the screen, this control sequence has no effect.

  CSI ? 25 h    =>  Shows the cursor
  CSI ? 25 l    =>  Hides the cursor 

  CSI ? 1049 h  =>  Enable the alternative screen buffer
  CSI ? 1049 l  =>  Disable the alternative screen buffer 

Xterm control sequences

The xterm program is a terminal emulator for the X Window System. The Xterm control sequences take their name from the terminal emulator of the same name. This means that the Xterm control sequences should primarily be able to run under xterm. However, they also work with other terminal emulators.

Escape sequences used by the module:

  CSI 1 4 t  =>  Report the window size in pixels
  CSI 1 5 t  =>  Report the screen size in pixels
  CSI 1 8 t  =>  Report the window size in chars
  CSI 1 9 t  =>  Report the screen size in chars

METHOD ALIASES

clear_screen and reset_screen can also be used with this aliases:

  reset_terminal  <=  reset_screen
  clear_terminal  <=  clear_screen
  reset           <=  reset_screen
  clear           <=  clear_screen

TERMINALS TESTED

As described above, terminal emulators or the system console are used to interact with the operating system.

Terminals tested so far with the module:

  • LXTerminal

  • mate-terminal

  • ROXTerm

  • xterm

LIMITATIONS

Xterm control sequences

The use of Xterm escape sequences is still considered experimental.

Reading the response from STDIN is blocking with respect to the request of escape sequences, if no data are responded. To overcome the problem of waiting endless for an user input a timeout is programmed.

If the timeout is set too short, the response to the request cannot be evaluated. If information on the size of the window is requested in quick succession, the data from STDIN will be read in incorrectly. This can be overcome by deleting STDIN. A method of deleting or resetting STDIN is not known yet.

If the standard value is not applicable, reduce the timeout step by step. If the timeout is to short the method is not able to catch the input from STDIN.

OPEN ISSUES

It is not yet clear how an installation of the module for Unix or Unix-like operating systems only can best be realised.

A routine is needed that can reliably delete STDIN. Previous attempts to delete STDIN did not lead to satisfactory results.

KNOWN BUGS

Not known yet

ABSTRACT

The module is intended for Linux as well as Unix or Unix-like operating systems in general. These operating systems meet the requirements for using the module and its methods. The module contains, among others, two methods for clearing and resetting the terminal window. This is a standard task when scripts has to be executed in the terminal window. The related Shell commands are slow in comparison to the implemented methods in this module. This is achieved by using ANSI escape sequences. In addition Xterm control sequences can be used to query screen and window size. The terminal or window size is in general available via the system call ioctl.

SEE ALSO

ANSI escape sequences

Xterm control sequences

stty(1) - Linux manual page

termios(3) - Linux manual page

ioctl_tty(2) - Linux manual page

AUTHOR

Dr. Peter Netz, <ztenretep@cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2022 by Dr. Peter Netz

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.30.0 or, at your option, any later version of Perl 5 you may have available.