Android virtual key reporting


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

Two implementation methods

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

Report keyevent method

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

__ set_ bit(EV_SYN, input_dev->evbit);   // Synchronization event

__ set_ bit(EV_KEY, input_dev->evbit);   // Key event

Report supported keys

__ set_ bit(KEY_home, input_dev->keybit);  // home key

__ set_ bit(KEY_back, input_dev->keybit);  // back button

__ set_ bit(KEY_menu, input_dev->keybit);   // menu key

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. Just report the corresponding key and synchronize sync with the device

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)
				case 120:
					input_report_key(data->input_dev, KEY_BACK, 1);
				case 360: 
					input_report_key(data->input_dev, KEY_HOME, 1);
				case 500: 
					input_report_key(data->input_dev, KEY_MENU, 1);
				default: break;
				case 120:
					input_report_key(data->input_dev, KEY_BACK, 0);
				case 360: 
					input_report_key(data->input_dev, KEY_HOME, 0);
				case 500: 
					input_report_key(data->input_dev, KEY_MENU, 0);
				default: break;

        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. Of course, it will not exceed the maximum number of points supported by the touch screen. And each time the report is completed, a synchronization event input will be sent_ Sync() to indicate that the reporting is over.

        If (event - > au16_y [i] = = 1400) is used to judge the y-axis coordinates of the touch point. Generally speaking, the positions of the virtual keys are in a row, so there must be one axis with the same coordinates. Obviously, the y-axis coordinates of the three virtual keys are the same.

        This judgment if (event - > au8_touch_event [i] = = 0 | event - > au8_touch_event [i] = = 2) should judge whether the key is pressed or lifted according to the code logic before and after. If yes, enter the switch branch, judge the coordinates of another x-axis, and report different key_ BACK,KEY_HOME,KEY_MENU. This is the report when pressing the key, input_ report_ key(data->input_dev, KEY_BACK, 1);. If the key is lifted, the input will be reported_ report_ Key (data - > input_dev, key_back, 0). In this function, only the last parameter 1 and 0 indicate whether the key is pressed or lifted. But the input will be sent whether it is pressed or lifted_ The sync() synchronization event indicates the end of this report.

Virtualkeys method

      Virtual keys is the architecture provided by android. It is simple and convenient to use. It is recommended to use. Take the frequently used ft5x06 touch screen as an example:

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,

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,	

static struct attribute *d10a_rmi4_virtual_key_properties_attrs[] = {

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

		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, 

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

Implementation principle of virtualkeys method

Virtualkey is implemented based on sysfs file system. To access the virtualkey, the upper layer must implement such a file node under sys:


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

In the framework layer, 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, to implement the sys file node, there are two functions

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

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

What we use here is

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}. In the Linux kernel, attribute is used_ Group to implement subdirectories

As shown in the figure, Sys / board exists_ properties/virtualkey_ synaptics_ rmi4_ File nodes such as I2C

      A kobject corresponds to a directory in sysfs, and the files in the directory are created by sysfs_ops and attribute, where attribute defines the attribute of kobject and corresponds to a file in sysfs, 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, board_ The properties directory is defined as kobject:

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

    In this way, Sys / board is implemented_ Properties directory

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

      fops is a function that defines the operation of an attribute with "virtualkeys.{deviceName}" as its name.   In the definition of kernel, fops of attribute is the show/store function corresponding to each attribute

The kernel defines a kobj_ The structure of attribute.

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 the flexibility. However, sysfs uses kobj in kobject_ type->sysfs_ OPS to read and write attributes. If you want to use kobj_ If you use show/store in the attribute to read and write the attribute, it must be in kobj_ type->sysfs_ Specified in ops.

       kobj_attribute is a more flexible way of handling attributes provided by the kernel. Only when we use kobject_create to create a kobject, use kobj_attribute is more convenient.

    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 / / define 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" //Define x, y, width, heigh t

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

          This uses the default qwerty.kl mapping table of android system.

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

        If you want to compile the "driver name. kl" into the file system during Android source code compilation, you only need to place the file in the Android source code / vender / sec / sec_ In the proprietary / utc100 / keychars directory, and modify the file in this directory.

        Processing method of underlying keys in Android system

        Window Manager is responsible for the processing of Android keys. The main key value mapping conversion is implemented in Android source code frameworks/base/libs/ui/EventHub.cpp. This file processes all input events from the bottom layer and classifies the events according to the source,

        For key events, the processing process is as follows:

a) Record driver name

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

c) Find the key mapping file with the path "system/usr/keylayout/ft5x0x_ts.kl". If the file ("ft5x0x_ts.kl") does not exist, the key value mapping table in the file with the path "system path / usr / keylayout / quality. KL" will be used by default.

        In this way, the underlying driver of virtualkey is implemented. At the same time, based on this drive, when four virtual keys are pressed, if the motor is realized in the hardware and the key vibration function is realized in the upper layer, vibration will be generated.

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\

Access order of the directory where the file is located:

        First, Android_ Go to the root / usr / IDC directory to find the file with the corresponding name and return the complete path name. If it cannot be found, it will be returned from Android_ Go to data / system / devices / IDC and find Android here_ Root generally refers to the / system directory, ANDROID_DATA generally refers to the / data directory.

        The search order of file names is vendor first_ XXXX_ Product_ XXXX_ Version_ Xxxx.idc, then Vendor_XXXX_Product_XXXX.idc ends with DEVICE_NAME.idc.

        To sum up, Android opens the configuration file for the input device and accesses it in turn.







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, users can redefine the key functions sent by the kernel. In other words, the kernel sends a home key, and you can map it here to a back key or something else. Generally, 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

Access order of this file:


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' may mean something else. This configuration file is used for these mappings. Generally, 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:


Tags: Linux Android

Posted on Fri, 08 Oct 2021 22:57:03 -0400 by scrap0346