Getting Started with Embedded Linux - Input System Application Programming (Mouse, Keyboard, Touch Screen)

Table of contents

1. Input system

1.1 Basic concepts

1.2 Get input device information

1.3 Input system framework

2. Input system programming

2.1 Determine the corresponding relationship

2.2 Writing code steps

 3. Programming on the development board


It is better to learn with questions. For example, under the Linux system, how do we write a program to obtain the position of the mouse? Which key on the keyboard was pressed? Where on the touch screen was touched?

Anyone who has studied single-chip microcomputers knows that these are essentially signals that are parsed by the driver, but we are talking about application programming, that is to say, we can directly obtain what we need from the driver.

Then a set of standardized interfaces is necessary , otherwise everyone writes differently. To make an application, you have to read the driver source code, which is outrageous.

Embedded Linux Getting Started Complete Tutorial: Embedded Linux Tutorial - Bare Metal, Application, Driver Complete Tutorial Directory

1. Input system

1.1 Basic concepts

Common input devices include keyboard, mouse, touch screen, Bluetooth, etc., through which users exchange data with the Linux system.

In order to uniformly manage these input devices, the Linux system implements a framework compatible with all input devices: the input system. Driver developers develop programs based on this framework, and application developers can use a unified API to use the device.

1.2 Get input device information

Determine the device information: the device node name of the input device is /dev/input/eventX (it may also be /dev/eventX, X represents numbers such as 0, 1, 2, etc.). To view device nodes, you can execute the following command:

ls /dev/input

If it is a development board, there may not be an input folder, it is directly under /dev.

How do you know what hardware these device nodes correspond to ? The following commands can be executed:

cat /proc/bus/input/devices

This instruction can obtain the relevant device information corresponding to the event:

I:id of the device(设备 ID)

N: name of the device device name

P: physical path to the device in the system hierarchy The physical path of the device in the system hierarchy.

S:sysfs path is located in the path of the sys file system

U: unique identification code for the device (if device has it) unique identification code of the device

H: list of input handles associated with the device. A list of input handles associated with the device.

B: bitmaps (bitmap)

It is worth noting that the B bitmap, such as "B: EV=b" in the above figure, is used to indicate which type of input event the device supports. The binary value of b is 1011, and bit0, 1, and 3 are 1, indicating that the device supports three types of events of 0, 1, and 3, namely EV_SYN, EV_KEY, and EV_ABS.

To give another example, how to understand "B: ABS=2658000 3"?

It indicates which events of the class EV_ABS are supported by the device. These are two 32-bit numbers: 0x2658000, 0x3, with the high bit first and the lower bit behind, to form a 64-bit number: "0x2658000,00000003", the bits with value 1 are: 0, 1, 47, 48, 50, 53, 54, namely: 0, 1, 0x2f, 0x30, 0x32, 0x35, 0x36, corresponding to the following macros: the

kernel version is lower under /usr/include/linux/input.h.

 

1.3 Input system framework

Take the button as an example: button press –> input system driver layer –> input system core layer –> input system event layer –> user space

​ From the perspective of application software programming, we only need to pay attention to what events are obtained after the user space gets the key press. For example, I want to know whether the key I am currently pressing is a short press or a long press? Or I want to know whether I am currently pressing the space bar or the enter key on the keyboard, etc.

In the input subsystem, the occurrence of each event uses event (type) -> sub-event (code) -> value (value). The main device number of all input devices is 13, and input-core uses the secondary device to Input devices are classified, such as 0-31 is a joystick, 32-63 is a mouse (corresponding to Mouse Handler), 64-95 is an event device (such as a touch screen, corresponding to Event Handler).

Source code in input.h:

struct input_event {
	struct timeval time;
	__u16 type;
	__u16 code;
	__s32 value;
};

timeval means "how much time has elapsed since the system started", it is a structure, containing "tv_sec, tv_usec" two items (ie seconds, microseconds).
 

Event types supported by the Linux input subsystem

event type coding meaning
EV_SYN 0x00 synchronous event
EV_KEY 0x01 Key events (mouse, keyboard, etc.)
EV_REL 0x02 Relative coordinates (e.g. mouse movement, reporting offset from last position)
EV_ABS 0x03 Absolute coordinates (such as: touch screen or joystick, report absolute coordinate position)
EV_MSC 0x04 other
EV_SW 0x05 switch
EV_LED 0x11 Button/device light
EV_SND 0x12 sound/alarm
EV_REP 0x14 repeat
EV_FF 0x15 force feedback
EV_PWR 0x16 power supply
EV_FF_STATUS 0x17 force feedback state
EV_MAX 0x1f Maximum number of event types and bitmask support

After the driver finishes reporting a series of data, it will report a "synchronous event", indicating that the data reporting is completed. When the APP reads the "synchronization event", it knows that it has finished reading the current data. The synchronous event is also an input_event structure, and its type, code, and value are all 0.

2. Input system programming

2.1 Determine the corresponding relationship

Already know through the above, you can pass:

ls /dev/input

To view input device nodes, pass:

cat /proc/bus/input/devices

Check the corresponding hardware.

But it's still a bit vague, for example, there are several Mouse, which one is it? pass:

hexdump /dev/input/event2     //event3、event4

Let's test it. When testing event2, it is found that the data is continuously output when the mouse moves, indicating that it is event2.

2.2 Writing code steps

Step 1: Define a structure variable for an event. We need to use the event and need to get the event. A variable is definitely needed to describe the event in the program.

Step 2: Open the device node, everything in Linux is a file, so use the open function to open the input device node

The third step: read the event, read the data in the open input device node, and enter the event variable defined in our first step

