Пример #1
0
static void process_report(int usb_number, struct usb_state * state, struct libusb_transfer * transfer)
{
  int i;
  for(i = 0; i < controller[state->type].endpoints.in.reports.nb; ++i)
  {
    unsigned char report_id = controller[state->type].endpoints.in.reports.elements[i].report_id;
    unsigned char report_length = controller[state->type].endpoints.in.reports.elements[i].report_length;
    if(transfer->buffer[0] == report_id)
    {
      if(transfer->actual_length == report_length)
      {
        if(state->type == C_TYPE_XONE_PAD && !adapter_get(usb_number)->status)
        {
          break;
        }

        s_report* current = (s_report*) transfer->buffer;
        s_report* previous = &state->reports[i].report.value;

        report2event(state->type, usb_number, (s_report*)current, (s_report*)previous, state->joystick_id);

        if(state->type == C_TYPE_DS4 || state->type == C_TYPE_T300RS_PS4 || state->type == C_TYPE_G29_PS4)
        {
          memcpy(&previous->ds4, &current->ds4, report_length); //s_report_ds4 is larger than report_length bytes!
        }
        else if(state->type == C_TYPE_360_PAD)
        {
          previous->x360 = current->x360;
        }
        else if(state->type == C_TYPE_XONE_PAD)
        {
          if(report_id == XONE_USB_HID_IN_REPORT_ID)
          {
            previous->xone.input = current->xone.input;
          }
          else if(report_id == XONE_USB_HID_IN_GUIDE_REPORT_ID)
          {
            previous->xone.guide = current->xone.guide;
          }
        }
      }
      else
      {
        fprintf(stderr, "incorrect report length on interrupt endpoint: received %d bytes, expected %d bytes\n", transfer->actual_length, report_length);
      }
      break;
    }
  }

  if(i == controller[state->type].endpoints.in.reports.nb)
  {
    if(state->type == C_TYPE_XONE_PAD && !adapter_get(usb_number)->status)
    {
      if(adapter_forward_interrupt_in(usb_number, transfer->buffer, transfer->actual_length) < 0)
      {
        fprintf(stderr, "can't forward interrupt data to the adapter\n");
      }
    }
  }
}
Пример #2
0
int usb_init(int usb_number, e_controller_type type)
{
  int ret = -1;
  int dev_i;

  struct usb_state* state = usb_states+usb_number;

  if(!controller[type].vendor || !controller[type].product)
  {
    gprintf(_("no pass-through device is needed\n"));
    return 0;
  }

  usb_state_indexes[usb_number] = usb_number;

  memset(state, 0x00, sizeof(*state));
  state->joystick_id = -1;
  state->type = type;
  state->ack = 1;

  if(!ctx)
  {
    ret = libusb_init(&ctx);
    if(ret != LIBUSB_SUCCESS)
    {
      fprintf(stderr, "libusb_init: %s.\n", libusb_strerror(ret));
      return -1;
    }
  }

  if(!devs)
  {
    cnt = libusb_get_device_list(ctx, &devs);
    if(cnt < 0)
    {
      fprintf(stderr, "libusb_get_device_list: %s.\n", libusb_strerror(cnt));
      return -1;
    }
  }

  for(dev_i=0; dev_i<cnt; ++dev_i)
  {
    struct libusb_device_descriptor desc;
    ret = libusb_get_device_descriptor(devs[dev_i], &desc);
    if(!ret)
    {
      if(desc.idVendor == controller[type].vendor && desc.idProduct == controller[type].product)
      {
        libusb_device_handle* devh;
        ret = libusb_open(devs[dev_i], &devh);
        if(ret != LIBUSB_SUCCESS)
        {
          fprintf(stderr, "libusb_open: %s.\n", libusb_strerror(ret));
          return -1;
        }
        else
        {
          ret = libusb_reset_device(devh);
          if(ret != LIBUSB_SUCCESS)
          {
            fprintf(stderr, "libusb_reset_device: %s.\n", libusb_strerror(ret));
            libusb_close(devh);
            return -1;
          }

#if defined(LIBUSB_API_VERSION) || defined(LIBUSBX_API_VERSION)
          libusb_set_auto_detach_kernel_driver(devh, 1);
#else
#ifndef WIN32
          ret = libusb_kernel_driver_active(devh, 0);
          if(ret == 1)
          {
            ret = libusb_detach_kernel_driver(devh, 0);
            if(ret != LIBUSB_SUCCESS)
            {
              fprintf(stderr, "libusb_detach_kernel_driver: %s.\n", libusb_strerror(ret));
              libusb_close(devh);
              return -1;
            }
          }
          else if(ret != LIBUSB_SUCCESS)
          {
            fprintf(stderr, "libusb_kernel_driver_active: %s.\n", libusb_strerror(ret));
            libusb_close(devh);
            return -1;
          }
#endif
#endif

          int config;

          ret = libusb_get_configuration(devh, &config);
          if(ret != LIBUSB_SUCCESS)
          {
            fprintf(stderr, "libusb_get_configuration: %s.\n", libusb_strerror(ret));
            libusb_close(devh);
            return -1;
          }

          if(config != controller[state->type].configuration)
          {
            ret = libusb_set_configuration(devh, controller[state->type].configuration);
            if(ret != LIBUSB_SUCCESS)
            {
              fprintf(stderr, "libusb_set_configuration: %s.\n", libusb_strerror(ret));
              libusb_close(devh);
              return -1;
            }
          }

          ret = libusb_claim_interface(devh, controller[state->type].interface);
          if(ret != LIBUSB_SUCCESS)
          {
            fprintf(stderr, "libusb_claim_interface: %s.\n", libusb_strerror(ret));
            libusb_close(devh);
          }
          else
          {
            state->devh = devh;
            ++nb_opened;

#ifndef WIN32
            const struct libusb_pollfd** pfd_usb = libusb_get_pollfds(ctx);

            int poll_i;
            for (poll_i=0; pfd_usb[poll_i] != NULL; ++poll_i)
            {
              GE_AddSource(pfd_usb[poll_i]->fd, usb_number, usb_handle_events, usb_handle_events, usb_close);
            }

            free(pfd_usb);
#endif

            if(state->type == C_TYPE_XONE_PAD && adapter_get(usb_number)->status)
            {
              //if the authentication was already performed, activate the controller

              //warning: make sure not to make any libusb async io before this!

              unsigned char activate[] = { 0x05, 0x20, 0x00, 0x01, 0x00 };
              usb_send_interrupt_out_sync(usb_number, activate, sizeof(activate));

              unsigned char activate_rumble[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00 };
              usb_send_interrupt_out_sync(usb_number, activate_rumble, sizeof(activate_rumble));
            }

            // register joystick
            state->joystick_id = GE_RegisterJoystick(controller[state->type].name, NULL);

            int i;
            for(i = 0; i < controller[state->type].endpoints.in.reports.nb; ++i)
            {
              usb_states[usb_number].reports[i].report_id = controller[state->type].endpoints.in.reports.elements[i].report_id;
            }

            return 0;
          }
        }
      }
    }
  }

  return -1;
}
Пример #3
0
void display_run(e_controller_type type, int axis[])
{
  int i;
  int d;
  char label[BUTTON_LENGTH];
  char rate[COLS];
  int tdiff;

  cpt++;

#ifndef WIN32
  gettimeofday(&t1, NULL);

  tdiff = (t1.tv_sec * 1000000 + t1.tv_usec) - (t0.tv_sec * 1000000 + t0.tv_usec);
#else
  QueryPerformanceCounter(&t1);

  tdiff = (t1.QuadPart - t0.QuadPart) * 1000000 / freq.QuadPart;
#endif

  if(tdiff > RATE_PERIOD)
  {
    cpt_total += cpt;
    sprintf(rate, _("Processing time: current=%dus average=%dus worst=%dus"), proc_time/cpt, proc_time_total/cpt_total, proc_time_worst);
    mvaddstr(LINES-2, 1, rate);
    clrtoeol();
    sprintf(rate, _("Refresh rate: %3dHz  "), cpt*1000000/RATE_PERIOD);
    mvaddstr(LINES-1, 1, rate);
    t0 = t1;
    cpt = 0;
    proc_time = 0;
  }

  d = 0;

  for(i=rel_axis_rstick_y+1; i<AXIS_MAX; ++i)
  {
    if(axis[i])
    {
      snprintf(label, sizeof(label), "%8s: %4d", control_get_name(type, i), axis[i]);
      mvwaddstr(wbuttons, 1 + d, 1, label);
      d++;
      if(d == BUTTON_Y_L - 3)
      {
        break;
      }
    }
  }
  memset(label, ' ', sizeof(label));
  label[sizeof(label)-1] = '\0';
  for(i=d; i<last_button_nb; ++i)
  {
    mvwaddstr(wbuttons, 1 + i, 1, label);
  }
  last_button_nb = d;
  wnoutrefresh(wbuttons);

  mvwaddch(lstick, cross[0][1], cross[0][0], ' ');
  cross[0][0] = STICK_X_L / 2 + (double)axis[rel_axis_lstick_x] / controller_get_max_signed(adapter_get(0)->type, rel_axis_lstick_x) * (STICK_X_L / 2 - 1);
  cross[0][1] = STICK_Y_L / 2 + (double)axis[rel_axis_lstick_y] / controller_get_max_signed(adapter_get(0)->type, rel_axis_lstick_y) * (STICK_Y_L / 2 - 1);
  if(cross[0][0] <= 0 || cross[0][0] >= STICK_X_L-1 || cross[0][1] <= 0 || cross[0][1] >= STICK_Y_L-1)
  {
    mvwaddch(lstick, cross[0][1], cross[0][0], CROSS_CHAR | COLOR_PAIR(3));
  }
  else
  {
    mvwaddch(lstick, cross[0][1], cross[0][0], CROSS_CHAR);
  }
  wnoutrefresh(lstick);

  mvwaddch(rstick, cross[1][1], cross[1][0], ' ');
  cross[1][0] = STICK_X_L / 2 + (double)axis[rel_axis_rstick_x] / controller_get_max_signed(adapter_get(0)->type, rel_axis_rstick_x) * (STICK_X_L / 2 - 1);
  cross[1][1] = STICK_Y_L / 2 + (double)axis[rel_axis_rstick_y] / controller_get_max_signed(adapter_get(0)->type, rel_axis_rstick_y) * (STICK_Y_L / 2 - 1);
  if(cross[1][0] <= 0 || cross[1][0] >= STICK_X_L-1 || cross[1][1] <= 0 || cross[1][1] >= STICK_Y_L-1)
  {
    mvwaddch(rstick, cross[1][1], cross[1][0], CROSS_CHAR | COLOR_PAIR(3));
  }
  else
  {
    mvwaddch(rstick, cross[1][1], cross[1][0], CROSS_CHAR);
  }
  wnoutrefresh(rstick);

  move(LINES-1, COLS-1);
  wnoutrefresh(stdscr);
  doupdate();
}
Пример #4
0
void display_run(e_controller_type type, int axis[])
{
  int i;
  int d;
  char label[BUTTON_LENGTH];
  char rate[COLS];

  int freq = stats_get_frequency(0);

  if(freq >= 0)
  {
    sprintf(rate, _("Refresh rate: %4dHz  "), freq);
    mvaddstr(LINES-1, 1, rate);
  }

  d = 0;

  for(i=rel_axis_rstick_y+1; i<AXIS_MAX; ++i)
  {
    if(axis[i])
    {
      snprintf(label, sizeof(label), "%8s: %4d", controller_get_axis_name(type, i), axis[i]);
      mvwaddstr(wbuttons, 1 + d, 1, label);
      d++;
      if(d == BUTTON_Y_L - 3)
      {
        break;
      }
    }
  }
  memset(label, ' ', sizeof(label));
  label[sizeof(label)-1] = '\0';
  for(i=d; i<last_button_nb; ++i)
  {
    mvwaddstr(wbuttons, 1 + i, 1, label);
  }
  last_button_nb = d;
  wnoutrefresh(wbuttons);

  mvwaddch(lstick, cross[0][1], cross[0][0], ' ');
  cross[0][0] = STICK_X_L / 2 + (double)axis[rel_axis_lstick_x] / controller_get_max_signed(adapter_get(0)->ctype, rel_axis_lstick_x) * (STICK_X_L / 2 - 1);
  cross[0][1] = STICK_Y_L / 2 + (double)axis[rel_axis_lstick_y] / controller_get_max_signed(adapter_get(0)->ctype, rel_axis_lstick_y) * (STICK_Y_L / 2 - 1);
  if(cross[0][0] <= 0 || cross[0][0] >= STICK_X_L-1 || cross[0][1] <= 0 || cross[0][1] >= STICK_Y_L-1)
  {
    mvwaddch(lstick, cross[0][1], cross[0][0], CROSS_CHAR | COLOR_PAIR(3));
  }
  else
  {
    mvwaddch(lstick, cross[0][1], cross[0][0], CROSS_CHAR);
  }
  wnoutrefresh(lstick);

  mvwaddch(rstick, cross[1][1], cross[1][0], ' ');
  cross[1][0] = STICK_X_L / 2 + (double)axis[rel_axis_rstick_x] / controller_get_max_signed(adapter_get(0)->ctype, rel_axis_rstick_x) * (STICK_X_L / 2 - 1);
  cross[1][1] = STICK_Y_L / 2 + (double)axis[rel_axis_rstick_y] / controller_get_max_signed(adapter_get(0)->ctype, rel_axis_rstick_y) * (STICK_Y_L / 2 - 1);
  if(cross[1][0] <= 0 || cross[1][0] >= STICK_X_L-1 || cross[1][1] <= 0 || cross[1][1] >= STICK_Y_L-1)
  {
    mvwaddch(rstick, cross[1][1], cross[1][0], CROSS_CHAR | COLOR_PAIR(3));
  }
  else
  {
    mvwaddch(rstick, cross[1][1], cross[1][0], CROSS_CHAR);
  }
  wnoutrefresh(rstick);

  move(LINES-1, COLS-1);
  wnoutrefresh(stdscr);
  doupdate();
}
Пример #5
0
static void translation_test()
{
  int dpi;
  int dz;
  double mul;
  double exp;

  GE_Event mouse_evt = { };

  s_mouse_cal* mc = cal_get_mouse(current_mouse, current_conf);

  if(!mc->dzx || !mc->mx || !mc->ex)
  {
    return;
  }

  dpi = mc->dpi;
  dz = *mc->dzx;
  mul = *mc->mx;
  exp = *mc->ex;

  if (dpi <= 0)
  {
    return;
  }

  e_controller_type ctype = adapter_get(cal_get_controller(current_mouse))->ctype;

  if(ctype == C_TYPE_NONE)
  {
    return;
  }

  if (dots <= 0)
  {
    dots = distance * dpi;
  }

  if(delay > 0)
  {
    delay--;
    return;
  }

  mouse_evt.motion.xrel = direction * step;
  mouse_evt.motion.which = current_mouse;
  mouse_evt.type = GE_MOUSEMOTION;
  process_event(&mouse_evt);

  dots -= step;

  if (dots <= 0)
  {
    delay = DURATION / gimx_params.refresh_period;
    step *= 2;
    direction *= -1;
    if (direction > 0)
    {
      if ((dz - mul + mul * pow(step * 2 * gimx_params.frequency_scale, exp)) * controller_get_axis_scale(ctype, rel_axis_2) > controller_get_mean_unsigned(ctype, rel_axis_2))
      {
        step = 1;
        distance = 0.1;
      }
      else
      {
        distance = distance * 3;
      }
    }
  }
}
Пример #6
0
/*
 * Use the mouse wheel to calibrate the mouse.
 */
