Using the Input Subsystem, Part II

No matter how many buttons an input device has or how many kinds of events it can generate, you can now work with it from user space.
Determining the Device Capabilities and Features

For some applications, it might be enough to know the device identity, because this would allow you to handle any special cases depending on what device is being used. However, it doesn't scale well; consider a case where you want to enable scroll wheel handling only if the device has a scroll wheel. You really don't want to have to list the vendor and product information for every mouse with a scroll wheel in your code.

To avoid this problem, the event interface allows you to determine which features and capabilities are available for a particular device. The types of features supported by the event interface are:

  • EV_KEY: absolute binary results, such as keys and buttons.

  • EV_REL: relative results, such as the axes on a mouse.

  • EV_ABS: absolute integer results, such as the axes on a joystick or for a tablet.

  • EV_MSC: miscellaneous uses that didn't fit anywhere else.

  • EV_LED: LEDs and similar indications.

  • EV_SND: sound output, such as buzzers.

  • EV_REP: enables autorepeat of keys in the input core.

  • EV_FF: sends force-feedback effects to a device.

  • EV_FF_STATUS: device reporting of force-feedback effects back to the host.

  • EV_PWR: power management events.

These are only the types of features; a wide range of individual features can be found within each type. For example, the EV_REL feature type distinguishes between X, Y and Z axes and horizontal and vertical wheels. Similarly, the EV_KEY feature type includes literally hundreds of different keys and buttons.

The capabilities or features of each device can be determined through the event interface, using the EVIOCGBIT ioctl. This function allows you to determine the types of features supported by any particular device, for example, whether it has keys, buttons or neither. It further allows you to determine the specific features that are supported, for example, which keys or buttons are present.

The EVIOCGBIT ioctl takes four arguments. If we consider it as ioctl(fd, EVIOCGBIT(ev_type, max_bytes), bitfield), then the fd argument is an open file descriptor; ev_type is the type of features to return (with 0 as a special case, indicating the list of all feature types supported should be returned, rather than the list of particular features for that type); max_bytes shows the upper limit on how many bytes should be returned; and bitfield is a pointer to the memory area where the result should be copied. The return value is the number of bytes actually copied on success or a negative error code on failure.

Let's look at a couple of examples of the EVIOCGBIT ioctl call. The first example, Listing 7, shows how to determine the types of features present. It determines how much memory is required for the bit array using evtype_bitmask, based on the EV_MAX definition in <linux/input.h>. The ioctl is then submitted, and the event layer fills in the bit array. We then test each bit in the array and show where the bit was set, which indicates the device does have at least one of this type of feature. All devices support the EV_SYN feature type in 2.5; the input core sets this bit.

Listing 7. Determining Features with EVIOCGBIT

When run, with a keyboard as the target, the example in Listing 7 produces:

Supported event types:
  Event type 0x00  (Synchronization Events)
  Event type 0x01  (Keys or Buttons)
  Event type 0x11  (LEDs)
  Event type 0x14  (Repeat)

With a mouse as the target, the example produces:

Supported event types:
  Event type 0x00  (Synchronization Events)
  Event type 0x01  (Keys or Buttons)
  Event type 0x02  (Relative Axes)

Retrieving Input from (and to) the Device

Having determined what capabilities a particular device has, you know what types of events it will produce and what types of events you can send.

Retrieving events from a device requires a standard character device “read” function. Each time you read from the event device (e.g., /dev/input/event0), you will get a whole number of events, each consisting of a struct input_event.

Listing 8. Checking for Busy Spots

The example shown in Listing 8 does a busy loop on the open file descriptor, trying to read any events. It filters out any events that don't correspond to keys and then prints out the various fields in the input_event structure. Running this while typing on my keyboard produced:

Event: time 1033621164.003838, type 1, code 37, value 1
Event: time 1033621164.027829, type 1, code 38, value 0
Event: time 1033621164.139813, type 1, code 38, value 1
Event: time 1033621164.147807, type 1, code 37, value 0
Event: time 1033621164.259790, type 1, code 38, value 0
Event: time 1033621164.283772, type 1, code 36, value 1
Event: time 1033621164.419761, type 1, code 36, value 0
Event: time 1033621164.691710, type 1, code 14, value 1
Event: time 1033621164.795691, type 1, code 14, value 0

