Beispiel #1
0
void joystick_linux::open_joystick(const char *p_path) {

	int joy_num = get_free_joy_slot();
	int fd = open(p_path, O_RDONLY | O_NONBLOCK);
	if (fd != -1 && joy_num != -1) {

		int rc = libevdev_new_from_fd(fd, &joysticks[joy_num].dev);
		if (rc < 0) {

			fprintf(stderr, "Failed to init libevdev (%s)\n", strerror(-rc));
			return;
		}

		libevdev *dev = joysticks[joy_num].dev;

		//check if the device supports basic gamepad events, prevents certain keyboards from
		//being detected as joysticks
		if (libevdev_has_event_type(dev, EV_ABS) && libevdev_has_event_type(dev, EV_KEY) &&
				(libevdev_has_event_code(dev, EV_KEY, BTN_A) || libevdev_has_event_code(dev, EV_KEY, BTN_THUMBL) || libevdev_has_event_code(dev, EV_KEY, BTN_TOP))) {

			char uid[128];
			String name = libevdev_get_name(dev);
			uint16_t bus = __bswap_16(libevdev_get_id_bustype(dev));
			uint16_t vendor = __bswap_16(libevdev_get_id_vendor(dev));
			uint16_t product = __bswap_16(libevdev_get_id_product(dev));
			uint16_t version = __bswap_16(libevdev_get_id_version(dev));

			joysticks[joy_num].reset();

			Joystick &joy = joysticks[joy_num];
			joy.fd = fd;
			joy.devpath = String(p_path);
			setup_joystick_properties(joy_num);
			sprintf(uid, "%04x%04x", bus, 0);
			if (vendor && product && version) {

				sprintf(uid + String(uid).length(), "%04x%04x%04x%04x%04x%04x", vendor,0,product,0,version,0);
				input->joy_connection_changed(joy_num, true, name, uid);
			}
			else {
				String uidname = uid;
				int uidlen = MIN(name.length(), 11);
				for (int i=0; i<uidlen; i++) {

					uidname = uidname + _hex_str(name[i]);
				}
				uidname += "00";
				input->joy_connection_changed(joy_num, true, name, uidname);

			}
		}
		else {
			//device is not a gamepad, clean up
			libevdev_free(dev);
			close(fd);
		}
	}
}
Beispiel #2
0
END_TEST

START_TEST(test_uinput_create_device_from_fd)
{
	struct libevdev *dev, *dev2;
	struct libevdev_uinput *uidev;
	int fd, fd2;
	unsigned int type, code;
	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_code(dev, EV_REL, REL_X, NULL);
	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);

	fd = open(UINPUT_NODE, O_RDWR);
	ck_assert_int_gt(fd, -1);

	rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
	ck_assert_int_eq(rc, 0);
	ck_assert(uidev != NULL);

	ck_assert_int_eq(libevdev_uinput_get_fd(uidev), fd);

	devnode = libevdev_uinput_get_devnode(uidev);
	ck_assert(devnode != NULL);

	fd2 = open(devnode, O_RDONLY);
	ck_assert_int_gt(fd2, -1);
	rc = libevdev_new_from_fd(fd2, &dev2);
	ck_assert_int_eq(rc, 0);

	for (type = 0; type < EV_CNT; type++) {
		int max = libevdev_event_type_get_max(type);
		if (max == -1)
			continue;

		for (code = 0; code < max; code++) {
			ck_assert_int_eq(libevdev_has_event_code(dev, type, code),
					 libevdev_has_event_code(dev2, type, code));
		}
	}

	libevdev_free(dev);
	libevdev_free(dev2);
	libevdev_uinput_destroy(uidev);
	close(fd);
	close(fd2);
}
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);
    }
