Xlib tutorial part 16 -- Keyboard Input

by Alan at Mon 20th Jul 2009 1:00AM EST

Hello, and welcome to part 15 of this Xlib tutorial.

This week we're going to look at making the keyboard input. You can get the code

I've reduced the code to just what's necessary to demonstrate some new concepts. We'll hook up the buttons and menus in a later lesson.


/* first include the standard headers that we're likely to need */
#include <X11/Xlib.h<
#include <X11/Xutil.h<
#include <X11/Xresource.h<
#include <stdio.h<
#include <stdlib.h<
#include <string.h<

int main(int argc, char ** argv){
	int screen_num, width, height;
	unsigned long background, border;
	Window win;
	XEvent ev;
	Display *dpy;

	/* First connect to the display server */
	dpy = XOpenDisplay(NULL);
	if (!dpy) {fprintf(stderr, "unable to connect to displayn");return 7;}

	/* these are macros that pull useful data out of the display object */
	/* we use these bits of info enough to want them in their own variables */
	screen_num = DefaultScreen(dpy);
	background = BlackPixel(dpy, screen_num);
	border = WhitePixel(dpy, screen_num);

	width = 40; /* start with a small window */
	height = 40;

	win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), /* display, parent */
		0,0, /* x, y: the window manager will place the window elsewhere */
		width, height, /* width, height */
		2, border, /* border width & colour, unless you have a window manager */
		background); /* background colour */

This should all look familiar so far. The next line won't look very different either. Note that we want to know when keyboard keys are changed.


	/* tell the display server what kind of events we would like to see */
	XSelectInput(dpy, win, ButtonPressMask|StructureNotifyMask|KeyPressMask|KeyReleaseMask|KeymapStateMask);

	/* okay, put the window on the screen, please */
	XMapWindow(dpy, win);

Below is the main loop. The two things that are interesting are the XRefreshKeyboardMapping() call (which is good practice to do since another process may change the mapping and the KeymapNotify notifies us that it's happened) and the XLookupString() call. The XLookupString() call turns the ev.xkey which can be anything, into a string and a key symbol. The string will be filled with whatever the key is mapped to (and can be remapped). The keysym is a slightly different thing. In this case we don't use it, but if we wanted to support the function keys, the escape key, backspace, the page up keys etc, we would have to look at the keysym and compare them to the values defined in <X11/keysymdef.h>.


	/* as each event that we asked about occurs, we respond.  In this
	 * case we note if the window's shape changed, and exit if a button
	 * is pressed inside the window */
	while(1){
		XNextEvent(dpy, &ev);
		switch(ev.type){
		case KeymapNotify:
			XRefreshKeyboardMapping(&ev.xmapping);
			break;
		case KeyPress: break; /* ignore these */
		case KeyRelease:
			{
				char string[25];
				int len;
				KeySym keysym;
				len = XLookupString(&ev.xkey, string, 25, &keysym, NULL);
				if (len < 0){
					if (string[0] == 'r'){
						string[0] = 'n';
					}
					fputs(string, stdout);
				}
			}
			break;
		case ConfigureNotify:
			if (width != ev.xconfigure.width
					|| height != ev.xconfigure.height) {
				width = ev.xconfigure.width;
				height = ev.xconfigure.height;
				printf("Size changed to: %d by %dn", width, height);
			}
			break;
		case ButtonPress:
			XCloseDisplay(dpy);
			return 0;
		}
	}
}

That's all I'm going to do this week. Try playing around with it to see what you can get it to do. Did you notice that (assuming you're on a unix like machine) that when you type, nothing shows up until you press enter? Do you know why? I can assure you that it has nothing to do with X. But you could put a fflush(NULL) call in after the fputs() call and it will change.

Comments are closed.