Android virtual button report

overview

This article mainly describes the virtual keys menu , home , return  that may be used on the touch screen , the implementation of the underlying drivers and related implementation principles, and the connection with the upper layer is only an overview.

two implementations

 There are two methods for sending touch keys: one is the virtualkey's architecture method provided by android , and the other is the method of directly reporting key events .

report keyevent method

Add the supported key types in the driver and report the supported event types

__set_bit(EV_SYN, input_dev->evbit); //synchronous event

__set_bit(EV_KEY, input_dev->evbit); //Key event

Report supported keystrokes

__set_bit(KEY_HOME, input_dev->keybit); // home button

__set_bit(KEY_BACK, input_dev->keybit);  // back按键

__set_bit(KEY_MENU, input_dev->keybit); // menu button

The coordinates corresponding to the three keys on the touch screen

(KEY_BACK) 120:1400

(KEY_HOME) 360:1400

(KEY_MENU) 500:1400

The reporting method of keyevent is very simple, as long as the corresponding key is reported and the device is synchronized in sync.

static void ft5x0x_report_value(struct ft5x0x_ts_data *data)
{
	struct ts_event *event = &data->event;
	int i;
	for (i = 0; i < event->touch_point; i++)
	{
		if (event->au16_y[i]==1400)
		{
			if(event->au8_touch_event[i]== 0 || event->au8_touch_event[i] == 2)
			{
				switch(event->au16_x[i])
				{
				case 120:
					input_report_key(data->input_dev, KEY_BACK, 1);
					break;
				case 360: 
					input_report_key(data->input_dev, KEY_HOME, 1);
					break;
				case 500: 
					input_report_key(data->input_dev, KEY_MENU, 1);
					break;	
				default: break;
				}
			}
			else
			{
				switch(event->au16_x[i])
				{
				case 120:
					input_report_key(data->input_dev, KEY_BACK, 0);
					break;
				case 360: 
					input_report_key(data->input_dev, KEY_HOME, 0);
					break;
				case 500: 
					input_report_key(data->input_dev, KEY_MENU, 0);
					break;	
				default: break;
				}
			}
			input_sync(data->input_dev);
			return;
		}
}

       First look at the outermost for loop, it can be seen that the number of reports is the number of points detected by the touch screen, and of course it will not exceed the maximum number of points supported by the touch screen. And every time the report is completed, a synchronization event input_sync() will be sent to indicate the end of the report at this time.

       The if (event->au16_y[i]==1400) inside is judging the y-axis coordinates of the touch point. Generally speaking, the positions of the virtual buttons are all in a row, so there must be an axis with the same coordinates. Here it is obvious that the y-axis coordinates of the three virtual buttons are the same.

       This judgment if(event->au8_touch_event[i]== 0 || event->au8_touch_event[i] == 2) According to the code logic before and after, it should be to judge whether the button is pressed or lifted. If it is pressed, then enter the switch branch, judge the coordinates of another x-axis, and report different keys KEY_BACK, KEY_HOME, KEY_MENU. This is the report when the button is pressed, input_report_key(data->input_dev, KEY_BACK, 1);. If the button is lifted, it will report input_report_key(data->input_dev, KEY_BACK, 0), there is only the last parameter in this function 1, 0 indicates whether the button is pressed or lifted. But whether it is pressed or lifted, the input_sync() synchronization event will be sent to indicate the end of the report.

Virtualkeys method

     virtualkeys is the framework provided by android, which is easy to use and is recommended for everyone to use. Take the frequently used ft5x06 touch screen as an example:

#ifdef CONFIG_XXX_RMI4_VIRTUAL_KEY_SUPPORT
struct kobject *d10a_rmi4_virtual_key_properties_kobj;

static ssize_t d10a_rmi4_virtual_keys_register(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{	
       return snprintf(buf, 200,
	   	__stringify(EV_KEY) ":" __stringify(KEY_MENU)  ":101:1343:120:96" \
         ":" __stringify(EV_KEY) ":" __stringify(KEY_HOMEPAGE)  ":360:1343:150:96" \
         ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK)  ":618:1343:120:96" "\n");
}

static struct kobj_attribute d10a_rmi4_virtual_keys_attr = {
       .attr = {
               .name = "virtualkeys.synaptics_rmi4_i2c",
               .mode = S_IRUGO,
       },
       .show = &d10a_rmi4_virtual_keys_register,
};

#ifdef D10A_SUPPORT_KEY_VIRTUAL_EXCHANGE
static ssize_t synaptics_virtual_exchange_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{	
   return sprintf(buf, "%d\n", synaptics_key_exchange_enable);
}

static ssize_t synaptics_virtual_exchange_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n)
{
	int virtual_exchange;
	
	if (sscanf(buf, "%d", &virtual_exchange) == 1) {
		pr_err(KERN_ERR "%s: set virtual_exchange= %d \n", __func__, virtual_exchange);		
		synaptics_key_exchange_enable = !!virtual_exchange;
		
		pr_err(KERN_ERR "%s: set synaptics_key_exchange_enable= %d \n", __func__,        synaptics_key_exchange_enable);		

		return n;
	}
	
	return -EINVAL;
}

