This questions about xlib not opengl but i figure some of you may know :)

hi, ive just created a simple demo involving movement and rotation of the camera. the problem is that their is a delay. by this i mean that when i hold down a button the movement/rotation will keep being triggered, which is what i want, but it has a pause between the first and second times the times the movement/rotation is triggered. it is exactly like the pause in a word processor when holding down a key. does anyone know how to eliminate this pause? thanks :slight_smile:

Instead of rotating by a fixed amount for each KeyPress event (which, when you hold a key down, means for each autorepeat), rotate by a fixed amount for a fixed time interval whenever the key is down.

In practical terms, this means not using blocking functions such as XNextEvent(). Instead use one of the XCheck*Event functions, which returns False if no suitable event is available. If that happens, use select() or poll() on the X socket (obtained via XConnectionNumber()) with a timeout, so that you still get to perform updates when no input events are being generated.

For more clues, look at the source code to GLUT.

kk ill look this over. i have never used poll or select before ill look through my xlib books and see what i can find on poll() and select()
this is what im gonna try first though:


while(1)
{
XCheckMaskEvent(display, ExposureMask | KeyPressMask, &report);
if report's-keysym == a
{
bool switch = true;
while(switch)
{
XCheckMaskEvent(display, ExposureMask | KeyReleaseMask, &report);
if (report's-keysym == release a) switch = false;
wait (0.05)
updategame()
maindisplayfunction()
}
}
maindisplayfunction()
}

does your way somehow involve somehow not having to put the maindisplayfunction() in each button’s “check if its held down” loop?

thanks

You may not find them mentioned in Xlib books; they’re core Unix functions.

Both functions have the same purpose: given a set of file descriptors, wait either until at least one of the descriptors can be read or written without blocking, or until a timeout occurs.

Because X uses a client-server architecture, once there are no more events queued in the client, you can wait for subsequent events by waiting on the file descriptor corresponding to the socket which connects the client to the server.

All that is done in response to a KeyPress/KeyRelease event is to set or clear a flag which indicates whether a given key is down.

Updates occur at regular time intervals regardless of which events are received. Once all pending events (if any) have been processed, you check whether it’s time for another update. If it isn’t, you calculate how long you should wait, then select/poll the socket with that value as a timeout.

When performing an update, you check whether any of the relevant keys are currently down based upon the flags mentioned above. If they are, you move/rotate by a fixed amount in the appropriate direction. If an update changes anything which would affect the display, then you perform a redraw.

The general logic behind a fixed update interval is:


void mainloop(void)
{
    static const int interval = 1.0/60; /* 60 updates/second */
    double last = get_time();

    while (1) {
	process_pending_events();

	double now = get_time();
	double elapsed = now - last;
	int updates = (int) floor(elapsed / interval);

	if (updates <= 0) {
            /* select/poll to wait for more events or timeout */
	    wait_for(interval - elapsed);
	}
	else {
	    for (int i = 0; i < updates; i++)
		update();
	    last += updates * interval;
	}
    }
}

okay i shall look over this, it might take me a while, but ill probably get it :slight_smile:
one last question, how would you handle multiple keys being held down? and do i need to do something special to get mouse input and multiple or single held down keys at the same time?

thanks so much for your great answer

That’s purely a design decision. Holding e.g. left+up may result in the two being combined (although you may wish to normalise the resulting vector, so that diagonal movement isn’t faster than orthogonal movement). Holding left+right may result in both being ignored, or you may wish to favour the last one pressed (in which case, the KeyDown handling needs to be changed from setting a flag to storing a timestamp).

No.

One caveat: most PC keyboards can’t handle arbitrary “chords” (multiple keys held at the same time). Pressing two keys at the same time always works. With three or more keys, it depends upon their location in the matrix. Any number of modifier keys (Shift, Control, Alt) with one non-modifier key should always work.

http://www.dribin.org/dave/keyboard/one_html/

hey, one last thing, can you point me to a place where i can learn about poll() and select()? preferably a website, but a book might be alright…
thanks

I couldn’t find a decent tutorial, but it should be covered in any decent book (e.g. Stevens’ “Advanced Programming in the Unix(R) Environment”; in spite of its name, it doesn’t assume any prior knowledge).

But maybe the information given in the manual pages is enough: select(3) and poll(3).

Both perform essentially the same function but with slightly different interfaces; poll() offers additional options which aren’t required here.

Briefly, to wait until the X server sends more data or a timeout occurs:


void wait_for(Display *dpy, double seconds)
{
    fd_set read_fds;
    struct timeval tv;
    /* convert seconds from double to integer seconds+microseconds */
    tv.tv_sec = (int)floor(seconds);
    tv.tv_usec = (int)((seconds - tv.tv_sec) * 1e6);
    /* initialise the set to contain the descriptor for the X connection */
    FD_ZERO(&read_fds);
    FD_SET(XConnectionNumber(dpy), &read_fds);
    /* wait until the X connection has more data or the timeout expires */
    select(FD_SETSIZE, &read_fds, NULL, NULL, &tv);
}

An fd_set is a set (bitmask) of file descriptors. select() accepts 3 such sets, corresponding to descriptors which should be checked for read, write or error conditions. A set is initialised with FD_ZERO(), descriptors are added or removed with FD_SET() and FD_CLR() (to set and clear the bit corresponding to a single descriptor). select() modifies the sets to indicate which descriptors are actually ready for read or write or have an error condition. Once select() returns, you can check whether a set includes a given descriptor with FD_ISSET().

poll() uses an array of structures instead of a bitmask. This has a number of advantages, but poll() is newer and perhaps less well known (the disadvantages of select() became more significant as computers became more powerful and processes started dealing with thousands of descriptors rather than dozens).

thanks for all the help, thats all :slight_smile:

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.