Beispiel #4
0
evdevDevice::evdevDevice(const std::string& devnode) : m_devfile(devnode)
{
  // The device file will be read on one of the main threads, so we open in non-blocking mode.
  m_fd = open(devnode.c_str(), O_RDWR | O_NONBLOCK);
  int ret = libevdev_new_from_fd(m_fd, &m_dev);

  if (ret != 0)
  {
    // This useally fails because the device node isn't an evdev device, such as /dev/input/js0
    m_initialized = false;
    close(m_fd);
    return;
  }

  m_name = StripSpaces(libevdev_get_name(m_dev));

  // Controller buttons (and keyboard keys)
  int num_buttons = 0;
  for (int key = 0; key < KEY_MAX; key++)
    if (libevdev_has_event_code(m_dev, EV_KEY, key))
      AddInput(new Button(num_buttons++, key, m_dev));

  // Absolute axis (thumbsticks)
  int num_axis = 0;
  for (int axis = 0; axis < 0x100; axis++)
    if (libevdev_has_event_code(m_dev, EV_ABS, axis))
    {
      AddAnalogInputs(new Axis(num_axis, axis, false, m_dev),
                      new Axis(num_axis, axis, true, m_dev));
      num_axis++;
    }

  // Force feedback
  if (libevdev_has_event_code(m_dev, EV_FF, FF_PERIODIC))
  {
    for (auto type : {FF_SINE, FF_SQUARE, FF_TRIANGLE, FF_SAW_UP, FF_SAW_DOWN})
      if (libevdev_has_event_code(m_dev, EV_FF, type))
        AddOutput(new ForceFeedback(type, m_dev));
  }
  if (libevdev_has_event_code(m_dev, EV_FF, FF_RUMBLE))
  {
    AddOutput(new ForceFeedback(FF_RUMBLE, m_dev));
  }

  // TODO: Add leds as output devices

  m_initialized = true;
  m_interesting = num_axis >= 2 || num_buttons >= 8;
}
static inline void
tp_init_middlebutton_emulation(struct tp_dispatch *tp,
			       struct evdev_device *device)
{
	bool enable_by_default,
	     want_config_option;

	if (tp->buttons.is_clickpad)
		return;