static struct kobj_attribute d10a_rmi4_key_virtual_exchange_attr = {
	.attr = {
		.name = "virtual_exchange",
		.mode = 	S_IRUGO,
	},
	.show = &synaptics_virtual_exchange_show,
	.store = &synaptics_virtual_exchange_store,	
};
#endif

static struct attribute *d10a_rmi4_virtual_key_properties_attrs[] = {
       &d10a_rmi4_virtual_keys_attr.attr,
#ifdef D10A_SUPPORT_KEY_VIRTUAL_EXCHANGE
	&d10a_rmi4_key_virtual_exchange_attr.attr,
#endif
       NULL,
};

static struct attribute_group d10a_rmi4_virtual_key_properties_attr_group = {
       .attrs = d10a_rmi4_virtual_key_properties_attrs,
};
#endif
	if (d10a_rmi_virtual_key_support) {
		printk("linxc:  synaptics virtual_key_support =%d\n", 
                d10a_rmi_virtual_key_support);

		d10a_rmi4_virtual_key_properties_kobj = 
				kobject_create_and_add("board_properties", NULL);

		if (d10a_rmi4_virtual_key_properties_kobj) 
			retval = sysfs_create_group(d10a_rmi4_virtual_key_properties_kobj, 
			       &d10a_rmi4_virtual_key_properties_attr_group);

		if( !d10a_rmi4_virtual_key_properties_kobj ||retval)
		  	printk("failed to create synaptics d10a board_properties\n");
	}

The realization principle of the virtualkeys method

virtualkey is implemented based on the sysfs file system. If the upper layer wants to access virtualkey, it must implement such a file node under sys:

/sys/board_properties/virtualkeys.{deviceName}

Why the implementation of virtualkey must be based on the sysfs file node, this is determined by the call of the upper layer.

In the frameworks layer, the InputManger.java function defines how the upper layer accesses the virtualkey.

public VirtualKeyDefinition[] getVirtualKeyDefinitions(String deviceName) {
            ArrayList<VirtualKeyDefinition> keys = new ArrayList<VirtualKeyDefinition>();
            try {
                FileInputStream fis = new FileInputStream(
                        "/sys/board_properties/virtualkeys." + deviceName);
    ...
                }
    ...
}

Therefore, there are 2 functions to implement the sys file node

int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr);

int sysfs_create_group(struct kobject *kobj,const struct attribute_group *grp)

Here we are using

int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp);

       Because this function is in the directory corresponding to kobject, you can also create a subdirectory: virtualkeys.{deviceName}, the Linux kernel uses attribute_group to implement the subdirectory.

