Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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;
}

enum MODKEYS
{
    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
1  
@ak2: xterm is a terminal emulator for the X Window System –  slashmais Jan 20 '12 at 12:36
show 1 more comment

2 Answers

up vote 2 down vote accepted
+50

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
add comment

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)
mod3      
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
add comment

Your Answer

 
discard

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.