	/* init middle button emulation on non-clickpads, but only if we
	 * don't have a middle button. Exception: ALPS touchpads don't know
	 * if they have a middle button, so we always want the option there
	 * and enabled by default.
	 */
	if (!libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE)) {
		enable_by_default = true;
		want_config_option = false;
	} else if (device->model == EVDEV_MODEL_ALPS_TOUCHPAD) {
		enable_by_default = true;
		want_config_option = true;
	} else
		return;

	evdev_init_middlebutton(tp->device,
				enable_by_default,
				want_config_option);
}
static void
set_resolution(struct libevdev *dev, int xres, int yres)
{
	struct input_absinfo abs;

	abs.resolution = xres;
	if (libevdev_has_event_code(dev, EV_ABS, ABS_X))
		set_abs(dev, OPT_RES, ABS_X, &abs);
	if (libevdev_has_event_code(dev, EV_ABS, ABS_MT_POSITION_X))
		set_abs(dev, OPT_RES, ABS_MT_POSITION_X, &abs);

	abs.resolution = yres;
	if (libevdev_has_event_code(dev, EV_ABS, ABS_Y))
		set_abs(dev, OPT_RES, ABS_Y, &abs);
	if (libevdev_has_event_code(dev, EV_ABS, ABS_MT_POSITION_Y))
		set_abs(dev, OPT_RES, ABS_MT_POSITION_Y, &abs);
}
int power_key_resume_handler_init(void)
{
	const char *node_path;
    char *full_path;
	GDir *input_dir;
	int rc = 1;
	struct libevdev *dev = NULL;

	input_dir = g_dir_open("/dev/input", 0, NULL);
	if (!input_dir) {
		g_warning("Failed to reach /dev/input directory");
		return -ENODEV;
	}

	while ((node_path = g_dir_read_name(input_dir)) != NULL) {
		full_path = g_strdup_printf("/dev/input/%s", node_path);

		if (g_file_test(node_path, G_FILE_TEST_IS_DIR))
			continue;

		input_source_fd = open(full_path, O_RDONLY|O_NONBLOCK);
		g_free(full_path);

		if (input_source_fd < 0)
			continue;

		rc = libevdev_new_from_fd(input_source_fd, &dev);
		if (rc < 0) {
			fprintf(stderr, "Failed to init libevdev (%s)\n", strerror(-rc));
			close(input_source_fd);
			input_source_fd = -1;
			continue;
		}

		if (libevdev_has_event_code(dev, EV_KEY, KEY_POWER)) {
			libevdev_free(dev);
			break;
		}

		libevdev_free(dev);
		close(input_source_fd);
		input_source_fd = -1;
	}

	if (input_source_fd < 0)
		return -ENODEV;

	channel = g_io_channel_unix_new(input_source_fd);
	g_io_channel_set_encoding(channel, NULL, NULL);
	readwatch = g_io_add_watch(channel, G_IO_IN | G_IO_HUP | G_IO_NVAL, _handle_input_event, NULL);

	return 0;
}
static void
set_led(struct libevdev *dev, unsigned int led, int led_state)
{
	int rc;
	enum libevdev_led_value state =
		led_state ? LIBEVDEV_LED_ON : LIBEVDEV_LED_OFF;

	if (!libevdev_has_event_code(dev, EV_LED, led)) {
		fprintf(stderr,
			"Device '%s' doesn't have %s\n",
			libevdev_get_name(dev),
			libevdev_event_code_get_name(EV_LED, led));
		return;
	}

	rc = libevdev_kernel_set_led_value(dev, led, state);
	if (rc != 0)
		fprintf(stderr,
			"Failed to set LED %s: %s",
			libevdev_event_code_get_name(EV_LED, led),
			strerror(-rc));
}
Beispiel #9
0
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;
}
Beispiel #10
0
static int is_multitouch_device(struct libevdev* evdev)
{
  return libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_X);
}
Beispiel #11
0
int main(int argc, char* argv[])
{
  const char* pname = argv[0];
  const char* devroot = "/dev/input";
  char* device = NULL;
  char* sockname = DEFAULT_SOCKET_NAME;
  char* stdin_file = NULL;
  int use_stdin = 0;

  int opt;
  while ((opt = getopt(argc, argv, "d:n:vif:h")) != -1) {
    switch (opt) {
      case 'd':
        device = optarg;
        break;
      case 'n':
        sockname = optarg;
        break;
      case 'v':
        g_verbose = 1;
        break;
      case 'i':
        use_stdin = 1;
        break;
      case 'f':
        stdin_file = optarg;
        break;
      case '?':
        usage(pname);
        return EXIT_FAILURE;
      case 'h':
        usage(pname);
        return EXIT_SUCCESS;
    }
  }

  internal_state_t state = {0};

  if (device != NULL)
  {
    if (!consider_device(device, &state))
    {
      fprintf(stderr, "%s is not a supported touch device\n", device);
      return EXIT_FAILURE;
    }
  }
  else
  {
    if (walk_devices(devroot, &state) != 0)
    {
      fprintf(stderr, "Unable to crawl %s for touch devices\n", devroot);
      return EXIT_FAILURE;
    }
  }

  if (state.evdev == NULL)
  {
    fprintf(stderr, "Unable to find a suitable touch device\n");
    return EXIT_FAILURE;
  }

  state.has_mtslot =
    libevdev_has_event_code(state.evdev, EV_ABS, ABS_MT_SLOT);
  state.has_tracking_id =
    libevdev_has_event_code(state.evdev, EV_ABS, ABS_MT_TRACKING_ID);
  state.has_key_btn_touch =
    libevdev_has_event_code(state.evdev, EV_KEY, BTN_TOUCH);
  state.has_touch_major =
    libevdev_has_event_code(state.evdev, EV_ABS, ABS_MT_TOUCH_MAJOR);
  state.has_width_major =
    libevdev_has_event_code(state.evdev, EV_ABS, ABS_MT_WIDTH_MAJOR);

  state.has_pressure =
    libevdev_has_event_code(state.evdev, EV_ABS, ABS_MT_PRESSURE);
  state.min_pressure = state.has_pressure ?
    libevdev_get_abs_minimum(state.evdev, ABS_MT_PRESSURE) : 0;
  state.max_pressure= state.has_pressure ?
    libevdev_get_abs_maximum(state.evdev, ABS_MT_PRESSURE) : 0;

  state.max_x = libevdev_get_abs_maximum(state.evdev, ABS_MT_POSITION_X);
  state.max_y = libevdev_get_abs_maximum(state.evdev, ABS_MT_POSITION_Y);

  state.max_tracking_id = state.has_tracking_id
    ? libevdev_get_abs_maximum(state.evdev, ABS_MT_TRACKING_ID)
    : INT_MAX;

  if (!state.has_mtslot && state.max_tracking_id == 0)
  {
    // The touch device reports incorrect values. There would be no point
    // in supporting ABS_MT_TRACKING_ID at all if the maximum value was 0
    // (i.e. one contact). This happens on Lenovo Yoga Tablet B6000-F,
    // which actually seems to support ~10 contacts. So, we'll just go with
    // as many as we can and hope that the system will ignore extra contacts.
    state.max_tracking_id = MAX_SUPPORTED_CONTACTS - 1;
    fprintf(stderr,
      "Note: type A device reports a max value of 0 for ABS_MT_TRACKING_ID. "
      "This means that the device is most likely reporting incorrect "
      "information. Guessing %d.\n",
      state.max_tracking_id
    );
  }

  state.max_contacts = state.has_mtslot
    ? libevdev_get_abs_maximum(state.evdev, ABS_MT_SLOT) + 1
    : (state.has_tracking_id ? state.max_tracking_id + 1 : 2);

  state.tracking_id = 0;

  int contact;
  for (contact = 0; contact < MAX_SUPPORTED_CONTACTS; ++contact)
  {
    state.contacts[contact].enabled = 0;
  }

  fprintf(stderr,
    "%s touch device %s (%dx%d with %d contacts) detected on %s (score %d)\n",
    state.has_mtslot ? "Type B" : "Type A",
    libevdev_get_name(state.evdev),
    state.max_x, state.max_y, state.max_contacts,
    state.path, state.score
  );

  if (state.max_contacts > MAX_SUPPORTED_CONTACTS) {
    fprintf(stderr, "Note: hard-limiting maximum number of contacts to %d\n",
      MAX_SUPPORTED_CONTACTS);
    state.max_contacts = MAX_SUPPORTED_CONTACTS;
  }

  FILE* input;
  FILE* output;

  if (use_stdin || stdin_file != NULL)
  {
    if (stdin_file != NULL)
    {
      // Reading from a file
      input = fopen(stdin_file, "r");
      if (NULL == input)
      {
        fprintf(stderr, "Unable to open '%s': %s\n",
                stdin_file, strerror(errno));
        exit(EXIT_FAILURE);
      }
      else
      {
        fprintf(stderr, "Reading commands from '%s'\n",
                stdin_file);
      }
    }
    else
    {
      // Reading from terminal
      input = stdin;
      fprintf(stderr, "Reading from STDIN\n");
    }

    output = stderr;
    io_handler(input, output, &state);
    fclose(input);
    fclose(output);
    exit(EXIT_SUCCESS);
  }

  struct sockaddr_un client_addr;
  socklen_t client_addr_length = sizeof(client_addr);

  int server_fd = start_server(sockname);

  if (server_fd < 0)
  {
    fprintf(stderr, "Unable to start server on %s\n", sockname);
    return EXIT_FAILURE;
  }

  while (1)
  {
    int client_fd = accept(server_fd, (struct sockaddr *) &client_addr,
      &client_addr_length);

    if (client_fd < 0)
    {
      perror("accepting client");
      exit(1);
    }

    fprintf(stderr, "Connection established\n");

    input = fdopen(client_fd, "r");
    if (input == NULL)
    {
      fprintf(stderr, "%s: fdopen(client_fd,'r')\n", strerror(errno));
      exit(1);
    }

    output = fdopen(dup(client_fd), "w");
    if (output == NULL)
    {
      fprintf(stderr, "%s: fdopen(client_fd,'w')\n", strerror(errno));
      exit(1);
    }

    io_handler(input, output, &state);

    fprintf(stderr, "Connection closed\n");
    fclose(input);
    fclose(output);
    close(client_fd);
  }

  close(server_fd);

  libevdev_free(state.evdev);
  close(state.fd);

  return EXIT_SUCCESS;
}