You get one event per key press and another per key release.

This read interface has all the normal characteristics of a character device, meaning you don't need to use a busy loop. You can simply wait until your program needs some input from the device and then perform the read call. In addition, if you are interested in the input from a number of devices, you can use the poll and select functions to wait on a number of open devices at the same time.

Sending information to the device is a process similar to receiving it, except you use the standard write function instead of read. It is important to remember that the data used in the write call has to be a struct input_event.

A simple example of writing data is shown in Listing 9. This example turns the Caps Lock LED on, waits 200 milliseconds and then turns the Caps Lock LED off. It then turns the Num Lock LED on, waits 200 milliseconds, and then turns the Num Lock LED off. The cycle then repeats (in an infinite busy loop), so you see alternate flashing of the two keyboard LEDs.

Listing 9. Sample Data Write Function

By now it should be fairly clear that you receive events only when something changes—a key is pressed or released, the mouse is moved and so on. For some applications, you need to be able to determine what the global state of the device is. For example, a program that manages keyboards may need to determine which LEDs are currently lit and which keys are currently depressed on the keyboard, even though some of the keys may have been depressed before the application started.

The EVIOCGKEY ioctl is used to determine the global key and button state for a device. An example is shown in Listing 10. This ioctl is similar to the EVIOCGBIT(...,EV_KEY,...) function in some ways; instead of setting a bit in the bit array for each key or button that the device can send, EVIOCGKEY sets a bit in the bit array for each key or button that is depressed.

Listing 10. Determining a Device's Global Key and Button State

The EVIOCGLED and EVIOCGSND functions are analogous to EVIOCGKEY, except that they return which LEDs are currently lit and sounds that are currently turned on, respectively. An example of how you would use EVIOCGLED is shown in Listing 11. Again, each bit is interpreted in the same way as the bits in the bit array are filled in by EVIOCGBIT.

Listing 11. Using EVIOCGLED

You can determine the repeat rate settings for a keyboard using the EVIOCGREP ioctl. An example is shown in Listing 12, with two elements to the array. The first element specifies the delay before the keyboard starts repeating, and the second element specifies the delay between subsequent repeats. So if you hold down a key, you'll get one character straight away, a second character rep[0] milliseconds later, a third character rep[1] milliseconds after the second character and another character every rep[1] milliseconds thereafter, until you release the key.

Listing 12. Checking the Repeat Rate Settings

You also can set the key repeat rate using EVIOCSREP. This uses the same two-element array that you'd use to get the settings, as shown in Listing 13; it sets the initial delay to 2.5 seconds and the repeat rate to 1 per second.

Listing 13. Setting the Repeat Rates

Some input drivers support variable mappings between the keys held down (which are interpreted by the keyboard scan and reported as scancodes) and the events sent to the input layer. You can determine what key is associated with each scancode using the EVIOCGKEYCODE ioctl. An example is shown in Listing 14, which loops over the first 100 scancodes. The value of the scancode (input to the function) is the first element in the integer array, and the resulting input event key number (keycode) is the second element in the array. You can also modify the mapping, using the EVIOCSKEYCODE ioctl. An example is shown in Listing 15; this ioctl maps my M key to always produce a letter N. Be aware that keycode ioctl functions may not work on every keyboard—that USB keyboard is an example of a driver that does not support variable mappings.

Listing 14. Looping over Scancodes

Listing 15. Mapping Keys

The EVIOCGABS function also provides state information. Instead of filling in a bit array that represents the global state of boolean values, however, it provides a struct input_absinfo (see Listing 16) for one absolute axis. If you want the global state for a device, you have to call the function for each axis present on the device. An example is shown in Listing 17. The elements in the array are signed 32-bit quantities, and you can safely treat them as equivalent to int32_t. The first element shows the current value of the axis, the second and third elements show the current limits of the axis, the fourth element shows the size of the “flat” section (if any) of the response and the last element shows the size of the error that may be present.