void cal_button(int which, int button)
{
  double ratio;
  s_mouse_control* mc = cfg_get_mouse_control(current_mouse);
  s_mouse_cal* mcal = cal_get_mouse(current_mouse, current_conf);

  e_controller_type ctype = adapter_get(cal_get_controller(current_mouse))->ctype;

  if(ctype == C_TYPE_NONE)
  {
    return;
  }

  switch (button)
  {
    case GE_BTN_WHEELUP:
      switch (current_cal)
      {
        case MC:
          current_mouse += 1;
          if (!GE_MouseName(current_mouse))
          {
            current_mouse -= 1;
          }
          break;
        case CC:
          current_conf += 1;
          if (current_conf > MAX_CONFIGURATIONS - 1)
          {
            current_conf = MAX_CONFIGURATIONS - 1;
          }
          break;
        case MX:
          if (mcal->mx && mcal->my)
          {
            ratio = *mcal->my / *mcal->mx;
            *mcal->mx += DEFAULT_MULTIPLIER_STEP;
            *mcal->my = *mcal->mx * ratio;
          }
          break;
        case MY:
          if (mcal->mx && mcal->my)
          {
            ratio = *mcal->my / *mcal->mx;
            ratio += DEFAULT_MULTIPLIER_STEP;
            *mcal->my = *mcal->mx * ratio;
          }
          break;
        case DZX:
          if (mcal->dzx)
          {
            *mcal->dzx += 1;
            if (*mcal->dzx > controller_get_mean_unsigned(ctype, rel_axis_rstick_x) / controller_get_axis_scale(ctype, rel_axis_rstick_x))
            {
              *mcal->dzx = controller_get_mean_unsigned(ctype, rel_axis_rstick_x) / controller_get_axis_scale(ctype, rel_axis_rstick_x);
            }
            mc->merge_x[mc->index] = 1;
            mc->merge_y[mc->index] = 0;
            mc->change = 1;
          }
          break;
        case DZY:
          if (mcal->dzy)
          {
            *mcal->dzy += 1;
            if (*mcal->dzy > controller_get_mean_unsigned(ctype, rel_axis_rstick_x) / controller_get_axis_scale(ctype, rel_axis_rstick_x))
            {
              *mcal->dzy = controller_get_mean_unsigned(ctype, rel_axis_rstick_x) / controller_get_axis_scale(ctype, rel_axis_rstick_x);
            }
            mc->merge_x[mc->index] = 0;
            mc->merge_y[mc->index] = 1;
            mc->change = 1;
          }
          break;
        case DZS:
          if (mcal->dzs)
          {
            if (*mcal->dzs == E_SHAPE_CIRCLE)
            {
              *mcal->dzs = E_SHAPE_RECTANGLE;
            }
            else
            {
              *mcal->dzs = E_SHAPE_CIRCLE;
            }
            mc->merge_x[mc->index] = 1;
            mc->merge_y[mc->index] = 1;
            mc->change = 1;
          }
          break;
        case RD:
          mcal->rd += 1;
          break;
        case VEL:
          mcal->vel += 1;
          break;
        case EX:
          if (mcal->ex)
          {
            *mcal->ex += EXPONENT_STEP;
          }
          break;
        case EY:
          if (mcal->ey)
          {
            *mcal->ey += EXPONENT_STEP;
          }
          break;
        case TEST:
          test_time += 10;
          break;
        case NONE:
          break;
      }
      if(current_cal != NONE)
      {
        if(gimx_params.curses)
        {
          display_calibration();
        }
        else
        {
          cal_display();
        }
      }
      break;
    case GE_BTN_WHEELDOWN:
      switch (current_cal)
      {
        case MC:
          if (current_mouse > 0)
          {
            current_mouse -= 1;
          }
          break;
        case CC:
          if (current_conf > 0)
          {
            current_conf -= 1;
          }
          break;
        case MX:
          if (mcal->mx && mcal->my)
          {
            ratio = *mcal->my / *mcal->mx;
            *mcal->mx -= DEFAULT_MULTIPLIER_STEP;
            *mcal->my = *mcal->mx * ratio;
          }
          break;
        case MY:
          if (mcal->mx && mcal->my)
          {
            ratio = *mcal->my / *mcal->mx;
            ratio -= DEFAULT_MULTIPLIER_STEP;
            *mcal->my = *mcal->mx * ratio;
          }
          break;
        case DZX:
          if (mcal->dzx && *mcal->dzx > 0)
          {
            *mcal->dzx -= 1;
            mc->merge_x[mc->index] = -1;
            mc->merge_y[mc->index] = 0;
            mc->change = 1;
          }
          break;
        case DZY:
          if (mcal->dzy && *mcal->dzy > 0)
          {
            *mcal->dzy -= 1;
            mc->merge_x[mc->index] = 0;
            mc->merge_y[mc->index] = -1;
            mc->change = 1;
          }
          break;
        case DZS:
          if (mcal->dzs)
          {
            if (*mcal->dzs == E_SHAPE_CIRCLE)
            {
              *mcal->dzs = E_SHAPE_RECTANGLE;
            }
            else
            {
              *mcal->dzs = E_SHAPE_CIRCLE;
            }
            mc->merge_x[mc->index] = -1;
            mc->merge_y[mc->index] = -1;
            mc->change = 1;
          }
          break;
        case RD:
          mcal->rd -= 1;
          if(mcal->rd < 1)
          {
            mcal->rd = 1;
          }
          break;
        case VEL:
          mcal->vel -= 1;
          if(mcal->vel < 1)
          {
            mcal->vel = 1;
          }
          break;
        case EX:
          if (mcal->ex)
          {
            *mcal->ex -= EXPONENT_STEP;
          }
          break;
        case EY:
          if (mcal->ey)
          {
            *mcal->ey -= EXPONENT_STEP;
          }
          break;
        case TEST:
          test_time -= 10;
          break;
        case NONE:
          break;
      }
      if(current_cal != NONE)
      {
        if(gimx_params.curses)
        {
          display_calibration();
        }
        else
        {
          cal_display();
        }
      }
      break;
    default:
      break;
  }
}
Пример #7
0
int args_read(int argc, char *argv[], s_gimx_params* params)
{
  int ret = 0;
  int c;
  unsigned char controller = 0;
  unsigned char input = 0;

  struct option long_options[] =
  {
    /* These options set a flag. */
    {"nograb",         no_argument, &params->grab,           0},
    {"status",         no_argument, &params->status,         1},
    {"subpos",         no_argument, &params->subpositions,   1},
    {"force-updates",  no_argument, &params->force_updates,  1},
    {"curses",         no_argument, &params->curses,         1},
    {"window-events",  no_argument, &params->window_events,  1},
    {"btstack",        no_argument, &params->btstack,        1},
    /* These options don't set a flag. We distinguish them by their indices. */
    {"bdaddr",  required_argument, 0, 'b'},
    {"config",  required_argument, 0, 'c'},
    {"dst",     required_argument, 0, 'd'},
    {"event",   required_argument, 0, 'e'},
    {"hci",     required_argument, 0, 'h'},
    {"help",    no_argument,       0, 'm'},
    {"keygen",  required_argument, 0, 'k'},
    {"log",     required_argument, 0, 'l'},
    {"port",    required_argument, 0, 'p'},
    {"refresh", required_argument, 0, 'r'},
    {"src",     required_argument, 0, 's'},
    {"type",    required_argument, 0, 't'},
    {"version", no_argument,       0, 'v'},
    {0, 0, 0, 0}
  };
  
  while (1)
  {
    /* getopt_long stores the option index here. */
    int option_index = 0;

    c = getopt_long (argc, argv, "b:c:d:e:h:k:l:p:r:s:t:vm", long_options, &option_index);

    /* Detect the end of the options. */
    if (c == -1)
    break;

    if(controller == MAX_CONTROLLERS)
    {
      printf(_("ignoring: -%c %s (max controllers reached)\n"), c, optarg);
      continue;
    }

    switch (c)
    {
      case 0:
        /* If this option set a flag, do nothing else now. */
        if (long_options[option_index].flag != 0)
          break;
        printf(_("option %s"), long_options[option_index].name);
        if (optarg)
          printf(_(" with arg %s"), optarg);
        printf("\n");
        break;

      case 'b':
        adapter_get(controller)->atype = E_ADAPTER_TYPE_BLUETOOTH;
        adapter_get(controller)->bdaddr_dst = optarg;
        if(adapter_get(controller)->ctype == C_TYPE_NONE)
        {
          adapter_get(controller)->ctype = C_TYPE_SIXAXIS;
        }
        printf(_("controller #%d: option -b with value `%s'\n"), controller + 1, optarg);
        ++controller;
        printf(_("now reading arguments for controller #%d\n"), controller + 1);
        break;

      case 'c':
        params->config_file = optarg;
        printf(_("global option -c with value `%s'\n"), optarg);
        input = 1;
        break;

      case 'e':
        {
          char label[AXIS_NAME_MAX_SIZE];
          int axis;
          int value;
          if(sscanf(optarg, "%"STR(AXIS_NAME_MAX_SIZE)"[^(](%d)", label, &value) != 2)
          {
            fprintf(stderr, _("Bad event format: %s\n"), optarg);
            ret = -1;
          }
          else
          {
            // strip trailing spaces
            char * end;
            for (end = label + strlen(label) - 1; end > label && *end == ' '; --end) {}
            *(end + 1) = '\0';
            if((axis = controller_get_axis_index(label)) != -1)
            {
              printf(_("controller #%d: option -e with value `%s(%d)'\n"), controller + 1, label, value);
              adapter_set_axis(controller, axis, value);
              adapter_get(controller)->event = 1;
              input = 1;
            }
            else
            {
              fprintf(stderr, _("Bad axis name for event: %s\n"), optarg);
              ret = -1;
            }
          }
        }
        break;

      case 'h':
        adapter_get(controller)->dongle_index = atoi(optarg);
        printf(_("controller #%d: option -h with value `%d'\n"), controller + 1, adapter_get(controller)->dongle_index);
        break;

      case 'd':
        if(read_ip(optarg, &adapter_get(controller)->dst_ip,
            &adapter_get(controller)->dst_port) < 0)
        {
          printf(_("Bad format for argument -d: '%s'\n"), optarg);
          ret = -1;
        }
        else
        {
          adapter_get(controller)->atype = E_ADAPTER_TYPE_REMOTE_GIMX;
          printf(_("controller #%d: option -d with value `%s'\n"), controller + 1, optarg);
          ++controller;
          printf(_("now reading arguments for controller #%d\n"), controller + 1);
        }
        break;

      case 'm':
        usage();
        exit(0);
        break;

      case 's':
        if(read_ip(optarg, &adapter_get(controller)->src_ip,
            &adapter_get(controller)->src_port) < 0)
        {
          printf(_("Bad format for argument -s: '%s'\n"), optarg);
          ret = -1;
        }
        else
        {
          printf(_("controller #%d: option -s with value `%s'\n"), controller + 1, optarg);
          input = 1;
          params->network_input = 1;
        }
        break;

      case 'k':
        params->keygen = optarg;
        printf(_("controller #%d: option -k with value `%s'\n"), controller + 1, optarg);
        break;

      case 'l':
        if(params->logfilename == NULL)
        {
          if(!params->curses)
          {
            params->logfilename = optarg;
            if(params->logfilename && strlen(params->logfilename))
            {
              char file_path[PATH_MAX];
              snprintf(file_path, sizeof(file_path), "%s%s%s%s", params->homedir, GIMX_DIR, LOG_DIR, params->logfilename);
              params->logfile = fopen(file_path, "w");
              if(params->logfile != NULL)
              {
                dup2(fileno(params->logfile), fileno(stdout));
                dup2(fileno(params->logfile), fileno(stderr));
              }
              else
              {
                printf(_("can't open log file (%s)\n"), file_path);
                ret = -1;
              }
            }
            printf(_("global option -l with value `%s'\n"), optarg);
          }
          else
          {
            printf(_("log file can't be used with curses\n"));
            ret = -1;
          }
        }
        else
        {
          printf(_("only one log file can be specified\n"));
          ret = -1;
        }
        break;

      case 'p':
        if(adapter_get(controller)->atype == E_ADAPTER_TYPE_NONE)
        {
          // no adapter type specified => try to guess it from the port
          if(strstr(optarg, DEV_HIDRAW) || !strstr(optarg, DEV_SERIAL))
          {
            adapter_get(controller)->atype = E_ADAPTER_TYPE_GPP;
          }
          else
          {
            adapter_get(controller)->atype = E_ADAPTER_TYPE_DIY_USB;
          }
        }
        if(adapter_set_port(controller, optarg) < 0)
        {
          printf(_("port already used: `%s'\n"), optarg);
          ret = -1;
        }
        else
        {
          printf(_("controller #%d: option -p with value `%s'\n"), controller + 1, optarg);
          ++controller;
          printf(_("now reading arguments for controller #%d\n"), controller + 1);
        }
        break;

      case 'r':
        params->refresh_period = atof(optarg) * 1000;
        if(params->refresh_period)
        {
          params->postpone_count = 3 * DEFAULT_REFRESH_PERIOD / params->refresh_period;
          printf(_("global option -r with value `%s'\n"), optarg);
        }
        else
        {
          fprintf(stderr, "Bad refresh period: %s\n", optarg);
          ret = -1;
        }
        break;

      case 't':
        printf(_("controller #%d: option -t with value `%s'\n"), controller + 1, optarg);
        if (!strcmp(optarg, "GPP"))
        {
          adapter_get(controller)->atype = E_ADAPTER_TYPE_GPP;
        }
        else
        {
          adapter_get(controller)->ctype = controller_get_type(optarg);
          if (adapter_get(controller)->ctype == C_TYPE_NONE)
          {
            fprintf(stderr, "Bad controller type: %s\n", optarg);
            ret = -1;
          }
        }
        break;

      case 'v':
        printf("GIMX %s %s\n", INFO_VERSION, INFO_ARCH);
        exit(0);
        break;

      case '?':
        usage();
        exit(-1);
        break;

      default:
        printf(_("unrecognized option: %c\n"), c);
        ret = -1;
        break;
    }
  }

  if(params->status || params->logfilename)
    params->curses = 0;

  if(!params->grab)
    printf(_("grab flag is unset\n"));
  if(params->status)
    printf(_("status flag is set\n"));
  if(params->subpositions)
    printf(_("subpos flag is set\n"));
  if(params->force_updates)
    printf(_("force_updates flag is set\n"));
  if(params->curses)
    printf(_("curses flag is set\n"));
  if(params->window_events)
    printf(_("window_events flag is set\n"));
  if(params->btstack)
    printf(_("btstack flag is set\n"));

  if(!input)
  {
    fprintf(stderr, "At least a config file, an event, or a source IP:port should be specified as argument.\n");
    ret = -1;
  }

  if(params->logfile)
  {
    log_info();
  }

  return ret;
}