The Science Boy
The Science Boy

Reputation: 359

Capturing key events in the linux console

I have a problem, that is similar to a lot of other's before me, but different in a way that makes it much more difficult. :)

I'm writing a text editor for the Linux console. There is no X11 running, so forget about any toolkit for that. I want to capture key down and key-up events as I want to be able to mark sections of text by holding down shift and using the arrow keys (much like you would in an X-based or Windows-based editor).

I've previously managed to write an application that uses raw mode to access key scancodes, but it is unable to handle detecting shift key and arrow keys at the same time.

Does anyone have an example code that is able to detect any key combinations (or at least all combinations with shift, ctrl and alt).

Upvotes: 1

Views: 3971

Answers (2)

Jonas Schäfer
Jonas Schäfer

Reputation: 20718

How about using ncurses, which does all that for you? It also helps you with figuring out how to format text for the particular terminal type you're connected with and so on.

Using the getkey() function the python binding provide, I am able to find out modifiers for different keys. I also found out that for Shift+Arrow keys, there is a separate key code, abbreviated with KEY_SR, KEY_SF for up and down and KEY_SLEFT and KEY_SRIGHT.

import curses
import curses.textpad
import curses.ascii

def decodeSuffix(i):
    return {
        0b110: ( True,  True,   False),
        0b100: ( True, False,    True),
        0b111: (False,  True,    True),
        0b101: (False,  True,   False),
        0b011: (False, False,    True),
    }[i]

def test(stdscr):
    while True:
        k = stdscr.getkey()
        if k == "\n":
            return
        elif k[0] == "k" and len(k) > 1:
            i = int(k[-1])
            shift, ctrl, alt = decodeSuffix(i)
            s = ""
            if shift:
                s += "shift "
            if ctrl:
                s += "ctrl "
            if alt:
                s += "alt "
            s += k[1:-1]
            stdscr.addstr("{0:40s} {1:08b}\n".format(s, i))
        else:
            stdscr.addstr("{0}\n".format(k))
            pass

curses.wrapper(test)

You may play around with that. Looking at the source of getkey(), we find that it's basically a combination of getch and keyname curses functions.

Upvotes: 1

The Science Boy
The Science Boy

Reputation: 359

I have sort of managed to do what I set out to do. The only problem is it requires that I connect directly to the keyboard driver. Right now I do not know how to do that without root privileges, so my editor requires root. This could be awkward.

In short, I open the /dev/input/event? stream, where ? is the number of the keyboard driver (most often 0) and capture the key-presses from there. This is really only useful for checking the state of a key (by building a key-state from the down and up-press events) since the events are delivered from all applications (this is after all the keyboard driver).

It is better to get all other key-presses from a more conventional source and just use the keyboard driver for CTRL, SHIFT and so on.

I'll post code later if I get it to work together. :)

Upvotes: 0

Related Questions