Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I need to get access to modifier-key state for a console app I'm writing (a personalized editor).

Are there any packages/libs/whatever that provide this access?

I cobbled the following from somewhere, but it only works if you're root, and I don't really want to mess about at root-level.

#include <iostream>
#include <string>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <termios.h>
#include <fcntl.h>
#include <linux/input.h>
#include <unistd.h>
#include <errno.h>

int kbhit(void)
    struct termios oldt, newt;
    int ch;
    int oldf;

    tcgetattr(STDIN_FILENO, &oldt);

    newt = oldt;
    newt.c_lflag &= ~0000172 ; //~(ICANON | ECHO);

    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
    fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

    ch = getchar();

    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    fcntl(STDIN_FILENO, F_SETFL, oldf);

    return ch;

    SHIFT_L = 1,
    SHIFT_R = 2,
    CTRL_L = 4,
    CTRL_R = 8,
    ALT_L = 16,
    ALT_R = 32,

int chkmodifiers()
    int mods=0,keyb,mask;
    char key_map[KEY_MAX/8 + 1];    //  Create a byte array the size of the number of keys

    //event1 - got by inspecting /dev/input/... 
    FILE *kbd = fopen("/dev/input/event1", "r");
    if (kbd == NULL)
        printf("(chkmodifiers) ERROR: %s\n", strerror(errno)); //permission - got to be root!
        return 0;

    memset(key_map, 0, sizeof(key_map));
    ioctl(fileno(kbd), EVIOCGKEY(sizeof(key_map)), key_map);    //  Fill the keymap with the current keyboard state

    keyb = key_map[KEY_LEFTSHIFT/8];
    mask = 1 << (KEY_LEFTSHIFT % 8);
    if (keyb & mask) mods += SHIFT_L;

    keyb = key_map[KEY_RIGHTSHIFT/8];
    mask = 1 << (KEY_RIGHTSHIFT % 8);
    if (keyb & mask) mods += SHIFT_R;

    keyb = key_map[KEY_LEFTCTRL/8];
    mask = 1 << (KEY_LEFTCTRL % 8);
    if (keyb & mask) mods += CTRL_L;

    keyb = key_map[KEY_RIGHTCTRL/8];
    mask = 1 << (KEY_RIGHTCTRL % 8);
    if (keyb & mask) mods += CTRL_R;

    keyb = key_map[KEY_LEFTALT/8];
    mask = 1 << (KEY_LEFTALT % 8);
    if (keyb & mask) mods += ALT_L;

    keyb = key_map[KEY_RIGHTALT/8];
    mask = 1 << (KEY_RIGHTALT % 8);
    if (keyb & mask) mods += ALT_R;

    return mods;


int main()
    puts("Press a key!");

    char ch=0;
    int n=0,m;

    while (ch != 'q')
        n = kbhit();
        if (n != -1)
            m = chkmodifiers();
            ch =  (char)n;
            printf("You pressed '%c' [%d]\n", ch, n);
            if ((m & SHIFT_L) == SHIFT_L) printf(" .. and ls\n");
            if ((m & SHIFT_R) == SHIFT_R) printf(" .. and rs\n");
            if ((m & CTRL_L) == CTRL_L) printf(" .. and lc\n");
            if ((m & CTRL_R) == CTRL_R) printf(" .. and rc\n");
            if ((m & ALT_L) == ALT_L) printf(" .. and la\n");
            if ((m & ALT_R) == ALT_R) printf(" .. and ra\n");

    return 0;
share|improve this question
Do you really need the actual modifier key events, or do you just need to know their state when pressed together with "proper" keys? Xterm-compatible terminals do provide the latter. – ak2 Jan 19 '12 at 9:17
@ak2: how can I get what you suggest - if it is workable pls put it in an answer that I can accept. – slashmais Jan 19 '12 at 13:14
@ak2: PS - with X it is easy since the X event system provides it, I'm here referring to consoles (CLI) (not terminals in a GUI (X) environment) – slashmais Jan 20 '12 at 8:17
I don't mean X events, but xterm key codes, i.e. the character sequences sent for each key press. In a bash shell, press Ctrl+V followed by the key combination in question to see what each one sends. – ak2 Jan 20 '12 at 9:13
@ak2: xterm is a terminal emulator for the X Window System – slashmais Jan 20 '12 at 12:36
up vote 2 down vote accepted

Maybe have a look at libtermkey, a terminal key input library that recognises special keys (such as arrow and function keys), including "modified" keys like Ctrl-Left.

Another option might be to enhance the functionality of charm, a minimal ncurses copy.

share|improve this answer

In a terminal, it has always been really hard to have this kind of information. You can only get a "keycode" and, of course, it means different things depending on what combination of OS, keyboard and terminal you use.

You'll find a complete list of those keycode on your OS with a call to xmodmap.

$ xmodmap -pke
keycode   9 = Escape NoSymbol Escape
keycode  10 = ampersand 1 ampersand 1 dead_caron dead_ogonek dead_caron dead_ogonek
keycode  11 = eacute 2 eacute 2 asciitilde Eacute asciitilde Eacute
keycode 244 = XF86Battery NoSymbol XF86Battery
keycode 245 = XF86Bluetooth NoSymbol XF86Bluetooth
keycode 246 = XF86WLAN NoSymbol XF86WLAN
keycode 247 =

And a list of all modifiers value with this :

$ xmodmap
xmodmap:  up to 4 keys per modifier, (keycodes in parentheses):

shift       Shift_L (0x32),  Shift_R (0x3e)
lock        Caps_Lock (0x42)
control     Control_L (0x25),  Control_R (0x69)
mod1        Alt_L (0x40),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod4        Super_L (0x85),  Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)

There are some raw information in terminfo database or more polished in ncurses API in order to help system developers to overcome this mess.

If you can re-use an existing source code like nano's one, it should save you a lots of time. Take a look at the "get_escape_seq_kbinput" function to see what I mean.

If you just need modern linux support, it's possible that a call to keyname is enough.

share|improve this answer
nano uses either s-lang or (n)curses at the back.ncurses is a spaghetti-monster-code to fight thru. then there's also the loadkeys and family - another bizarre way of doing things. (PS: the nano maintainers really put a lot of work into it) – slashmais Jan 25 '12 at 8:35

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.