Example #1
0
static void evdev_init_parms(struct input_device *dev, struct input_abs_parms *parms, int code) {
  parms->flat = libevdev_get_abs_flat(dev->dev, code);
  parms->min = libevdev_get_abs_minimum(dev->dev, code);
  parms->max = libevdev_get_abs_maximum(dev->dev, code);
  parms->avg = (parms->min+parms->max)/2;
  parms->range = parms->max - parms->avg;
  parms->diff = parms->max - parms->min;
}
Example #2
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;
}
Example #3
0
evdevDevice::Axis::Axis(u8 index, u16 code, bool upper, libevdev* dev)
    : m_code(code), m_index(index), m_upper(upper), m_dev(dev)
{
  m_min = libevdev_get_abs_minimum(m_dev, m_code);
  m_range = libevdev_get_abs_maximum(m_dev, m_code) - m_min;
}
Example #4
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;
}