Subject: Re: "Application key pad mode" in cygwin console
From: Fabien PERRIOLLAT <[email-masked]>
To: [email-masked]
Date: Mon, 08 Jul 2002 12:02:21 +0200

Christopher Faylor,

I just completed a patch to cygwin1.dll to provide the application keyboard
modes.
The patches are in the files :
    fhandler_console.cc
    fhandler_termios.cc
    select.cc
    fhandler.h
    tty.h
    shared_info,h

These patches was done in the Cygwin version 10 03.11.0.0
And I have a short and simple test program to exercise the new facility.
I attache a file which is the output of diif processing for the modified
files.

Could you tel me to how I must send this patch, and what is the procedure.

Fabien PERRIOLLAT

Christopher Faylor wrote:

> On Fri, Apr 05, 2002 at 12:03:18AM +0200, Fabien Perriollat wrote:
> >I am porting a Unix package to Cygwin environment.
> >This package use the capability offered by xterm but also by linux
> >console to set the numerical key pad in "Application mode" (by sending
> >an escape sequence string).
> >This facility seem to be not available, and a quick look into the file
> >fhandler_console.cc and into winuser.h show me that "NUMPADxx" key
> >outside VK_NUMPAD5 is not handle. but only the "Numeric key pad mode"
> >is handle.
> >
> >Do you have any plan to provide the cygwin console with this facility
> >similar to xterm and or linux console,
>
> No plans, but you're welcome to submit a patch.
>
> >our could you provide me with any alternated way to have a similar
> >result.
>
> Have you tried 'rxvt'?
>
> If you don't have it installed currently, rerun setup.exe to install it.
>
> cgf

--
====================================================================
Fabien Perriollat      office 10 2-001 http://home.cern.ch/perrioll/
Beam Diagnostics       mailto:[email-masked]
Division PS, CERN      Phone (+41 22) 767 5044   (+41) 79 201 0561
CH-1211 Geneva 23      Fax   (+41 22) 767 9145
====================================================================

==============================================================================

Cygwin version 10 03.11.0.0
differences in /src/winsup/cygwin files :
    fhandler_console.cc
    fhandler_termios.cc
    select.cc
    fhandler.h
    tty.h
    shared_info.h
as produced by 'diff -bE -C 2 new_file ref_file
introduced to provide keypad mode control (DECPAM, DECPNM control sequences)
and cursor key mode (DECCKM  control sequences)

Fabien PERRIOLLAT, CERN Geneva, Switzerland
[email-masked]
June 2002
==============================================================================

*** fhandler_console_ref.cc	Wed Jun 12 16:07:04 2002
--- fhandler_console.cc	Wed Jun 19 14:47:29 2002
***************
*** 93,97 ****
  #define use_tty ISSTATE (myself, PID_USETTY)
  
! const char * get_nonascii_key (INPUT_RECORD&, char *);
  
  static tty_min NO_COPY *shared_console_info = NULL;
--- 93,97 ----
  #define use_tty ISSTATE (myself, PID_USETTY)
  
! const char * get_nonascii_key (INPUT_RECORD&, char *, BOOL, BOOL);
  
  static tty_min NO_COPY *shared_console_info = NULL;
***************
*** 204,207 ****
--- 204,209 ----
  
    int ch;
+   int vkc;
+ 
    set_input_state ();
  
