aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/showkey.c
blob: de1f80499446726238a11ea504a183f8cf8e7148 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* showkey.c - Shows the keys pressed.
 *
 * Copyright 2014 David Seikel <won_fang@yahoo.com.au>
 *
 * Not actually a standard, seems to be three different versions.
 * The original kbd - http://kbd-project.org/
 * The kbd fork console-tools - http://lct.sourceforge.net/
 * A utility invented by Eric S. Raymond - http://catb.org/esr/showkey/

USE_SHOWKEY(NEWTOY(showkey, "", TOYFLAG_USR|TOYFLAG_BIN))

config SHOWKEY
  bool "showkey"
  default n
  help
    usage: showkey

    Shows the keys pressed.
*/

#include "toys.h"
#include "lib/handlekeys.h"

typedef void (*eventHandler) (void);

struct keyCommand
{
  char *key;
  eventHandler handler;
};

GLOBALS(
  unsigned h, w;
  int x, y;
)

#define TT this.showkey


static void quit()
{
  printf("Quitting.\r\n");
  handle_keys_quit();
}

// The key to command mappings.
static struct keyCommand simpleKeys[] =
{
  {"^C",	quit}
};

// Callback for incoming sequences from the terminal.
static int handleEvent(long extra, struct keyevent *event)
{
  int i;

  switch (event->type)
  {
    case HK_RAW :
    {
      printf("RAW ");
      for (i = 0; event->sequence[i]; i++)
      {
        printf("(%x) ", (int) event->sequence[i]);
        if (32 > event->sequence[i])
          printf("^%c, ", (int) event->sequence[i] + 'A' - 1);
        else
          printf("%c, ", (int) event->sequence[i]);
      }
      printf("-> ");
      break;
    }

    case HK_KEYS :
    {
      int l = strlen(event->sequence);

      if (event->isTranslated)
        printf("TRANSLATED - ");
      else
        printf("KEY - ");
      printf("%s\r\n", event->sequence);

      // Search for a key sequence bound to a command.
      for (i = 0; i < ARRAY_LEN(simpleKeys); i++)
      {
        if (strncmp(simpleKeys[i].key, event->sequence, l) == 0)
        {
          // If it's a partial match, keep accumulating them.
          if (strlen(simpleKeys[i].key) != l)
            return 0;
          else
            if (simpleKeys[i].handler)  simpleKeys[i].handler();
        }
      }
      break;
    }

    case HK_CSI :
    {
      // Is it a cursor location report?
      if (strcmp("R", event->sequence) == 0)
      {
        printf("CSI cursor position - line %d, column %d\r\n", event->params[0], event->params[1]);
        return 1;
      }

      printf("CSI command %s - ", event->sequence);
      for (i = 0; i < event->count; i++)
        printf("%d ", event->params[i]);
      printf("\r\n");
      break;
    }

    default :  break;
  }

  return 1;
}

void showkey_main(void)
{
  struct termios termIo, oldTermIo;

  // Grab the old terminal settings and save it.
  tcgetattr(0, &oldTermIo);
  tcflush(0, TCIFLUSH);
  termIo = oldTermIo;

  // Mould the terminal to our will.
  // In this example we are turning off all the terminal smarts, but real code
  // might not want that.
  termIo.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL
                     | IUCLC | IXON | IXOFF | IXANY);
  termIo.c_oflag &= ~OPOST;
  termIo.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | TOSTOP | ICANON | ISIG
                     | IEXTEN);
  termIo.c_cflag &= ~(CSIZE | PARENB);
  termIo.c_cflag |= CS8;
  termIo.c_cc[VTIME]=0;  // deciseconds.
  termIo.c_cc[VMIN]=1;
  tcsetattr(0, TCSANOW, &termIo);

  handle_keys(0, handleEvent);

  tcsetattr(0, TCSANOW, &oldTermIo);
  puts("");
  fflush(stdout);
}