Thread: Tracking key release in Linux.

  1. #1
    Registered User
    Join Date
    Feb 2010
    Posts
    12

    Tracking key release in Linux.

    I've been looking for how to find when a key is released, through C, in Linux, and from what I found, putting the keyboard in raw/keycode mode is the best way.
    However, I don't know what to do from there, and can't find any simple examples.
    What I need is this:
    A key is pressed and the program pauses until that same key is released, then returning to execution.
    Does anyone have any examples of how to do this?
    Is entering raw/keycode mode the best way or do you know any other way?
    I can use non standard libraries, but I'm working with linux compatible ones only.

    Thank you for your time.

  2. #2
    Registered User jeffcobb's Avatar
    Join Date
    Dec 2009
    Location
    Henderson, NV
    Posts
    875
    Look up ncurses. It is not standard C but then any but the most trivial keyboard IO isn't. That library will give the basics for detecting when a key is pressed, let up, etc.

    If you are working with non-character mode stuff look into libx-dev....

    let me know if you have more questions...
    C/C++ Environment: GNU CC/Emacs
    Make system: CMake
    Debuggers: Valgrind/GDB

  3. #3
    Registered User
    Join Date
    Feb 2010
    Posts
    12
    I've searched through ncurses tutorials, FAQs, etc. and can't find anything about key releases :S
    Do you know of a function/variable name I can look that may give me more information?
    Thanks.

  4. #4
    Registered User jeffcobb's Avatar
    Join Date
    Dec 2009
    Location
    Henderson, NV
    Posts
    875
    First hit I found with Google...what did you use as a search key?
    Basic keyboard input
    C/C++ Environment: GNU CC/Emacs
    Make system: CMake
    Debuggers: Valgrind/GDB

  5. #5
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    The ncurses function you are looking for is getch():

    getch(3): char from curses terminal keyboard - Linux man page

    I learnt ncurses largely from:
    NCURSES Programming HOWTO
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  6. #6
    Registered User
    Join Date
    Feb 2010
    Posts
    12
    I've been to those sites that you provided, and use getch() in the program. The problem is that I didn't see anything about using it to detect when a key is released.
    Doesn't getch() only return a character without waiting for enter to be pressed? Or does it have some way of detecting when a key is released?

    Thanks for your time.

  7. #7
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Cynary View Post
    A key is pressed and the program pauses until that same key is released, then returning to
    !Facepalm

    AFAIK you can't do that with ncurses, it returns the value of a keypress event which happens when the key is released -- but not before that. You are looking to separate key down from key up. If you want to deal with keyup/keydown events without having to hack the kernel driver, you probably have to be in X, aka "GUI" mode (most people are...), in which case key up key down are handled as XEvents. X does deal directly with the kernel and hardware, all linux systems use it.

    http://tronche.com/gui/x/xlib/

    You get handed these in some graphically oriented high level libraries which involve the creation of a window, but you can also make requests to the window your console emulator is running in (eg, the Xterm or gnome-terminal or whatever). If you think you want to go that route post again and I can show you how to identify your window for Xlib purposes.

    I haven't done those events with Xlib, but I have used it to manipulate window geometry and flash the keyboard LEDS (num lock, etc) in goofy patterns, so I know some stuff about the event interface.
    Last edited by MK27; 02-14-2010 at 08:07 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  8. #8
    Registered User
    Join Date
    Feb 2010
    Posts
    12
    If it wasn't much trouble, I'd thank if you taught me how to make requests to the window of the console emulator. The program doesn't really need a GUI, and I want to keep it as simples as I can.

    Thanks for your time ... again xD

  9. #9
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    First, I think you should have a look here
    http://tronche.com/gui/x/xlib/events...d-pointer.html
    and decide if you really need to get a window. If you don't need to submit a datatype Window* to any of the Xlib functions you need to use, then life is much easier.


    But if you do, to give you an idea of what's involved, this is a program to list all your windows and whether or not they will accept an EWMH request to go fullscreen (that is, remove the titlebar and borders). You can do that to most windows on some window managers this way. But that does not really matter to you.

    If you run it without any arguments, it just lists the windows and possibly some stuff about _NET_WM_ALLOWED_ACTIONS.

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <X11/Xlib.h>
    #include <X11/Xatom.h>
    #include <errno.h>
    
    /* compile -lX11 */
    
    Atom *actionlist (Display *disp, Window win, unsigned long *len); 
    char *atomtype (Atom x);
    int getprop (Display *disp, char *name, Window win);
    void makeRequest(Display *disp, Window win, char *req);
    Window *winlist (Display *disp, unsigned long *len);
    char *winame (Display *disp, Window win); 
    
    int main(int argc, char *argv[]) {
    	int i,j;
    	unsigned long len, l2;
    	Display *disp = XOpenDisplay(NULL);
    	Window *list;
    	Atom *actions, act;
    	char *name, *props[] = {
    /* these are NOT defined in any header */
    		"_NET_SUPPORTED",
    		"_NET_CLIENT_LIST",
    		"WM_NAME"
    	};
    
    	if (!disp) {
    		puts("no display!");
    		return -1;
    	}
    
    	for (i=0;i<3;i++) getprop(disp,props[i],XDefaultRootWindow(disp));
    
    	list = (Window*)winlist(disp,&len);
    
    	act = XInternAtom(disp,"_NET_WM_ACTION_FULLSCREEN",False);
    
    	for (i=0;i<(int)len;i++) {
    		name = winame(disp,list[i]);
    		printf("\n%s:\n",name);
    		if (argc == 2 && !strcmp(name,argv[1])) {
    			makeRequest(disp,list[i],"_NET_WM_STATE_FULLSCREEN");
    			printf("Tried\n"); fflush(stdout);
    		}
    		free(name);
    		getprop(disp,"_NET_WM_ALLOWED_ACTIONS",list[i]);
    		actions = actionlist(disp,list[i],&l2);
    		for (j=0;j<l2;j++) if (actions[j] == act) puts("\t***Fullscreen Available***");
    		XFree(actions);
    	}
    
    	XFree(list);
    
    	XCloseDisplay(disp);
    	return 0;
    }
    
    
    Atom *actionlist (Display *disp, Window win, unsigned long *len) {
    	Atom prop = XInternAtom(disp,"_NET_WM_ALLOWED_ACTIONS",False), type;
    	int form;
    	unsigned long remain;
    	unsigned char *list;
    
    	errno = 0;
    	if (XGetWindowProperty(disp,win,prop,0,1024,False,XA_ATOM,&type,&form,len,&remain,&list) != Success) {
    		perror("actionlist() -- GetWinProp");
    		return 0;
    	}
    
    	return (Atom*)list;
    }
    
    
    char *atomtype (Atom x) {
    	char *type = malloc(32);
    	switch (x) {
    		case XA_PRIMARY:
    			strcpy(type,"XA_PRIMARY");
    			break;
    		case XA_SECONDARY:
    			strcpy(type,"XA_SECONDARY");
    			break;
    		case XA_ARC:
    			strcpy(type,"XA_ARC");
    			break;
    		case XA_ATOM:
    			strcpy(type,"XA_ATOM");
    			break;
    		case XA_CARDINAL:
    			strcpy(type,"XA_CARDINAL");
    			break;
    		case XA_INTEGER:
    			strcpy(type,"XA_INTEGER");
    			break;
    		case XA_STRING:
    			strcpy(type,"XA_STRING");
    			break;
    		case XA_WINDOW:
    			strcpy(type,"XA_WINDOW");
    			break;
    		case XA_WM_HINTS:
    			strcpy(type,"XA_WM_HINTS");
    			break;
    		default:
    			sprintf(type,"unlisted (%lu), see Xatom.h",x);
    			break;
    		}
    		return type;
    }
    
    
    
    int getprop (Display *disp, char *name, Window win) {
    	Atom prop = XInternAtom(disp,name,False), type;
    	int form, r = 0;
    	unsigned long len, remain;
    	unsigned char *list;
    	char *tname;
    
    	errno = 0;
    	if (XGetWindowProperty(disp,win,prop,0,1024,False,AnyPropertyType,&type,&form,&len,&remain,&list) != Success) {
    		perror("GetWinProp");
    		return 0;
    	}
    	if (type == None) printf("%s is not available.\n",name);
    	else {
    		tname = atomtype(type);
    		printf ("%s (type %s, %lu %d-bit items) remaining: %lu\n",name,tname,len,form,remain);
    		XFree(tname);
    		r = 1;
    	}
    	XFree(list);
    	return r;
    }
    
    
    void makeRequest(Display *disp, Window win, char *req) {
    	XEvent event;
    	Status r;
    	long mask = SubstructureRedirectMask | SubstructureNotifyMask;
    	//long mask = SubstructureNotifyMask;
    	//long mask = StructureNotifyMask | ResizeRedirectMask;
    	//long mask = SubstructureRedirectMask;
    	//long mask = PropertyChangeMask;
    
    	event.xclient.type = ClientMessage;
    	event.xclient.serial = 0;
    	event.xclient.send_event = True;
    	event.xclient.display = disp;
    	event.xclient.window = win;
    	event.xclient.message_type = XInternAtom(disp,"_NET_WM_STATE",False);
    	event.xclient.format = 32;
    	event.xclient.data.l[0] = 1;
    	event.xclient.data.l[1] = XInternAtom(disp,req,False);
        event.xclient.data.l[2] = 0;
        event.xclient.data.l[3] = 0;
        event.xclient.data.l[4] = 0;
    
    	if ((r=XSendEvent(disp,XDefaultRootWindow(disp),False,mask,&event)) != Success) printf("makeRequest error: %d\n",r);
    }
    
    
    Window *winlist (Display *disp, unsigned long *len) {
    	Atom prop = XInternAtom(disp,"_NET_CLIENT_LIST",False), type;
    	int form;
    	unsigned long remain;
    	unsigned char *list;
    
    	errno = 0;
    	if (XGetWindowProperty(disp,XDefaultRootWindow(disp),prop,0,1024,False,XA_WINDOW,&type,&form,len,&remain,&list) != Success) {
    		perror("winlist() -- GetWinProp");
    		return 0;
    	}
    	
    	return (Window*)list;
    }
    
    
    char *winame (Display *disp, Window win) {
    	Atom prop = XInternAtom(disp,"WM_NAME",False), type;
    	int form;
    	unsigned long remain, len;
    	unsigned char *list;
    
    	errno = 0;
    	if (XGetWindowProperty(disp,win,prop,0,1024,False,XA_STRING,&type,&form,&len,&remain,&list) != Success) {
    		perror("winlist() -- GetWinProp");
    		return NULL;
    	}
    //printf("%s %d\n",(char*)list, len); fflush(stdout);
    
    	return (char*)list;
    }
    Compile that:
    gcc thatcode.c -lX11
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  10. #10
    Registered User
    Join Date
    Feb 2010
    Posts
    12
    Thanks for your help!
    I'll start studying X tomorrow.
    Although monitoring X events is probably the best way to find a mouse up event, I developed in the meanwhile a simpler code to do that, that uses ncurses.
    For anyone interested:

    Code:
    #include <ncurses.h>
    
    int main() {
      char c;
      initscr();
      cbreak();
      noecho();
      keypad(stdscr, TRUE);
      while('q' != (c = getch())) {
        printw("%c\n", c);
        if(halfdelay(5) != ERR) {
          while(getch() == c)
            if(halfdelay(1) == ERR) break; }
        printw("Here\n");
        cbreak(); }
      endwin();
      return 0; }
    You press a key, it prints the key value and waits until you release it to print Here.

  11. #11
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Well Hallelujah!

    That'll work I guess -- no key pressed == ERR. Bravo.

    If you can stick with ncurses to do what you want, do.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C++ / Linux Developer - Menlo Park, CA
    By rmitsearch in forum Projects and Job Recruitment
    Replies: 0
    Last Post: 02-09-2005, 12:06 AM
  2. installing linux for the first time
    By Micko in forum Tech Board
    Replies: 9
    Last Post: 12-06-2004, 05:15 AM
  3. BCB Key press problem
    By Death_Wraith in forum Game Programming
    Replies: 0
    Last Post: 05-30-2004, 03:13 PM
  4. Linux for Windows!
    By Strut in forum Linux Programming
    Replies: 2
    Last Post: 12-25-2002, 11:36 AM
  5. Linux? Windows Xp?
    By VooDoo in forum Linux Programming
    Replies: 15
    Last Post: 07-31-2002, 08:18 AM