***************
*** 227,230 ****
--- 229,233 ----
      {
        int bgres;
+       int remove_echo = FALSE;
        if ((bgres = bg_check (SIGTTIN)) <= bg_eof)
  	return bgres;
***************
*** 294,305 ****
  #define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
  
  	  if (wch == 0 ||
  	      /* arrow/function keys */
! 	      (input_rec.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
  	    {
! 	      toadd = get_nonascii_key (input_rec, tmp);
  	      if (!toadd)
  		continue;
  	      nread = strlen (toadd);
  	    }
  	  else
--- 297,311 ----
  #define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
  
+ 	  vkc = input_rec.Event.KeyEvent.wVirtualKeyCode;
  	  if (wch == 0 ||
  	      /* arrow/function keys */
! 	      (input_rec.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY) ||
!             ((vkc == VK_MULTIPLY) || (vkc == VK_SUBTRACT) || (vkc == VK_ADD) ) )
  	    {
! 	      toadd = get_nonascii_key (input_rec, tmp, tc->application_keypad_mode, tc->application_cursor_mode);
  	      if (!toadd)
  		continue;
  	      nread = strlen (toadd);
+ 	      remove_echo = (*toadd == '\033'); /* no echo of escape sequence */
  	    }
  	  else
***************
*** 436,440 ****
        if (toadd)
  	{
! 	  int res = line_edit (toadd, nread);
  	  if (res < 0)
  	    goto sig_exit;
--- 442,446 ----
        if (toadd)
  	{
! 	  int res = line_edit (toadd, nread, 0, remove_echo);
  	  if (res < 0)
  	    goto sig_exit;
***************
*** 659,662 ****
--- 665,671 ----
    fhc->raw_win32_keyboard_mode = raw_win32_keyboard_mode;
  
+   fhc->tc->application_keypad_mode = tc->application_keypad_mode;
+   fhc->tc->application_cursor_mode = tc->application_cursor_mode;
+ 
    return 0;
  }
***************
*** 1034,1038 ****
  /*18 19 1A 1B 1C 1D 1E 1F */ NOR, NOR, ERR, ESC, ERR, ERR, ERR, ERR,
  /*   !  "  #  $  %  &  '  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
! /*()  *  +  ,  -  .  /  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
  /*0  1  2  3  4  5  6  7  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
  /*8  9  :  ;  <  =  >  ?  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
--- 1043,1047 ----
  /*18 19 1A 1B 1C 1D 1E 1F */ NOR, NOR, ERR, ESC, ERR, ERR, ERR, ERR,
  /*   !  "  #  $  %  &  '  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
! /*(  )  *  +  ,  -  .  /  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
  /*0  1  2  3  4  5  6  7  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
  /*8  9  :  ;  <  =  >  ?  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
***************
*** 1176,1179 ****
--- 1185,1195 ----
        switch (args_[0])
  	{
+ 	bool set_flg;
+ 
+ 	case 1:     /* Cursor Key mode */
+ 	  set_flg = (c == 'h');
+ 	  tc->application_cursor_mode = set_flg;
+ 	  break;
+ 
  	case 47:   /* Save/Restore screen */
  	  if (c == 'h') /* save */
***************
*** 1493,1496 ****
--- 1509,1513 ----
    debug_printf ("%x, %d", vsrc, len);
  
+ 
    while (src < end)
      {
***************
*** 1544,1548 ****
--- 1561,1577 ----
  	    }
  	  else if (*src == 'R')
+           {
  	      state_ = normal;
+           }
+         else if (*src == '=')
+ 	    {
+ 	    tc->application_keypad_mode = TRUE;
+ 	    state_ = normal;
+           }
+         else if (*src == '>')
+           {
+ 	    tc->application_keypad_mode = FALSE;
+ 	    state_ = normal;
+           }
  	  else
  	    {
***************
*** 1633,1640 ****
  }
  
! static struct {
    int vk;
!   const char *val[4];
! } keytable[] NO_COPY = {
  	       /* NORMAL */  /* SHIFT */    /* CTRL */       /* ALT */
    {VK_LEFT,	{"\033[D",	"\033[D",	"\033[D",	"\033\033[D"}},
--- 1662,1671 ----
  }
  
! typedef struct {
    int vk;
!   const char *val[4];   /* for NORMAL, SHIFT, CTRL and ALT modifier case */
! } KEY_TABLE;
! 
! static KEY_TABLE keytable[] NO_COPY = {
  	       /* NORMAL */  /* SHIFT */    /* CTRL */  /* ALT */
    {VK_LEFT,     {"\033[D",    "\033[D",      "\033[D",   "\033\033[D"}},
***************
*** 1662,1671 ****
    {VK_NUMPAD5,	{"\033[G",	NULL,		NULL,		NULL}},
    {VK_CLEAR,	{"\033[G",	NULL,		NULL,		NULL}},
!   {'6',		{NULL,		NULL,		"\036",		NULL}},
    {0,		{"",		NULL,		NULL,		NULL}}
  };
  
  const char *
! get_nonascii_key (INPUT_RECORD& input_rec, char *tmp)
  {
  #define NORMAL  0
--- 1693,1762 ----
    {VK_NUMPAD5,  {"\033[G",      NULL,          NULL,       NULL}},
    {VK_CLEAR,    {"\033[G",      NULL,          NULL,       NULL}},
!   {'6',         {  NULL,        NULL,        "\036",       NULL}},
    {0,           {"",            NULL,          NULL,       NULL}}
  };
  
+ /* WARNING :
+  * 1 - the order of these arrays are very much sensitive
+  *     VK_xxx must be in numerical order, and it is assumed that some
+  *     values are contigous.
+  * 2 - VK_APPS (0X5D) is also an enhanced key.
+  */
+ 
+ static KEY_TABLE numkeytable[] NO_COPY = {
+ 	      /* NORMAL     SHIFT     CTRL        ALT */
+   {VK_RETURN,   {"\033OM",  "\r",     NULL,       NULL}},
+ 
+   {VK_NUMPAD0,  {"\033Op",  "0",    "\033Op",   "\033Op"}},
+   {VK_NUMPAD1,  {"\033Oq",  "1",    "\033Oq",   "\033Oq"}},
+   {VK_NUMPAD2,  {"\033Or",  "2",    "\033Or",   "\033Or"}},
+   {VK_NUMPAD3,  {"\033Os",  "3",    "\033Os",   "\033Os"}},
+   {VK_NUMPAD4,  {"\033Ot",  "4",    "\033Ot",   "\033Ot"}},
+   {VK_NUMPAD5,  {"\033Ou",  "5",    "\033Ou",   "\033Ou"}},
+   {VK_NUMPAD6,  {"\033Ov",  "6",    "\033Ov",   "\033Ov"}},
+   {VK_NUMPAD7,  {"\033Ow",  "7",    "\033Ow",   "\033Ow"}},
+   {VK_NUMPAD8,  {"\033Ox",  "8",    "\033Ox",   "\033Ox"}},
+   {VK_NUMPAD9,  {"\033Oy",  "9",    "\033Oy",   "\033Oy"}},
+ 
+   {VK_MULTIPLY, {"\033Oj",  "*",      NULL,       NULL}},
+   {VK_ADD,      {"\033Ok",  "+",      NULL,       NULL}},
+   {VK_SEPARATOR,{"\033Ol",  "'",      NULL,       NULL}},
+   {VK_SUBTRACT, {"\033Om",  "-",      NULL,       NULL}},
+   {VK_DECIMAL,  {"\033On",  ".",      NULL,       NULL}},
+   {VK_DIVIDE,   {"\033Oo",  "/",      NULL,       NULL}},
+ 
+   {0,           {NULL,      NULL,     NULL,       NULL}}
+ };
+ 
+ static KEY_TABLE applcursortable [] NO_COPY = {
+ 	       /* NORMAL    SHIFT     CTRL        ALT */
+     {VK_LEFT,  {"\033OD", "\033OD", "\033OD",   "\033OD"}}, /* VK_LEFT  37 */
+     {VK_UP,    {"\033OA", "\033OA", "\033OA",   "\033OA"}}, /* VK_UP    38 */
+     {VK_RIGHT, {"\033OC", "\033OC", "\033OC",   "\033OC"}}, /* VK_RIGHT 39 */
+     {VK_DOWN,  {"\033OB", "\033OB", "\033OB",   "\033OB"}}, /* VK_DOWN  40 */
+     {0,        {  NULL,     NULL,     NULL,       }}
+   };
+ 
+ static struct {
+   int kc;
+   int mkc;
+ } numkeytranst[] NO_COPY = {
+   {VK_LEFT,      VK_NUMPAD4},
+   {VK_RIGHT,     VK_NUMPAD6},
+   {VK_UP,        VK_NUMPAD8},
+   {VK_DOWN,      VK_NUMPAD2},
+   {VK_PRIOR,     VK_NUMPAD9},
+   {VK_NEXT,      VK_NUMPAD3},
+   {VK_HOME,      VK_NUMPAD7},
+   {VK_END,       VK_NUMPAD1},
+   {VK_INSERT,    VK_NUMPAD0},
+   {VK_DELETE,    VK_DECIMAL},
+   {VK_CLEAR,     VK_NUMPAD5},
+   {0,            0}
+ };
+ 
+ 
  const char *
! get_nonascii_key (INPUT_RECORD& input_rec, char *tmp, BOOL keypad_mode, BOOL cursor_mode)
  {
  #define NORMAL  0
***************
*** 1673,1700 ****
  #define CONTROL	2
  #define ALT	3
    int modifier_index = NORMAL;
  
!   if (input_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
      modifier_index = SHIFT;
!   else if (input_rec.Event.KeyEvent.dwControlKeyState &
! 		(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
      modifier_index = CONTROL;
!   else if (input_rec.Event.KeyEvent.dwControlKeyState &
! 		(LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
      modifier_index = ALT;
  
!   for (int i = 0; keytable[i].vk; i++)
!     if (input_rec.Event.KeyEvent.wVirtualKeyCode == keytable[i].vk)
!       return keytable[i].val[modifier_index];
  
!   if (input_rec.Event.KeyEvent.uChar.AsciiChar)
!     {
!       tmp[0] = input_rec.Event.KeyEvent.uChar.AsciiChar;
!       tmp[1] = '\0';
        return tmp;
      }
    return NULL;
  }
  
  void
  fhandler_console::init (HANDLE f, DWORD a, mode_t bin)
--- 1764,1886 ----
  #define CONTROL	2
  #define ALT	3
+ 
+   int v_keycode, kc;
+   int kstate;
+   int i;
+   char ascii;
+ 
    int modifier_index = NORMAL;
+   BOOL enhanced = FALSE;
+   BOOL num_key = FALSE;		/* a key from numeric key pad */
+   BOOL ext_key = FALSE;       /* a key from extended key pad */
+   BOOL numlock = FALSE;
+   BOOL shift = FALSE;
+ 
+   kstate = input_rec.Event.KeyEvent.dwControlKeyState; 
+   v_keycode = input_rec.Event.KeyEvent.wVirtualKeyCode;
+   enhanced = input_rec.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY;
+   numlock = kstate & NUMLOCK_ON;
+   shift = kstate & SHIFT_PRESSED;	
+   tmp[0] = ascii = input_rec.Event.KeyEvent.uChar.AsciiChar;
+   tmp[1] = '\0';
  
!   if ( shift )
      modifier_index = SHIFT;
!   else if ( kstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) )
      modifier_index = CONTROL;
!   else if (kstate & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) )
      modifier_index = ALT;
  
!   if ( keypad_mode ) {
!     /* check for numeric or extended keypad */
!     if ( enhanced ) {
!       num_key = ((v_keycode == VK_RETURN) || (v_keycode == VK_DIVIDE));
!       ext_key = ! num_key;
!     } else {
!       switch (v_keycode) {
!         case VK_MULTIPLY :
!         case VK_SUBTRACT :
!         case VK_ADD :
! 	    num_key = TRUE;
! 	    break;
!         default :
!           if ( v_keycode < VK_NUMPAD0 ) {
!             for (i = 0; (kc = numkeytranst[i].kc) != 0; i++) {
!               if ( kc == v_keycode ) {
!                 v_keycode = numkeytranst[i].mkc;
! 	          num_key = TRUE;
!                 break;
! 	        }
!             }
!           } else num_key = (v_keycode <= VK_DIVIDE);           		
!       }
!     }
  
!     if ( num_key ) {
!       if ( !numlock && !shift ) {
!         /* get answer from translation table */ 
!         ascii = '\0';
!       } else if ( numlock && shift ) {
!         /* cancel the numlock effect */
!         ascii = '\0';
!         modifier_index = NORMAL;
!       }
!     }
! 
!     if ( ascii ) {
!       /* return the ascii code */
        return tmp;
      }
+ 
+     if ( num_key ) {
+       /* a numeric key pad */
+       if ( v_keycode == VK_RETURN ) {
+         return numkeytable[0].val[modifier_index];
+       } else if ( ((i = v_keycode - VK_NUMPAD0) >= 0) && (i <= (VK_DIVIDE - VK_NUMPAD0)) ) {
+         return numkeytable[i+1].val[modifier_index];
+       }
+     } 
+   }
+ 
+ 
+   if ( cursor_mode && ((v_keycode >= VK_LEFT) && (v_keycode <= VK_DOWN)) ) {
+     return applcursortable[v_keycode - VK_LEFT].val[modifier_index];
+   }
+ 
+   /* other key (function or extended key pad) */
+   for (i = 0; keytable[i].vk; i++) {
+     if (v_keycode == keytable[i].vk)
+       return keytable[i].val[modifier_index];
+   }
+ 
+   if ( !keypad_mode && ascii ) 
+     return tmp;
+ 
    return NULL;
  }
  
+ /* check_keyevent : return true if something will be returned
+  *   by a read to the console input (used by 'peek_console'
+  *   in select.cc file
+  *   Must be call only on KEY_EVENT, and when bKeyDown is true
+  */
+ bool
+ check_keyevent (fhandler_console *fh, INPUT_RECORD& input_rec)
+ {
+   int vkc;
+   char tmpbuf[17];
+   const char *toadd;
+ 
+   vkc = input_rec.Event.KeyEvent.wVirtualKeyCode;
+   if ( (input_rec.Event.KeyEvent.uChar.AsciiChar == '\0') ||
+        (input_rec.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY) ||
+        ((vkc == VK_MULTIPLY) || (vkc == VK_SUBTRACT) || (vkc == VK_ADD))
+      ) {
+ 	toadd = get_nonascii_key (input_rec, tmpbuf, fh->tc->application_keypad_mode, fh->tc->application_cursor_mode);
+ 	return (toadd != NULL);
+      }
+   return true;  /* a valid ascii char */
+ }
+ 
  void
  fhandler_console::init (HANDLE f, DWORD a, mode_t bin)

*** fhandler_termios_ref.cc	Thu Jun 13 17:54:40 2002
--- fhandler_termios.cc	Wed Jun 19 14:22:41 2002
***************
*** 61,64 ****
--- 61,66 ----
        tc->pgid = myself->pgid;
        TTYSETF (INITIALIZED);
+ 
+       tc->application_keypad_mode = tc->application_cursor_mode = FALSE;
      }
  }

*** select_ref.cc	Wed Jun 12 15:45:24 2002
--- select.cc	Wed Jun 12 15:31:04 2002
***************
*** 622,626 ****
  peek_console (select_record *me, bool)
  {
!   extern const char * get_nonascii_key (INPUT_RECORD& input_rec, char *);
    fhandler_console *fh = (fhandler_console *)me->fh;
  
--- 622,626 ----
  peek_console (select_record *me, bool)
  {
!   extern bool check_keyevent (fhandler_console *, INPUT_RECORD& input_rec);
    fhandler_console *fh = (fhandler_console *)me->fh;
  
***************
*** 643,647 ****
    DWORD events_read;
    HANDLE h;
-   char tmpbuf[17];
    set_handle_or_return_if_not_open (h, me);
  
--- 643,646 ----
***************
*** 662,667 ****
  	      return me->read_ready = true;
  	  }
! 	else if (irec.EventType == KEY_EVENT && irec.Event.KeyEvent.bKeyDown == true &&
! 		 (irec.Event.KeyEvent.uChar.AsciiChar || get_nonascii_key (irec, tmpbuf)))
  	  return me->read_ready = true;
  
--- 661,666 ----
  	      return me->read_ready = true;
  	  }
! 	else if (irec.EventType == KEY_EVENT && irec.Event.KeyEvent.bKeyDown
! 		 && (check_keyevent (fh, irec)))
  	  return me->read_ready = true;

*** fhandler_ref.h	Fri May 24 07:44:10 2002
--- fhandler.h	Thu Jun 20 14:34:06 2002
***************
*** 652,656 ****
    }
    HANDLE& get_output_handle () { return output_handle; }
!   int line_edit (const char *rptr, int nread, int always_accept = 0);
    void set_output_handle (HANDLE h) { output_handle = h; }
    void tcinit (tty_min *this_tc, int force = FALSE);
--- 652,656 ----
    }
    HANDLE& get_output_handle () { return output_handle; }
!   int line_edit (const char *rptr, int nread, int always_accept = 0, int remove_echo = 0);
    void set_output_handle (HANDLE h) { output_handle = h; }
    void tcinit (tty_min *this_tc, int force = FALSE);

*** tty_ref.h	Tue Mar  5 19:03:32 2002
--- tty.h	Wed Jun 19 10:04:48 2002
***************
*** 67,70 ****
--- 67,74 ----
    struct winsize winsize;
  
+   /* cursor and keypad mode (0 : normal (FALSE) or != 0 : application (TRUE)) */
+   int application_keypad_mode;
+   int application_cursor_mode;
+ 
    /* ioctl requests buffer */
    int cmd;

*** shared_info_ref.h	Thu Jun 20 15:08:59 2002
--- shared_info.h	Thu Jun 20 15:08:01 2002
***************
*** 140,144 ****
  #define SHARED_VERSION_MAGIC CYGWIN_VERSION_MAGIC (SHARED_MAGIC, SHARED_VERSION)
  
! #define SHARED_INFO_CB 47112
  
  #define CURR_SHARED_MAGIC 0x88e
--- 140,146 ----
  #define SHARED_VERSION_MAGIC CYGWIN_VERSION_MAGIC (SHARED_MAGIC, SHARED_VERSION)
  
! /* #define SHARED_INFO_CB 47112 */
! /* tty_min class was extented with 2 int for keypad and cursor mode. F.P. June 2002 */
! #define SHARED_INFO_CB 48136
  
  #define CURR_SHARED_MAGIC 0x88e

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/