Step 4: Use the acquired event information to complete the processing logic we wrote ourselves. Here we simply output the mouse position.

full code

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/input.h>

int main(void)
{
    //1、定义一个结构体变量用来描述input事件
    struct input_event event_mouse ;
    //2、打开input设备的事件节点  我的通用USB鼠标事件的节点是event2
    int fd    = -1 ;
	   fd = open("/dev/input/event2", O_RDONLY);
    if(-1 == fd)
    {
        printf("open mouse event fair!\n");
        return -1 ;
    }
    while(1)
    {
        //3、读事件
        read(fd, &event_mouse, sizeof(event_mouse));
		   if(EV_ABS == event_mouse.type)
		   {
            //code表示位移X或者Y,当判断是X时,打印X的位移value
			   //当判断是Y时,打印Y的位移value
            if(event_mouse.code == ABS_X)
            {
				   printf("event_mouse.code_X:%d\n", event_mouse.code);
                printf("event_mouse.value_X:%d\n", event_mouse.value);
            }
            else if(event_mouse.code == ABS_Y)
            {
                printf("event_mouse.code_Y:%d\n", event_mouse.code);
                printf("event_mouse.value_Y:%d\n", event_mouse.value);
            }
		}
    }
    close(fd);
    return 0 ;
}

 3. Programming on the development board

EV=b, B means that KEY and ABS events are supported, you can see that KEY=400 0 0 0 0 0 0 0 0 0 0 , that is, the 330th bit is 1, the hexadecimal is 0x14A, check the source code

#define BTN_TOUCH		0x14a

Indicates the BTN_TOUCH sub-event that supports the KEY event. ABS does the math by itself, so I don't need it.

There is only one input device, the touch screen, on my development board. Use the LCD display program under Linux in the previous article to change it casually.

Function: Press the touch screen to turn black, release, the screen turns white

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/input.h>

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <linux/fb.h>

static int fd_fb;
static struct fb_var_screeninfo var;	/* Current var */
static int screen_size;
static unsigned char *fb_base;
static unsigned int line_width;
static unsigned int pixel_width;
 
void lcd_put_pixel(int x, int y, unsigned int color)
//传入的 color 表示颜色,它的格式永远是 0x00RRGGBB,即 RGB888。
//当 LCD 是 16bpp 时,要把 color 变量中的 R、 G、 B 抽出来再合并成 RGB565 格式。
{
    unsigned char *pen_8 = fb_base+y*line_width+x*pixel_width;
    //计算(x,y)坐标上像素对应的 Framebuffer 地址。
 
    unsigned short *pen_16;
    unsigned int *pen_32;
    
    unsigned int red, green, blue;
    
    pen_16 = (unsigned short *)pen_8;
    pen_32 = (unsigned int *)pen_8;
 
    switch (var.bits_per_pixel)
    {
      //对于 8bpp, color 就不再表示 RBG 三原色了,这涉及调色板的概念, color 是调色板的值。
        case 8:
            {
                *pen_8 = color;
                break;
            }
        case 16:
            {
                 /* 565 */
                //先从 color 变量中把 R、 G、 B 抽出来。
                red = (color >> 16) & 0xff;
                green = (color >> 8) & 0xff;
                blue = (color >> 0) & 0xff;
                //把 red、 green、 blue 这三种 8 位颜色值,根据 RGB565 的格式,
                //只保留 red 中的高 5 位、 green 中的高 6 位、 blue 中的高 5 位,
                //组合成一个新的 16 位颜色值。
                color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
                //把新的 16 位颜色值写入 Framebuffer
                *pen_16 = color;
                break;
            }
        case 32:
            {
                //对于 32bpp,颜色格式跟 color 参数一致,可以直接写入Framebuffer
                *pen_32 = color;
                break;
            }
        default:
            {
                printf("can't surport %dbpp\n",var.bits_per_pixel);
                break;
            }
     }
}

int main(void)
{
    //1、定义一个结构体变量用来描述input事件
    struct input_event event_TouchScreen ;
    int fd    = -1 ;
	
	int i;
	fd_fb = open("/dev/fb0", O_RDWR);
	if (fd_fb < 0)
	{
		printf("can't open /dev/fb0\n");
		return -1;
	}	
	if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
	{
		printf("can't get var\n");
		return -1;
	}
	
	line_width = var.xres * var.bits_per_pixel / 8;
	pixel_width = var.bits_per_pixel / 8;
	screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
	
	fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
	if (fb_base == (unsigned char *)-1)
	{
		printf("can't mmap\n");
		return -1;
	}
	
    //2、打开input设备的事件节点	
	fd = open("/dev/event0", O_RDONLY);
    if(-1 == fd)
    {
        printf("open mouse event fair!\n");
        return -1 ;
    }
    while(1)
    {
        //3、读事件
        read(fd, &event_TouchScreen, sizeof(event_TouchScreen));
		   if(EV_KEY == event_TouchScreen.type)
		   {
            //code表示位移X或者Y,当判断是X时,打印X的位移value
			   //当判断是Y时,打印Y的位移value
            if(event_TouchScreen.code == BTN_TOUCH)
            {
				if(event_TouchScreen.value==0)
				/* 清屏: 全部设为白色 */
				memset(fb_base, 0xff, screen_size);
				else
				/* 清屏: 全部设为黑色 */
				memset(fb_base, 0x0, screen_size);
            }
            else;
		}
    }
    close(fd);
	close(fd_fb);
    return 0 ;
}

Complete, the complex logic can be written according to the needs. 

 

Guess you like

Origin blog.csdn.net/freestep96/article/details/126802108