Shiny New E-Book Gizmo: The Amazon Kindle


View Full Version : Access the hardware keys


thebohemian
10-01-2007, 07:04 AM
Hi,
I am new to Iliad development. :)

I want to receive events when someone presses any of the hardware keys of the iliad. Can you tell me how that can be done?

Can I even get keyboard events when my app is not the focused one? If so, how? :)

Regards

jharker
10-01-2007, 04:15 PM
Actually, I've studied this question in great detail. It's much more complicated than you might think. I started a thread about it (http://forum.irexnet.com/viewtopic.php?t=1607) over at the iRex forum, but I never posted detailed information about it. For the interested, here's a summary.

The iLiad buttons can be grouped into two categories. Yes, the power switch is considered a "button". normal buttons : flipbar, up arrow, down arrow, dot key, and the escape button (upper left corner). special buttons : 'books', 'news', 'notes', 'docs', IDS connect, the power switch, and the menu button (directly above the flipbar).
First of all, the buttons on the iLiad do not work in the usual way. The usual way is for the button driver to masquerade as a "keyboard" which is read directly by the X server, which then passes key signals to the appropriate application.

Instead, the ContentLister program runs in the background all the time and constantly queries the hardware buttons at /dev/buttons directly using ioctls. When a button is pressed, the ContentLister decides whether it was a "long press" or a "short press" and what to do with it. If it's a "normal" button, the ContentLister sends a key press event to the X server. (Matthijs informed me that XSendEvent is used for this, thanks, Matthijs!) If it's a "special" button, the ContentLister never passes it to the X server at all. More on this later.

You can easily use any of the "normal" buttons you want, simply by getting them through the X server. Here's how the "normal" buttons are represented as key presses in X via GDK:Button Press Keypress Equivalent
============ ===================
Up Arrow GDK_Up
Dot (Enter) GDK_Return
Down Arrow GDK_Down

Long Up Arrow GDK_F4
Long Dot (Enter) GDK_F6
Long Down Arrow GDK_F3

Page Forward GDK_Page_Down
Page Back GDK_Page_Up

Long Page Forward GDK_F1
Long Page Back GDK_F2

Escape GDK_F5

As I said above, if you press one of "special" buttons, it's completely different. The ContentLister takes care of the button press functionality by itself and doesn't pass anything to the X server. For example, if you press the 'books' key, the ContentLister will close whatever program is open, then display the "books" directory on your memory card.

So, there's no way to read any of the "special" buttons without writing your own program to query the button driver directly, the same way the ContentLister does.

Now, you can have a second program query the button driver simultaneously with the ContentLister. I've written such a program and it works beautifully. However, there's a small problem: if a button press is short enough (less than 1/10 second), it's possible for your program to catch the button push and the ContentLister to miss it (or vice versa). This is because querying the button data resets it, so if you push quick enough, one program will read the button data, and by the time the other program queries the driver, you've released the button and there's no data to get.

If anyone's interested in the gritty details of the button driver, ioctls, button handling, etc., I'd be happy to provide them. I have a short program that queries the iLiad buttons directly, as well as a reference of the hex code that each button returns. If you're interested, let me know!

Hope this helps!

thebohemian
10-07-2007, 05:36 AM
Hi. Thanks for all the information!!!

I would be very happy to receive any source code that show how /dev/buttons can be read. You can send it to: thebohemian (at) gmx.net

Regards
Robert

ldng
11-05-2007, 05:50 AM
Yes please, sample of both way would be very welcome.

I'm trying to catch "GDK" buttons in a pygtk program but it doesn't seems to get them :(

HET2
11-05-2007, 01:59 PM
I too would like to see your sources :)

jharker
11-05-2007, 02:53 PM
Okay, by popular demand, here's a simple command-line program to let you query the iLiad's hardware buttons directly!

7062 - This archive contains the source code, a precompiled binary, and a README with some notes on how it all works. The source code is distributed under the GNU GPL v3.

For those who are interested, here's the source code of the program for perusal and discussion:
/************************************************** *********
* ButtonReader-1.0.c
*
* This is a simple program to read button presses on the iRex iLiad.
* It may be run from the command line. When a button is pressed, it
* prints a line to stdout stating which button was pressed.
*
* This program is Copyright 2007 by John C. Harker, who may be reached
* via email at John.C.Harker <at> gmail.com.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Typically a copy of the GNU General Public License is located in the
* file named COPYING.
*
************************************************** *********/

#include <stdio.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <time.h>

#define SLEEPTIME_NSEC 100000000

int main(void)
{
unsigned int data;
int i,j;
int fd_buttons;
int loop = 1;

struct timespec sleeptime;
sleeptime.tv_sec = (time_t) 0;
sleeptime.tv_nsec = SLEEPTIME_NSEC;

fd_buttons = open( "/dev/buttons", O_RDWR );
if ( fd_buttons < 0 )
{
printf("Could not open /dev/buttons.\n");
exit(1);
}

while ( loop == 1 )
{
nanosleep(&sleeptime, NULL);

// Clear the data variable
data = 0;

// Request any data
ioctl(fd_buttons, 0x80046207, &data);

// Print out the data
switch( data )
{
case 0x00000800:
printf("iDS Connect");
break;
case 0x00000801:
printf("Options");
break;
case 0x00000802:
printf("Escape (level up)");
loop = 0;
break;
case 0x00000803:
printf("News");
break;
case 0x00000804:
printf("Books");
break;
case 0x00000805:
printf("Docs");
break;
case 0x00000806:
printf("Notes");
break;
case 0x00000807:
printf("Pagebar Left");
break;
case 0x00000808:
printf("Pagebar Right");
break;
case 0x00000809:
printf("Up Arrow");
break;
case 0x0000080a:
printf("Dot (Enter)");
break;
case 0x0000080b:
printf("Down Arrow");
break;
case 0x0000080e:
printf("Power");
break;
case 0x000008ff:
/* no button pressed */
break;
default:
printf("***Unknown code 0x%08x ***", data);
break;
}

if ( data != 0x000008ff )
{
printf(" button pressed!\n");
}

} /* end of button-reading do loop */

printf("Halted!\n");

close(fd_buttons);

return 0;
}

You can see that it's pretty straightforward ioctl polling. A similar approach is used to run the flashing light. Note that the presence of the stylus in its slot is not represented by a button signal, but the power button DOES generate a button signal. This means that if you kill the ContentLister, the iLiad will not shut down when you slide the power switch!

The ioctl polling method is somewhat inconvenient because it means that the program must be constantly polling in order to read button presses. If we could rewrite the actual kernel driver we might be able to change this... but figuring out how THAT works would be even harder.

Still, this is cool stuff. I hope someone finds it useful!

nekokami
11-07-2007, 12:40 PM
I was just thinking yesterday that I'd like to see IDS Connect reconfigured so that if you are in an application, rather than in ContentLister, it would cycle between open applications (and a task launching application).

Then I could be reading a PDF or something in FBReader and flipping over to a Notes page and back as needed.

ldng
11-08-2007, 05:20 AM
Many thanks for the sample. It's indeed easier than I thought. But how frequently do you need to poll /dev/buttons ? I guess I'll test that.

ldng
11-08-2007, 05:59 AM
Many thanks for the sample. It's indeed easier than I thought. But how frequently do you need to poll /dev/buttons ? I guess I'll test that.

:smack: read the source more carefully Luke :D