[BACK]Return to tty-keys.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Diff for /src/usr.bin/tmux/tty-keys.c between version 1.15 and 1.16

version 1.15, 2009/11/05 10:44:36 version 1.16, 2009/11/05 19:29:41
Line 26 
Line 26 
 #include "tmux.h"  #include "tmux.h"
   
 /*  /*
  * Handle keys input from the outside terminal.   * Handle keys input from the outside terminal. tty_keys[] is a base table of
    * supported keys which are looked up in terminfo(5) and translated into a
    * ternary tree (a binary tree of binary trees).
  */   */
   
 void    tty_keys_add(struct tty *, const char *, int);  void            tty_keys_add1(struct tty_key **, const char *, int);
 void    tty_keys_callback(int, short, void *);  void            tty_keys_add(struct tty *, const char *, int);
 int     tty_keys_mouse(char *, size_t, size_t *, struct mouse_event *);  void            tty_keys_free1(struct tty_key *);
   struct tty_key *tty_keys_find1(
                       struct tty_key *, const char *, size_t, size_t *);
   struct tty_key *tty_keys_find(struct tty *, const char *, size_t, size_t *);
   void            tty_keys_callback(int, short, void *);
   int             tty_keys_mouse(char *, size_t, size_t *, struct mouse_event *);
   
 struct tty_key_ent {  struct tty_key_ent {
         enum tty_code_code      code;          enum tty_code_code      code;
Line 43 
Line 50 
 #define TTYKEY_RAW 0x2  #define TTYKEY_RAW 0x2
 };  };
   
   /*
    * Default key tables. Those flagged with TTYKEY_RAW are inserted directly,
    * otherwise they are looked up in terminfo(5). Any keys marked TTYKEY_CTRL
    * have their last byte twiddled and are inserted as a Ctrl key as well.
    */
 struct tty_key_ent tty_keys[] = {  struct tty_key_ent tty_keys[] = {
         /* Function keys. */          /* Function keys. */
         { TTYC_KF1,     NULL,           KEYC_F1,                TTYKEY_CTRL },          { TTYC_KF1,     NULL,           KEYC_F1,                TTYKEY_CTRL },
Line 186 
Line 198 
         { TTYC_KUP7,    NULL,           KEYC_UP|KEYC_ESCAPE|KEYC_CTRL, 0 },          { TTYC_KUP7,    NULL,           KEYC_UP|KEYC_ESCAPE|KEYC_CTRL, 0 },
 };  };
   
 RB_GENERATE(tty_keys, tty_key, entry, tty_keys_cmp);  void
   tty_keys_add(struct tty *tty, const char *s, int key)
 struct tty_key *tty_keys_find(struct tty *, char *, size_t, size_t *);  
   
 int  
 tty_keys_cmp(struct tty_key *k1, struct tty_key *k2)  
 {  {
         return (strcmp(k1->string, k2->string));          size_t  size;
   
           if (tty_keys_find(tty, s, strlen(s), &size) == NULL) {
                   log_debug("new key 0x%x: %s", key, s);
                   tty_keys_add1(&tty->key_tree, s, key);
           }
 }  }
   
   /* Add next node to the tree. */
 void  void
 tty_keys_add(struct tty *tty, const char *s, int key)  tty_keys_add1(struct tty_key **tkp, const char *s, int key)
 {  {
         struct tty_key  *tk, *tl;          struct tty_key  *tk;
   
         tk = xmalloc(sizeof *tk);          /* Allocate a tree entry if there isn't one already. */
         tk->string = xstrdup(s);          tk = *tkp;
         tk->key = key;          if (tk == NULL) {
                   tk = *tkp = xcalloc(1, sizeof *tk);
                   tk->ch = *s;
                   tk->key = KEYC_NONE;
           }
   
         if ((tl = RB_INSERT(tty_keys, &tty->ktree, tk)) != NULL) {          /* Find the next entry. */
                 xfree(tk->string);          if (*s == tk->ch) {
                 xfree(tk);                  /* Move forward in string. */
                 log_debug("key exists: %s (old %x, new %x)", s, tl->key, key);                  s++;
                 return;  
                   /* If this is the end of the string, no more is necessary. */
                   if (*s == '\0') {
                           tk->key = key;
                           return;
                   }
   
                   /* Use the child tree for the next character. */
                   tkp = &tk->next;
           } else {
                   if (*s < tk->ch)
                           tkp = &tk->left;
                   else if (*s > tk->ch)
                           tkp = &tk->right;
         }          }
   
         if (strlen(tk->string) > tty->ksize)          /* And recurse to add it. */
                 tty->ksize = strlen(tk->string);          tty_keys_add1(tkp, s, key);
         log_debug("new key %x: size now %zu (%s)", key, tty->ksize, tk->string);  
 }  }
   
   /* Initialise a key tree from the table. */
 void  void
 tty_keys_init(struct tty *tty)  tty_keys_init(struct tty *tty)
 {  {
Line 225 
Line 256 
         const char              *s;          const char              *s;
         char                     tmp[64];          char                     tmp[64];
   
         RB_INIT(&tty->ktree);          tty->key_tree = NULL;
   
         tty->ksize = 0;  
         for (i = 0; i < nitems(tty_keys); i++) {          for (i = 0; i < nitems(tty_keys); i++) {
                 tke = &tty_keys[i];                  tke = &tty_keys[i];
   
Line 237 
Line 266 
                         if (!tty_term_has(tty->term, tke->code))                          if (!tty_term_has(tty->term, tke->code))
                                 continue;                                  continue;
                         s = tty_term_string(tty->term, tke->code);                          s = tty_term_string(tty->term, tke->code);
                         if (s[0] != '\033' || s[1] == '\0')  
                                 continue;  
                 }                  }
                   if (s[0] != '\033' || s[1] == '\0')
                           continue;
   
                 tty_keys_add(tty, s + 1, tke->key);                  tty_keys_add(tty, s + 1, tke->key);
                 if (tke->flags & TTYKEY_CTRL) {                  if (!(tke->flags & TTYKEY_CTRL)) {
                         if (strlcpy(tmp, s, sizeof tmp) >= sizeof tmp)                          if (strlcpy(tmp, s, sizeof tmp) >= sizeof tmp)
                                 continue;                                  continue;
                         tmp[strlen(tmp) - 1] ^= 0x20;                          tmp[strlen(tmp) - 1] ^= 0x20;
Line 251 
Line 280 
         }          }
 }  }
   
   /* Free the entire key tree. */
 void  void
 tty_keys_free(struct tty *tty)  tty_keys_free(struct tty *tty)
 {  {
         struct tty_key  *tk;          tty_keys_free1(tty->key_tree);
   }
   
         while (!RB_EMPTY(&tty->ktree)) {  /* Free a single key. */
                 tk = RB_ROOT(&tty->ktree);  void
                 RB_REMOVE(tty_keys, &tty->ktree, tk);  tty_keys_free1(struct tty_key *tk)
                 xfree(tk->string);  {
                 xfree(tk);          if (tk->next != NULL)
         }                  tty_keys_free1(tk->next);
           if (tk->left != NULL)
                   tty_keys_free1(tk->left);
           if (tk->right != NULL)
                   tty_keys_free1(tk->right);
           xfree(tk);
   
 }  }
   
   /* Lookup a key in the tree. */
 struct tty_key *  struct tty_key *
 tty_keys_find(struct tty *tty, char *buf, size_t len, size_t *size)  tty_keys_find(struct tty *tty, const char *buf, size_t len, size_t *size)
 {  {
         struct tty_key  *tk, tl;          *size = 0;
         char            *s;          return (tty_keys_find1(tty->key_tree, buf, len, size));
   }
   
         if (len == 0)  /* Find the next node. */
   struct tty_key *
   tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size)
   {
           /* If the node is NULL, this is the end of the tree. No match. */
           if (tk == NULL)
                 return (NULL);                  return (NULL);
   
         s = xmalloc(tty->ksize + 1);          /* Pick the next in the sequence. */
         for (*size = tty->ksize; (*size) > 0; (*size)--) {          if (tk->ch == *buf) {
                 if ((*size) > len)                  /* Move forward in the string. */
                         continue;                  buf++; len--;
                 memcpy(s, buf, *size);                  (*size)++;
                 s[*size] = '\0';  
   
                 log_debug2("looking for key: %s", s);                  /* At the end of the string, return the current node. */
                   if (len == 0)
                 tl.string = s;  
                 tk = RB_FIND(tty_keys, &tty->ktree, &tl);  
                 if (tk != NULL) {  
                         log_debug2("got key: 0x%x", tk->key);  
                         xfree(s);  
                         return (tk);                          return (tk);
                 }  
                   /* Move into the next tree for the following character. */
                   tk = tk->next;
           } else {
                   if (*buf < tk->ch)
                           tk = tk->left;
                   else if (*buf > tk->ch)
                           tk = tk->right;
         }          }
         xfree(s);  
   
         return (NULL);          /* Move to the next in the tree. */
           return (tty_keys_find1(tk, buf, len, size));
 }  }
   
   /*
    * Process at least one key in the buffer and invoke tty->key_callback. Return
    * 1 if there are no further keys, or 0 if there is more in the buffer.
    */
 int  int
 tty_keys_next(struct tty *tty)  tty_keys_next(struct tty *tty)
 {  {
         struct tty_key          *tk;          struct tty_key          *tk;
         struct timeval           tv;          struct timeval           tv;
         struct mouse_event       mouse;          struct mouse_event       mouse;
         char                    *buf;          char                    *buf, *ptr;
         size_t                   len, size;          size_t                   len, size;
         cc_t                     bspace;          cc_t                     bspace;
         int                      key;          int                      key;
         u_char                   ch;  
   
         buf = EVBUFFER_DATA(tty->event->input);          buf = EVBUFFER_DATA(tty->event->input);
         len = EVBUFFER_LENGTH(tty->event->input);          len = EVBUFFER_LENGTH(tty->event->input);
Line 315 
Line 363 
   
         /* If a normal key, return it. */          /* If a normal key, return it. */
         if (*buf != '\033') {          if (*buf != '\033') {
                 bufferevent_read(tty->event, &ch, 1);                  key = *buf;
                 key = ch;                  evbuffer_drain(tty->event->input, 1);
   
                 /*                  /*
                  * Check for backspace key using termios VERASE - the terminfo                   * Check for backspace key using termios VERASE - the terminfo
Line 326 
Line 374 
                 bspace = tty->tio.c_cc[VERASE];                  bspace = tty->tio.c_cc[VERASE];
                 if (bspace != _POSIX_VDISABLE && key == bspace)                  if (bspace != _POSIX_VDISABLE && key == bspace)
                         key = KEYC_BSPACE;                          key = KEYC_BSPACE;
                 goto found;                  goto handle_key;
         }          }
   
         /* Look for matching key string and return if found. */          /* Look for matching key string and return if found. */
         tk = tty_keys_find(tty, buf + 1, len - 1, &size);          tk = tty_keys_find(tty, buf + 1, len - 1, &size);
         if (tk != NULL) {          if (tk != NULL) {
                 evbuffer_drain(tty->event->input, size + 1);  
                 key = tk->key;                  key = tk->key;
                 goto found;                  goto found_key;
         }          }
   
         /* Not found. Is this a mouse key press? */          /* Not found. Is this a mouse key press? */
         key = tty_keys_mouse(buf, len, &size, &mouse);          key = tty_keys_mouse(buf, len, &size, &mouse);
         if (key != KEYC_NONE) {          if (key != KEYC_NONE) {
                 evbuffer_drain(tty->event->input, size);                  evbuffer_drain(tty->event->input, size);
                 goto found;                  goto handle_key;
         }          }
   
         /* Not found. Try to parse a key with an xterm-style modifier. */          /* Not found. Try to parse a key with an xterm-style modifier. */
         key = xterm_keys_find(buf, len, &size);          key = xterm_keys_find(buf, len, &size);
         if (key != KEYC_NONE) {          if (key != KEYC_NONE) {
                 evbuffer_drain(tty->event->input, size);                  evbuffer_drain(tty->event->input, size);
                 goto found;                  goto handle_key;
         }          }
   
         /* Skip the escape. */          /* Skip the escape. */
Line 357 
Line 404 
   
         /* Is there a normal key following? */          /* Is there a normal key following? */
         if (len != 0 && *buf != '\033') {          if (len != 0 && *buf != '\033') {
                 evbuffer_drain(tty->event->input, 1);                  key = *buf | KEYC_ESCAPE;
                 bufferevent_read(tty->event, &ch, 1);                  evbuffer_drain(tty->event->input, 2);
                 key = ch | KEYC_ESCAPE;                  goto handle_key;
                 goto found;  
         }          }
   
         /* Or a key string? */          /* Or a key string? */
         if (len > 1) {          if (len > 1) {
                 tk = tty_keys_find(tty, buf + 1, len - 1, &size);                  tk = tty_keys_find(tty, buf + 1, len - 1, &size);
                 if (tk != NULL) {                  if (tk != NULL) {
                         evbuffer_drain(tty->event->input, size + 2);  
                         key = tk->key | KEYC_ESCAPE;                          key = tk->key | KEYC_ESCAPE;
                         goto found;                          size++; /* include escape */
                           goto found_key;
                 }                  }
         }          }
   
           /* Escape and then nothing useful - fall through. */
   
   partial_key:
         /*          /*
          * Escape but no key string. If have, already seen an escape, then the           * Escape but no key string. If have already seen an escape, then the
          * timer must have expired, so give up waiting and send the escape.           * timer must have expired, so give up waiting and send the escape.
          */           */
         if (tty->flags & TTY_ESCAPE) {          if (tty->flags & TTY_ESCAPE) {
                 evbuffer_drain(tty->event->input, 1);                  evbuffer_drain(tty->event->input, 1);
                 key = '\033';                  key = '\033';
                 goto found;                  goto handle_key;
         }          }
   
           /* Fall through to start the timer. */
   
   start_timer:
         /* Start the timer and wait for expiry or more data. */          /* Start the timer and wait for expiry or more data. */
         tv.tv_sec = 0;          tv.tv_sec = 0;
         tv.tv_usec = ESCAPE_PERIOD * 1000L;          tv.tv_usec = ESCAPE_PERIOD * 1000L;
Line 394 
Line 446 
         tty->flags |= TTY_ESCAPE;          tty->flags |= TTY_ESCAPE;
         return (0);          return (0);
   
 found:  found_key:
         evtimer_del(&tty->key_timer);          if (tk->next != NULL) {
                   /* Partial key. Start the timer if not already expired. */
                   if (!(tty->flags & TTY_ESCAPE))
                           goto start_timer;
   
                   /* Otherwise, if no key, send the escape alone. */
                   if (tk->key == KEYC_NONE)
                           goto partial_key;
   
                   /* Or fall through to send the partial key found. */
           }
           evbuffer_drain(tty->event->input, size + 1);
   
           goto handle_key;
   
   handle_key:
           evtimer_del(&tty->key_timer);
   
         tty->key_callback(key, &mouse, tty->key_data);          tty->key_callback(key, &mouse, tty->key_data);
   
         tty->flags &= ~TTY_ESCAPE;          tty->flags &= ~TTY_ESCAPE;
         return (1);          return (1);
 }  }
   
   /* Key timer callback. */
 void  void
 tty_keys_callback(unused int fd, unused short events, void *data)  tty_keys_callback(unused int fd, unused short events, void *data)
 {  {
         struct tty      *tty = data;          struct tty      *tty = data;
   
         if (tty->flags & TTY_ESCAPE)          if (!(tty->flags & TTY_ESCAPE))
                 tty_keys_next(tty);                  return;
   
           while (tty_keys_next(tty))
                   ;
 }  }
   
   /* Handle mouse key input. */
 int  int
 tty_keys_mouse(char *buf, size_t len, size_t *size, struct mouse_event *m)  tty_keys_mouse(char *buf, size_t len, size_t *size, struct mouse_event *m)
 {  {
Line 418 
Line 493 
          * buttons, X and Y, all based at 32 with 1,1 top-left.           * buttons, X and Y, all based at 32 with 1,1 top-left.
          */           */
   
         log_debug("mouse input is: %.*s", (int) len, buf);  
         if (len != 6 || memcmp(buf, "\033[M", 3) != 0)          if (len != 6 || memcmp(buf, "\033[M", 3) != 0)
                 return (KEYC_NONE);                  return (KEYC_NONE);
         *size = 6;          *size = 6;
   
           log_debug("mouse input is: %.*s", (int) len, buf);
   
         m->b = buf[3];          m->b = buf[3];
         m->x = buf[4];          m->x = buf[4];

Legend:
Removed from v.1.15  
changed lines
  Added in v.1.16