using keyboard arrows - Unix

This is a discussion on using keyboard arrows - Unix ; Hi I am trying to write a small application to control a mobile robot from the keyboard. What I really need is to handle multiple keys pressed at one time. If it's too difficult with arrow keys I don't mind ...

+ Reply to Thread
Results 1 to 9 of 9

Thread: using keyboard arrows

  1. using keyboard arrows

    Hi

    I am trying to write a small application to control a mobile robot
    from the keyboard. What I really need is to handle multiple keys
    pressed at one time. If it's too difficult with arrow keys I don't
    mind using another combination like WSAD.

    I tried doing it from a console application using termios related
    stuffs, taking as example showkey from the kbd package, but I didn't
    manage to handle 2 keys at one time. I tried to distinguish between
    press and release state though. Besides the console keeps scrolling
    down very fast, so it's not easy to debug. Plus it requires super user
    privileges to open tty0. The code is at the end of this message.

    I don't mind using curse if it does the job... Portability is not an
    issue in that case. I have never used ncurse before; reading their
    documentation I could not find a proof that ncurse would handle
    multiple keys pressed at one time.

    Any idea of what would be a good way of doing this?






    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    int fd=-1, oldkbmode=-1;
    struct termios orig_kb;
    float linvel=0, rotvel=0;

    void initKbd(){
    struct termios newkbd;
    fd = open("/dev/tty0", O_RDONLY);
    tcgetattr ( fd, &orig_kb );
    tcgetattr ( fd, &newkbd );
    newkbd.c_lflag &= ~ (ECHO | ICANON I ISIG);
    newkbd.c_iflag = 0;
    newkbd.c_cc[VMIN] = 18;
    newkbd.c_cc[VTIME] = 1;
    tcsetattr ( fd, TCSAFLUSH, &newkbd );
    ioctl ( fd, KDGKBMODE, &oldkbmode );
    ioctl ( fd, KDSKBMODE, K_MEDIUMRAW );
    atexit(clean_up);
    }

    void clean_up ( void ) {
    ioctl ( fd, KDSKBMODE, oldkbmode );
    tcsetattr ( fd, 0, &orig_kb );
    close ( fd );
    }

    void * kbdThFunc(void *dummy){
    int keycode, pressed, controlPressed=0;
    float linvel=0,rotvel=0;
    while( 1 ){
    unsigned char buf[18]; /* divisible by 3 */
    int n = read ( fd, buf, sizeof ( buf ) );
    int i = 0;
    while ( i < n ) {
    if ( i+2 < n && ( buf[i] & 0x7f ) == 0
    && ( buf[i+1] & 0x80 ) != 0 && ( buf[i+2] & 0x80 ) != 0 ) {
    keycode = ( ( buf[i+1] & 0x7f ) << 7 ) | ( buf[i+2] & 0x7f );
    i += 3;
    }
    else keycode = ( buf[i++] & 0x7f );
    pressed = (buf[i] & 0x80) ? 0 : 1;
    }
    switch ( keycode ) {
    case 103: //UP ARROW
    case 'w':
    if( pressed ) linvel = 1;
    else linvel = 0;
    break;
    case 108: //DOWN ARROW
    case 's':
    if( pressed ) linvel = -1;
    else linvel = 0;
    break;
    case 105: //LEFT ARROW
    case 'a':
    if( pressed ) rotvel = -1;
    else linvel = 0;
    break;
    case 106: //RIGHT ARROW
    case 'd':
    if( pressed ) rotvel = 1;
    else linvel = 0;
    break;
    case 29: //CTRL
    controlPressed = pressed;
    break;
    case 46: //C
    if( controlPressed && pressed ) exit(0);
    break;
    }
    }
    return NULL;
    }

    int main(){
    pthread_t tid;
    initKbd();
    pthread_create(&tid,NULL,kbdThFunc,NULL);
    while(1){
    printf("%f %f\n",linvel,rotvel);
    sleep(1);
    }
    return 0;
    }

  2. Re: using keyboard arrows

    Brice Rebsamen writes:

    > I tried doing it from a console application using termios related
    > stuffs, taking as example showkey from the kbd package, but I didn't
    > manage to handle 2 keys at one time.


    The inner loop in kbdThFunc seems wrong. If one read() call
    returns with multiple keycodes in the buffer, you should process
    all of them. Now you instead store them to the keycode and
    pressed variables one at a time and then only use the last.
    Also, you're doing this:

    > else keycode = ( buf[i++] & 0x7f );
    > pressed = (buf[i] & 0x80) ? 0 : 1;


    i.e. the values of keycode and pressed are coming from different
    elements of buf. That seems wrong too.

    > Plus it requires super user privileges to open tty0.


    If you just used stdin or /dev/tty, then it'd work without
    superuser privileges, provided the program is actually running
    directly on a virtual console and not e.g. in Screen or xterm.

    You might also consider making an X program and then getting the
    keypresses and releases as X events. That would even be
    portable. Try with xev for example. If you want things to work
    both in the console and in X, there's libsdl for that.

    > I don't mind using curse if it does the job... Portability is not an
    > issue in that case. I have never used ncurse before; reading their
    > documentation I could not find a proof that ncurse would handle
    > multiple keys pressed at one time.


    Curses won't help.

  3. Re: using keyboard arrows

    > > Plus it requires super user privileges to open tty0.
    >
    > If you just used stdin or /dev/tty, then it'd work without
    > superuser privileges


    How to use stdin or /dev/tty?
    I tried:

    fd = fileno(stdin);
    // fd = open("/dev/tty", O_RDONLY)
    tcgetattr ( fd, &orig_kb );
    tcgetattr ( fd, &newkbd );
    newkbd.c_lflag &= ~ (ECHO | ICANON | ISIG | IEXTEN);
    newkbd.c_iflag = 0;
    newkbd.c_cc[VMIN] = 18;
    newkbd.c_cc[VTIME] = 1;
    tcsetattr ( fd, TCSAFLUSH, &newkbd );
    ioctl ( fd, KDGKBMODE, &oldkbmode );

    The last call fails with error code EINVAL

    > provided the program is actually running
    > directly on a virtual console and not e.g. in Screen or xterm.


    I am using the KDE terminal Konsole. Is it an xterm or a virtual
    console or ... ?

    > You might also consider making an X program and then getting the
    > keypresses and releases as X events. That would even be
    > portable. Try with xev for example. If you want things to work
    > both in the console and in X, there's libsdl for that.


    I took a quick look at libsdl. It looks promising. If I can't fix my
    current code I'll give it a shot.

    Thanks for your help.

  4. Re: using keyboard arrows

    Brice Rebsamen writes:

    > I am using the KDE terminal Konsole. Is it an xterm or a virtual
    > console or ... ?


    If you're going to run the program in KDE, thus X, you should
    certainly use the facilities of X rather than ioctl KDSKBMODE.
    That way, your program also does not hog the whole keyboard,
    rather it only gets the events meant for its own X window.

    It isn't terribly hard to implement this with Xlib.
    Perhaps it is even easier with libsdl; I don't know.

  5. Re: using keyboard arrows

    On Mar 12, 11:10 pm, Brice Rebsamen wrote:
    > Hi
    >
    > I am trying to write a small application to control a mobile robot
    > from the keyboard. What I really need is to handle multiple keys
    > pressed at one time. If it's too difficult with arrow keys I don't
    > mind using another combination like WSAD.


    > Any idea of what would be a good way of doing this?



    Using X11 might be more suitable. Try this little program:

    #include
    #include

    int main()
    {
    Display* d = XOpenDisplay(0);
    Window w, root;
    root = RootWindow(d, DefaultScreen(d));
    w = XCreateSimpleWindow(d, root, 100, 100, 640, 480, 0, 0, 0);
    XSelectInput(d, w, KeyPressMask | KeyReleaseMask);
    XMapWindow(d, w);

    XEvent e;
    for(;
    {
    XNextEvent(d, &e);

    if(e.type == KeyPress || e.type == KeyRelease)
    {
    KeySym k;
    k = XLookupKeysym(&(e.xkey), e.xkey.state);
    printf("keycode=%i key=%s %s\n", e.xkey.keycode,
    XKeysymToString(k), e.type == KeyPress ?"pressed":"released");
    }
    }
    }

    It probably does a goot bit of what you want with regards to key
    presses. Note that XNextEvent is a blocking call, which you probably
    don't want. However, the non-blocking call XPending(d) tells you if
    XNextEvent will block.


    -Ed
    --
    (You can't go wrong with psycho-rats.)(http://mi.eng.cam.ac.uk/~er258)

    /d{def}def/f{/Times s selectfont}d/s{11}d/r{roll}d f 2/m{moveto}d -1
    r 230 350 m 0 1 179{ 1 index show 88 rotate 4 mul 0 rmoveto}for/s 12
    d f pop 235 420 translate 0 0 moveto 1 2 scale show showpage



  6. Re: using keyboard arrows

    On Mar 14, 3:53 am, Edward Rosten wrote:
    > On Mar 12, 11:10 pm, Brice Rebsamen wrote:
    >
    > > Hi

    >
    > > I am trying to write a small application to control a mobile robot
    > > from the keyboard. What I really need is to handle multiple keys
    > > pressed at one time. If it's too difficult with arrow keys I don't
    > > mind using another combination like WSAD.
    > > Any idea of what would be a good way of doing this?

    >
    > Using X11 might be more suitable. Try this little program:
    >
    > #include
    > #include
    >
    > int main()
    > {
    > Display* d = XOpenDisplay(0);
    > Window w, root;
    > root = RootWindow(d, DefaultScreen(d));
    > w = XCreateSimpleWindow(d, root, 100, 100, 640, 480, 0, 0, 0);
    > XSelectInput(d, w, KeyPressMask | KeyReleaseMask);
    > XMapWindow(d, w);
    >
    > XEvent e;
    > for(;
    > {
    > XNextEvent(d, &e);
    >
    > if(e.type == KeyPress || e.type == KeyRelease)
    > {
    > KeySym k;
    > k = XLookupKeysym(&(e.xkey), e.xkey.state);
    > printf("keycode=%i key=%s %s\n", e.xkey.keycode,
    > XKeysymToString(k), e.type == KeyPress ?"pressed":"released");
    > }
    > }
    >
    > }
    >
    > It probably does a goot bit of what you want with regards to key
    > presses. Note that XNextEvent is a blocking call, which you probably
    > don't want. However, the non-blocking call XPending(d) tells you if
    > XNextEvent will block.
    >
    > -Ed
    > --
    > (You can't go wrong with psycho-rats.)(http://mi.eng.cam.ac.uk/~er258)
    >
    > /d{def}def/f{/Times s selectfont}d/s{11}d/r{roll}d f 2/m{moveto}d -1
    > r 230 350 m 0 1 179{ 1 index show 88 rotate 4 mul 0 rmoveto}for/s 12
    > d f pop 235 420 translate 0 0 moveto 1 2 scale show showpage




    this code is great and is a very good solution to my problem. Can you
    just tell me how to map a key to an action. I am using switch case
    block like this:

    #include
    #include

    switch ( e.xkey.keycode ) {
    case XK_Up: case XK_W: case XK_w: case XK_KP_Up: case XK_KP_8:
    linvel = e.type==KeyPress ? 1 : 0;
    break;
    case XK_Down: case XK_S: case XK_s: case XK_KP_Down: case
    XK_KP_2:
    linvel = e.type==KeyPress ? -1 : 0;
    break;
    case XK_Left: case XK_A: case XK_a: case XK_KP_Left: case
    XK_KP_4:
    rotvel = e.type==KeyPress ? -1 : 0;
    break;
    case XK_Right: case XK_D: case XK_d: case XK_KP_Right: case
    XK_KP_6:
    rotvel = e.type==KeyPress ? 1 : 0;
    break;
    }

    But it does not work. How can I know which key is pressed?

  7. Re: using keyboard arrows

    On Mar 13, 4:49 pm, Kalle Olavi Niemitalo wrote:
    > Brice Rebsamen writes:
    > > I tried doing it from a console application using termios related
    > > stuffs, taking as example showkey from the kbd package, but I didn't
    > > manage to handle 2 keys at one time.

    >
    > The inner loop in kbdThFunc seems wrong. If one read() call
    > returns with multiple keycodes in the buffer, you should process
    > all of them. Now you instead store them to the keycode and
    > pressed variables one at a time and then only use the last.
    > Also, you're doing this:
    >
    > > else keycode = ( buf[i++] & 0x7f );
    > > pressed = (buf[i] & 0x80) ? 0 : 1;

    >
    > i.e. the values of keycode and pressed are coming from different
    > elements of buf. That seems wrong too.
    >
    > > Plus it requires super user privileges to open tty0.

    >
    > If you just used stdin or /dev/tty, then it'd work without
    > superuser privileges, provided the program is actually running
    > directly on a virtual console and not e.g. in Screen or xterm.
    >
    > You might also consider making an X program and then getting the
    > keypresses and releases as X events. That would even be
    > portable. Try with xev for example. If you want things to work
    > both in the console and in X, there's libsdl for that.
    >
    > > I don't mind using curse if it does the job... Portability is not an
    > > issue in that case. I have never used ncurse before; reading their
    > > documentation I could not find a proof that ncurse would handle
    > > multiple keys pressed at one time.

    >
    > Curses won't help.


    I fixed the keycode interpretation loop. Now it's working properly.
    There is still one problem: the terminal keeps scrolling down, as if I
    was continuously pressing down the ENTER key. How can I suppress that?

  8. Re: using keyboard arrows

    Brice Rebsamen writes:

    > switch ( e.xkey.keycode ) {
    > case XK_Up: case XK_W: case XK_w: case XK_KP_Up: case XK_KP_8:


    These XK_ constants are keysyms, not keycodes. So you should
    compare them to the values returned by XLookupKeysym, not to
    e.xkey.keycode.

    I suppose it's also possible to examine the keymap beforehand,
    make a list of the interesting keycodes, and then use that. It
    would be more difficult however, especially with the more complex
    keymaps made possible by the X Keyboard Extension (XKB).

  9. Re: using keyboard arrows

    On Mar 14, 3:45 pm, Kalle Olavi Niemitalo wrote:
    > Brice Rebsamen writes:
    > > switch ( e.xkey.keycode ) {
    > > case XK_Up: case XK_W: case XK_w: case XK_KP_Up: case XK_KP_8:

    >
    > These XK_ constants are keysyms, not keycodes. So you should
    > compare them to the values returned by XLookupKeysym, not to
    > e.xkey.keycode.
    >
    > I suppose it's also possible to examine the keymap beforehand,
    > make a list of the interesting keycodes, and then use that. It
    > would be more difficult however, especially with the more complex
    > keymaps made possible by the X Keyboard Extension (XKB).


    Ok, it works well. And it's definitely better than the ioctl
    KDSKBMODE: there is no risk that I mess my keyboard anymore. And the
    code is so much simpler.
    Thanks guys.

+ Reply to Thread