As shown in the figure, there is a file node like sys/board_properties/virtualkey_synaptics_rmi4_i2c

      A kobject corresponds to a directory in sysfs, and the files under the directory are realized by sysfs_ops and attribute. Among them, attribute defines the attribute of kobject, corresponds to a file in sysfs, and sysfs_ops is used to define the method of reading and writing this file.  

static struct kobj_attribute d10a_rmi4_key_virtual_exchange_attr = {
	.attr = {
		.name = "virtual_exchange",
		.mode = 	S_IRUGO,
	},
	.show = &synaptics_virtual_exchange_show,
	.store = &synaptics_virtual_exchange_store,	
};

Based on this understanding, the board_properties directory is defined as kobject:

struct kobject *properties_kobj;
    
properties_kobj = kobject_create_and_add("board_properties", NULL);

    That's it for the sys/board_properties directory.

   Because the files in the directory are realized by sysfs_ops and attribute, the file virtualkeys.{deviceName} in the directory will be defined as attribute, so how to define the fops of attribute?

     fops defines the operation function for the attribute whose name is "virtualkeys.{deviceName}". In the definition of the kernel, the fops of the attribute is the show/store function corresponding to each attribute.

The kernel defines a kobj_attribute structure.

struct kobj_attribute {
    struct attribute attr;
    ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
            char *buf);
    ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
             const char *buf, size_t count);
};

        In this way, each attribute will have its own show/store function, which greatly improves flexibility. However, sysfs reads and writes attributes through kobj_type->sysfs_ops in kobject, so if you want to use show/store in kobj_attribute to read and write attributes, you must specify it in kobj_type->sysfs_ops.

       kobj_attribute is a more flexible way of processing attributes provided by the kernel. It is convenient to use kobj_attribute only when we use kobject_create to create kobject.

    Each virtual key has six parameters:

0x01: A version code. Must always be 0x01.
<Linux key code>: The Linux key code of the virtual key.
<centerX>: The X pixel coordinate of the center of the virtual key.
<centerY>: The Y pixel coordinate of the center of the virtual key.
<width>: The width of the virtual key in pixels.
<height>: The height of the virtual key in pixels.
#define FT5X0X_KEY_HOME    102
#define FT5X0X_KEY_MENU    139
#define FT5X0X_KEY_BACK    158
#define FT5X0X_KEY_SEARCH  217 //定义key code
    __stringify(EV_KEY) ":" __stringify(FT5X0X_KEY_HOME) ":0:849:120:40"
     ":" __stringify(EV_KEY) ":" __stringify(FT5X0X_KEY_MENU) ":160:849:120:40"
     ":" __stringify(EV_KEY) ":" __stringify(FT5X0X_KEY_BACK) ":300:849:120:40"
     ":" __stringify(EV_KEY) ":" __stringify(FT5X0X_KEY_SEARCH) ":450:849:120:40" //定义X  Y,width,heigh

      Next, configure the /system/usr/keylayout .kl file and the .kcm file. If not specified, Android will automatically select the qwerty.kl and qwerty.kcm files in the default \android\sdk\emulator\keymaps\ directory.

         This is to use the default qwerty.kl mapping table of the android system.

        If you need to create the "driver name.kl" file by yourself, you can create it yourself according to the style of the qwerty.kl file, and put the "driver name.kl" file in the /system/usr/keylayout directory in the android file system.

        If you want to compile "driver name.kl" into the file system during the android source code compilation process, you only need to place the file in the android source code/vender/sec/sec_proprietary/utc100/keychars directory, and modify the Android .mk files.

        How the Android system handles the underlying buttons

        The processing of Android buttons is the responsibility of Window Manager. The main key-value mapping conversion implementation is in the android source code frameworks/base/libs/ui/EventHub.cpp This file handles all input events from the bottom layer and classifies events according to their sources deal with,

        The key event processing process is as follows:

a) Record the driver name

b) Get the environment and change ANDROID_ROOT to the system path (the default is /system, in the android source code system/core/rootdir/init.rc file)