Listing 16. input_absinfo for an Absolute Axis

Listing 17. Checking Globabl State by Axis

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Full example source.

waeva I dont care's picture

I am making a full source code basic tutorial for copy pasting should be done in a few days I'll post the link. It will also include handling a joystick.
A forward note in the 2.6 version of kernel you need root permissions to open event# files. So you need to run under sudo or make a dev rule.

Best Way to Detect Hotplug from App

E Franz's picture

To Solusrex: I have the same issue. I see at
that the kernel should call /sbin/hotplug which calls device-specific scripts to handle the add or remove event. I'm going to try to instrument the associated script to somehow send a message to my app to notify it. You might try the same.
E Franz

Seriously, how hard is it to give useful code examples?

Bryan Ischo's picture

WHY would you not include the entire code fragment in each example? WHY are you obfuscating some parameter types? Example: you describe getting the unique identifier of a device using the EVIOCGUNIQ ioctl. But you reference a magical variable called 'uniq' the type of which you do not define anywhere. Exactly how is hiding this information supposed to be useful? Who edited this? Why are you trying to make my life more difficult? WTF?!?!

What is the best way to

Solusrex's picture

What is the best way to detect from an app that a USB input device was plugged/unplugged beside polling it using open() function?

Hello, you can write a small

Uwe's picture

Hello,

you can write a small app that is called from a udev rule.
(You have to add a small rule for this)

Inside of the app you can broadcast a small message on a local socket.

Every app that listens on this socket, receive this notification.

bye
Uwe

Retrieve Scan Infor

sfog's picture

Hi all...

I need to retrieve all data (position x,y) from the driver when i try to draw something on the pad tablet....

can anyone tell me how to get the ABS when i got event scan ??

bad code

Anonymous's picture

The author clearly does not understand the beauty of copy and paste. Each listing of code just will never compile because the variables are not defined. People have to pull their hair to figure it out.

HELP: Retrieving Input from a Device

Fatih Isler's picture

Hi All,

In one of my project, I need to retrieve events from keyboard in Linux environment. For doing that in my code firstly I opened /dev/input/event0 file and it was successfully opened. However, when I was trying to read something from that file. The read() function stuck and my program can't execute any further steps. Does anybody know why this kind of problem that I encounter and how can I solve this problem. Here is my code:

P.S: In order to execute program you need to be super user and then need to execute code. Otherwise, program will can give "File can not open" error.

#define FILE_PATH "/dev/input/event0"

int main()
{
	printf("Starting KeyEvent Module\n");

	//int file, version;
	size_t file;
	const char *str = FILE_PATH;

	printf("File Path: %s\n", str);

	if((file = open(str, O_RDWR)) < 0)
	{
		printf("ERROR:File can not open\n");
		exit(0);
	}

	struct input_event event[64];

        size_t reader;
        reader = read(file, &event, sizeof(struct input_event) * 64);

        printf("DO NOT COME HERE...\n");

	close(file);
	return 0;
}

change this : reader =

Anonymous's picture

change this :
reader = read(file, &event, sizeof(struct input_event) * 64);
to
reader = read(file, event, sizeof(struct input_event) * 64);

You need one more flag

FireHL's picture

change this:

if((file = open(str, O_RDWR)) < 0)

to

if((file = open(str, O_RDWR|O_NDELAY)) < 0)

and check manual by 'man 2 open'

nice to see, but how many users have figured how to get a joysti

jago25_98's picture

I for one can figure out how /etc/devfsd.conf needs to be edited to setup /dev/joysticks, or /dev/js* with nothing under /dev/input being created either.

linux/Doc*/devices says digital joysticks are char-15,128 while the help doc under makeconfig states char 13:0+ - /dev/input/jsX

neither of this help me much.

If there was documentation somewhere in the world about how to setup joysticks we could hopefully have more people using this code :)

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState