+int in_config_bind_key(int dev_id, const char *key, int acts, int bind_type)
+{
+ in_dev_t *dev;
+ int i, offs, kc;
+
+ if (dev_id < 0 || dev_id >= IN_MAX_DEVS || bind_type >= IN_BINDTYPE_COUNT)
+ return -1;
+ dev = &in_devices[dev_id];
+
+ /* maybe a raw code? */
+ if (key[0] == '\\' && key[1] == 'x') {
+ char *p = NULL;
+ kc = (int)strtoul(key + 2, &p, 16);
+ if (p == NULL || *p != 0)
+ kc = -1;
+ }
+ else {
+ /* device specific key name */
+ if (dev->binds == NULL) {
+ dev->binds = in_alloc_binds(dev->drv_id, dev->key_count);
+ if (dev->binds == NULL)
+ return -1;
+ in_config_start();
+ }
+
+ kc = -1;
+ if (dev->key_names != NULL) {
+ for (i = 0; i < dev->key_count; i++) {
+ const char *k = dev->key_names[i];
+ if (k != NULL && strcasecmp(k, key) == 0) {
+ kc = i;
+ break;
+ }
+ }
+ }
+
+ if (kc < 0)
+ kc = DRV(dev->drv_id).get_key_code(key);
+ if (kc < 0 && strlen(key) == 1) {
+ /* assume scancode */
+ kc = key[0];
+ }
+ }
+
+ if (kc < 0 || kc >= dev->key_count) {
+ lprintf("input: bad key: %s\n", key);
+ return -1;
+ }
+
+ if (bind_type == IN_BINDTYPE_NONE) {
+ for (i = 0; i < IN_BINDTYPE_COUNT; i++)
+ dev->binds[IN_BIND_OFFS(kc, i)] = 0;
+ return 0;
+ }
+
+ offs = IN_BIND_OFFS(kc, bind_type);
+ if (dev->binds[offs] == -1)
+ dev->binds[offs] = 0;
+ dev->binds[offs] |= acts;
+ return 0;
+}
+
+void in_config_end(void)
+{
+ int i;
+
+ for (i = 0; i < IN_MAX_DEVS; i++) {
+ int n, t, ret, count, *binds, *def_binds;
+ in_dev_t *dev = &in_devices[i];
+
+ if (dev->binds == NULL)
+ continue;
+
+ count = dev->key_count;
+ binds = dev->binds;
+ def_binds = binds + count * IN_BINDTYPE_COUNT;
+
+ for (n = 0; n < count; n++) {
+ int is_default = 1;
+ for (t = 0; t < IN_BINDTYPE_COUNT; t++)
+ if (binds[IN_BIND_OFFS(n, t)] == -1)
+ binds[IN_BIND_OFFS(n, t)] = 0;
+ else
+ is_default = 0;
+
+ if (is_default)
+ for (t = 0; t < IN_BINDTYPE_COUNT; t++)
+ binds[IN_BIND_OFFS(n, t)] = def_binds[IN_BIND_OFFS(n, t)];
+ }
+
+ if (dev->drv_data == NULL)
+ continue;
+
+ ret = DRV(dev->drv_id).clean_binds(dev->drv_data, binds, def_binds);
+ if (ret == 0) {
+ /* no useable binds */
+ free(dev->binds);
+ dev->binds = NULL;
+ }
+ }
+}
+
+void in_debug_dump(void)
+{
+ int i;
+
+ lprintf("# drv probed binds name\n");
+ for (i = 0; i < IN_MAX_DEVS; i++) {
+ in_dev_t *d = &in_devices[i];
+ if (!d->probed && d->name == NULL && d->binds == NULL)
+ continue;
+ lprintf("%d %3d %6c %5c %s\n", i, d->drv_id, d->probed ? 'y' : 'n',
+ d->binds ? 'y' : 'n', d->name);
+ }
+}
+
+/* handlers for unknown/not_preset drivers */
+
+static void in_def_probe(void) {}
+static void in_def_free(void *drv_data) {}
+static int in_def_get_bind_count(void) { return 0; }
+static void in_def_get_def_binds(int *binds) {}
+static int in_def_clean_binds(void *drv_data, int *b, int *db) { return 0; }
+static int in_def_get_config(void *drv_data, int what, int *val) { return -1; }
+static int in_def_set_config(void *drv_data, int what, int val) { return -1; }
+static int in_def_update_keycode(void *drv_data, int *is_down) { return 0; }
+static int in_def_menu_translate(void *drv_data, int keycode) { return keycode; }
+static int in_def_get_key_code(const char *key_name) { return -1; }
+static const char *in_def_get_key_name(int keycode) { return NULL; }
+