int tp_init_buttons(struct tp_dispatch *tp, struct evdev_device *device) { struct libinput *libinput = tp_libinput_context(tp); struct tp_touch *t; const struct input_absinfo *absinfo_x, *absinfo_y; tp->buttons.is_clickpad = libevdev_has_property(device->evdev, INPUT_PROP_BUTTONPAD); tp->buttons.has_topbuttons = libevdev_has_property(device->evdev, INPUT_PROP_TOPBUTTONPAD); if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) || libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) { if (tp->buttons.is_clickpad) log_bug_kernel(libinput, "%s: clickpad advertising right button\n", device->devname); } else if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_LEFT) && !tp->buttons.is_clickpad && libevdev_get_id_vendor(device->evdev) != VENDOR_ID_APPLE) { log_bug_kernel(libinput, "%s: non clickpad without right button?\n", device->devname); } absinfo_x = device->abs.absinfo_x; absinfo_y = device->abs.absinfo_y; /* pinned-finger motion threshold, see tp_unpin_finger. */ tp->buttons.motion_dist.x_scale_coeff = 1.0/absinfo_x->resolution; tp->buttons.motion_dist.y_scale_coeff = 1.0/absinfo_y->resolution; tp->buttons.config_method.get_methods = tp_button_config_click_get_methods; tp->buttons.config_method.set_method = tp_button_config_click_set_method; tp->buttons.config_method.get_method = tp_button_config_click_get_method; tp->buttons.config_method.get_default_method = tp_button_config_click_get_default_method; tp->device->base.config.click_method = &tp->buttons.config_method; tp->buttons.click_method = tp_click_get_default_method(tp); tp_switch_click_method(tp); tp_init_top_softbuttons(tp, device, 1.0); tp_init_middlebutton_emulation(tp, device); tp_for_each_touch(tp, t) { t->button.state = BUTTON_STATE_NONE; libinput_timer_init(&t->button.timer, tp_libinput_context(tp), tp_button_handle_timeout, t); }
END_TEST START_TEST(test_uinput_properties) { struct libevdev *dev, *dev2; struct libevdev_uinput *uidev; int fd; int rc; const char *devnode; dev = libevdev_new(); ck_assert(dev != NULL); libevdev_set_name(dev, TEST_DEVICE_NAME); libevdev_enable_event_type(dev, EV_SYN); libevdev_enable_event_type(dev, EV_REL); libevdev_enable_event_type(dev, EV_KEY); libevdev_enable_event_code(dev, EV_REL, REL_X, NULL); libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL); libevdev_enable_event_code(dev, EV_KEY, BTN_LEFT, NULL); libevdev_enable_property(dev, INPUT_PROP_BUTTONPAD); libevdev_enable_property(dev, INPUT_PROP_MAX); rc = libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uidev); ck_assert_int_eq(rc, 0); ck_assert(uidev != NULL); devnode = libevdev_uinput_get_devnode(uidev); ck_assert(devnode != NULL); fd = open(devnode, O_RDONLY); ck_assert_int_gt(fd, -1); rc = libevdev_new_from_fd(fd, &dev2); ck_assert_int_eq(rc, 0); ck_assert(libevdev_has_property(dev2, INPUT_PROP_BUTTONPAD)); ck_assert(libevdev_has_property(dev2, INPUT_PROP_MAX)); libevdev_free(dev); libevdev_free(dev2); libevdev_uinput_destroy(uidev); close(fd); }
static int consider_device(const char* devpath, internal_state_t* state) { int fd = -1; struct libevdev* evdev = NULL; if (!is_character_device(devpath)) { goto mismatch; } if ((fd = open(devpath, O_RDWR)) < 0) { perror("open"); fprintf(stderr, "Unable to open device %s for inspection", devpath); goto mismatch; } if (libevdev_new_from_fd(fd, &evdev) < 0) { fprintf(stderr, "Note: device %s is not supported by libevdev\n", devpath); goto mismatch; } if (!is_multitouch_device(evdev)) { goto mismatch; } int score = 10000; if (libevdev_has_event_code(evdev, EV_ABS, ABS_MT_TOOL_TYPE)) { int tool_min = libevdev_get_abs_minimum(evdev, ABS_MT_TOOL_TYPE); int tool_max = libevdev_get_abs_maximum(evdev, ABS_MT_TOOL_TYPE); if (tool_min > MT_TOOL_FINGER || tool_max < MT_TOOL_FINGER) { fprintf(stderr, "Note: device %s is a touch device, but doesn't" " support fingers\n", devpath); goto mismatch; } score -= tool_max - MT_TOOL_FINGER; } if (libevdev_has_event_code(evdev, EV_ABS, ABS_MT_SLOT)) { score += 1000; // Some devices, e.g. Blackberry PRIV (STV100) have more than one surface // you can touch. On the PRIV, the keypad also acts as a touch screen // that you can swipe and scroll with. The only differences between the // touch devices are that one is named "touch_display" and the other // "touch_keypad", the keypad only supports 3 contacts and the display // up to 9, and the keypad has a much lower resolution. Therefore // increasing the score by the number of contacts should be a relatively // safe bet, though we may also want to decrease the score by, say, 1, // if the device name contains "key" just in case they decide to start // supporting more contacts on both touch surfaces in the future. int num_slots = libevdev_get_abs_maximum(evdev, ABS_MT_SLOT); score += num_slots; } // For Blackberry devices, see above. const char* name = libevdev_get_name(evdev); if (strstr(name, "key") != NULL) { score -= 1; } // Alcatel OneTouch Idol 3 has an `input_mt_wrapper` device in addition // to direct input. It seems to be related to accessibility, as it shows // a touchpoint that you can move around, and then tap to activate whatever // is under the point. That wrapper device lacks the direct property. if (libevdev_has_property(evdev, INPUT_PROP_DIRECT)) { score += 10000; } // Some devices may have an additional screen. For example, Meizu Pro7 Plus // has a small screen on the back side of the device called sub_touch, while // the boring screen in the front is called main_touch. The resolution on // the sub_touch device is much much lower. It seems like a safe bet // to always prefer the larger device, as long as the score adjustment is // likely to be lower than the adjustment we do for INPUT_PROP_DIRECT. if (libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_X)) { int x = libevdev_get_abs_maximum(evdev, ABS_MT_POSITION_X); int y = libevdev_get_abs_maximum(evdev, ABS_MT_POSITION_Y); score += sqrt(x * y); } if (state->evdev != NULL) { if (state->score >= score) { fprintf(stderr, "Note: device %s was outscored by %s (%d >= %d)\n", devpath, state->path, state->score, score); goto mismatch; } else { fprintf(stderr, "Note: device %s was outscored by %s (%d >= %d)\n", state->path, devpath, score, state->score); } } libevdev_free(state->evdev); state->fd = fd; state->score = score; strncpy(state->path, devpath, sizeof(state->path)); state->evdev = evdev; return 1; mismatch: libevdev_free(evdev); if (fd >= 0) { close(fd); } return 0; }