c) Find the key mapping file whose path is "system/usr/keylayout/ft5x0x_ts.kl", if the file ("ft5x0x_ts.kl") does not exist, the default path is "system path/usr/keylayout/qwerty.kl " key-value mapping table in the file.

        In this way, the underlying driver of virtualkey is realized. At the same time, based on this driver, when pressing 4 virtual keys, if the motor is implemented on the hardware, and the upper layer has the key vibration function, there will be vibration.

Touch screen attribute configuration related files

        idc file, used to configure some properties of the touch screen. The system and data directories mentioned below are all under this path

Path: out\target\product\XX\

The access sequence of the directory where the file is located:

        First, go to the ANDROID_ROOT/usr/idc directory to find the file with the corresponding name and return the complete path name. If you can’t find it, go to the ANDROID_DATA/system/devices/idc to find it. Here ANDROID_ROOT generally refers to the /system directory, and ANDROID_DATA generally refers to /data directory.

        The file name lookup order is first Vendor_XXXX_Product_XXXX_Version_XXXX.idc, then Vendor_XXXX_Product_XXXX.idc and finally DEVICE_NAME.idc.

        In summary, Android opens configuration files for input devices and will access them in turn.

/system/usr/idc/Vendor_XXXX_Product_XXXX_Version_XXXX.idc

/system/usr/idc/Vendor_XXXX_Product_XXXX.idc

/system/usr/idc/DEVICE_NAME.idc

/data/system/devices/idc/Vendor_XXXX_Product_XXXX_Version_XXXX.idc

/data/system/devices/idc/Vendor_XXXX_Product_XXXX.idc

/data/system/devices/idc/DEVICE_NAME.idc

Text content:

touch.deviceType = touchScreen
touch.orientationAware = 1

keyboard.layout = qwerty
keyboard.characterMap = qwerty
keyboard.orientationAware = 1
keyboard.builtIn = 1

cursor.mode = navigation
cursor.orientationAware = 1

key layout file

        The key layout file is a key mapping file at the android level. Through this file, the user can redefine the key functions sent by the kernel. That is to say, the kernel sends up a home button, and you can map it to a back button or something else here. Under normal circumstances, this file will not be modified, so the default configuration file can be used.

Text content:

key 158    BACK

key 139    MENU

key 172    HOME

key 217    SEARCH

This file access sequence:

/system/usr/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl
/system/usr/keylayout/Vendor_XXXX_Product_XXXX.kl
/system/usr/keylayout/DEVICE_NAME.kl
/data/system/devices/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl
/data/system/devices/keylayout/Vendor_XXXX_Product_XXXX.kl
/data/system/devices/keylayout/DEVICE_NAME.kl
/system/usr/keylayout/Generic.kl
/data/system/devices/keylayout/Generic.kl

characterMap file

      The characterMap file is a character mapping file at the android level. For example, if you press an 'e' key, it usually represents 'e', ​​shift+'e' represents 'E', casplk+'e' represents 'E', alt+'e' It may mean something else. This configuration file is for these mappings. Under normal circumstances, this file does not need to be modified. Just use the default.

    Text content:

key A {
    label:                              'A'
    base:                               'a'
    shift, capslock:                    'A'
}

File access path:

/system/usr/keychars/Vendor_XXXX_Product_XXXX_Version_XXXX.kcm
/system/usr/keychars/Vendor_XXXX_Product_XXXX.kcm
/system/usr/keychars/DEVICE_NAME.kcm
/data/system/devices/keychars/Vendor_XXXX_Product_XXXX_Version_XXXX.kcm
/data/system/devices/keychars/Vendor_XXXX_Product_XXXX.kcm
/data/system/devices/keychars/DEVICE_NAME.kcm
/system/usr/keychars/Generic.kcm
/data/system/devices/keychars/Generic.kcm
/system/usr/keychars/Virtual.kcm
/data/system/devices/keychars/Virtual.kcm

Guess you like

Origin blog.csdn.net/FANG_YISHAO/article/details/120666318