in_sdl: give names to gamepad buttons
[libpicofe.git] / input.c
diff --git a/input.c b/input.c
index 9d938ea..92b47a2 100644 (file)
--- a/input.c
+++ b/input.c
 #include "plat.h"
 #include "lprintf.h"
 
-#ifdef IN_VK
-#error needs update: in_vk_init in_vk_update
-#include "../win32/in_vk.h"
-#endif
-
 typedef struct
 {
        int drv_id;
@@ -30,6 +25,7 @@ typedef struct
        char *name;
        int key_count;
        int *binds;     /* total = key_count * bindtypes * 2 */
+       int *kbd_binds; /* total = key_count */
        const char * const *key_names;
        unsigned int probed:1;
        unsigned int does_combos:1;
@@ -43,6 +39,8 @@ static int in_have_async_devs = 0;
 static int in_probe_dev_id;
 static int menu_key_state = 0;
 static int menu_last_used_dev = 0;
+static int menu_key_prev = 0;
+static int menu_key_repeat = 0;
 
 #define DRV(id) in_drivers[id]
 
@@ -75,6 +73,31 @@ static int *in_alloc_binds(int drv_id, int key_count)
        return binds;
 }
 
+static int *in_alloc_kbd_binds(int drv_id, int key_count)
+{
+       const struct in_default_bind *defbinds;
+       int *binds;
+       int i;
+
+       binds = calloc(key_count * 2, sizeof(binds[0]));
+       if (binds == NULL)
+               return NULL;
+
+       /* always have a copy of defbinds */
+       defbinds = DRV(drv_id).kbd_binds;
+       if (defbinds != NULL) {
+               for (i = 0; ; i++) {
+                       if (defbinds[i].code == 0 && defbinds[i].btype == 0
+                           && defbinds[i].bit == 0)
+                               break;
+
+                       binds[defbinds[i].code] = defbinds[i].bit;
+               }
+       }
+
+       return binds;
+}
+
 static void in_unprobe(in_dev_t *dev)
 {
        if (dev->probed)
@@ -97,7 +120,7 @@ static void in_free(in_dev_t *dev)
 void in_register(const char *nname, int drv_fd_hnd, void *drv_data,
                int key_count, const char * const *key_names, int combos)
 {
-       int i, ret, dupe_count = 0, *binds;
+       int i, ret, dupe_count = 0, *binds, *kbd_binds;
        char name[256], *name_end, *tmp;
 
        strncpy(name, nname, sizeof(name));
@@ -140,12 +163,18 @@ void in_register(const char *nname, int drv_fd_hnd, void *drv_data,
                free(tmp);
                return;
        }
+       kbd_binds = in_alloc_kbd_binds(in_probe_dev_id, key_count);
+       if (kbd_binds == NULL) {
+               free(tmp);
+               return;
+       }
 
        memcpy(binds, binds + key_count * IN_BINDTYPE_COUNT,
                sizeof(binds[0]) * key_count * IN_BINDTYPE_COUNT);
 
        in_devices[i].name = tmp;
        in_devices[i].binds = binds;
+       in_devices[i].kbd_binds = kbd_binds;
        in_devices[i].key_count = key_count;
        if (i + 1 > in_dev_count)
                in_dev_count = i + 1;
@@ -290,6 +319,19 @@ int in_update(int *result)
        return ret;
 }
 
+int in_update_kbd(int *result)
+{
+       int i, ret = 0;
+
+       for (i = 0; i < in_dev_count; i++) {
+               in_dev_t *dev = &in_devices[i];
+               if (dev->probed && dev->binds != NULL)
+                       ret += DRV(dev->drv_id).update_kbd(dev->drv_data, dev->kbd_binds, result+ret);
+       }
+
+       return ret;
+}
+
 static in_dev_t *get_dev(int dev_id)
 {
        if (dev_id < 0 || dev_id >= IN_MAX_DEVS)
@@ -308,6 +350,16 @@ int in_update_analog(int dev_id, int axis_id, int *result)
        return DRV(dev->drv_id).update_analog(dev->drv_data, axis_id, result);
 }
 
+int in_update_pointer(int dev_id, int id, int *result)
+{
+       in_dev_t *dev = get_dev(dev_id);
+
+       if (dev == NULL || !dev->probed)
+               return -1;
+
+       return DRV(dev->drv_id).update_pointer(dev->drv_data, id, result);
+}
+
 static int in_update_kc_async(int *dev_id_out, int *is_down_out, int timeout_ms)
 {
        int i, is_down, result;
@@ -355,8 +407,11 @@ int in_update_keycode(int *dev_id_out, int *is_down_out, char *charcode, int tim
 
        if (in_have_async_devs) {
                result = in_update_kc_async(&dev_id, &is_down, timeout_ms);
-               if (result == -1)
+               if (result == -1) {
+                       // no key up event for RDRAW, clear to avoid key repeat
+                       menu_key_state &= ~PBTN_RDRAW;
                        return -1;
+               }
                drv = &DRV(in_devices[dev_id].drv_id);
                goto finish;
        }
@@ -432,47 +487,43 @@ int in_menu_wait_any(char *charcode, int timeout_ms)
 {
        int keys_old = menu_key_state;
        int ret;
-       int is_down = 0, dev_id = 0;
+       int dev_id = 0;
+
+       menu_key_prev = menu_key_state;
 
-       in_update_keycode(&dev_id, &is_down, charcode, timeout_ms);
+       in_update_keycode(&dev_id, NULL, charcode, timeout_ms);
 
        if (keys_old != menu_key_state)
                menu_last_used_dev = dev_id;
 
        ret = menu_key_state;
-       menu_key_state &= ~PBTN_CHAR;
+       if (ret == 0)
+               menu_key_prev = 0;
+
        return ret;
 }
 
 /* wait for menu input, do autorepeat */
 int in_menu_wait(int interesting, char *charcode, int autorep_delay_ms)
 {
-       static int inp_prev = 0;
-       static int repeats = 0;
-       int ret, release = 0, wait = 450;
+       int ret, wait = 450;
 
-       if (repeats)
+       if (menu_key_repeat)
                wait = autorep_delay_ms;
 
-       ret = in_menu_wait_any(charcode, wait);
-       if (ret == inp_prev)
-               repeats++;
-
-       while (!(ret & interesting)) {
-               ret = in_menu_wait_any(charcode, -1);
-               release = 1;
-       }
-
-       if (release || ret != inp_prev)
-               repeats = 0;
-
-       inp_prev = ret;
+       /* wait until either key repeat or a new key has been pressed */
+       interesting |= PBTN_RDRAW;
+       do {
+               ret = in_menu_wait_any(charcode, wait);
+               if (ret == 0 || ret != menu_key_prev)
+                       menu_key_repeat = 0;
+               else
+                       menu_key_repeat++;
+               wait = -1;
+       } while (!(ret & interesting));
 
        /* we don't need diagonals in menus */
-       if ((ret & PBTN_UP)   && (ret & PBTN_LEFT))  ret &= ~PBTN_LEFT;
-       if ((ret & PBTN_UP)   && (ret & PBTN_RIGHT)) ret &= ~PBTN_RIGHT;
-       if ((ret & PBTN_DOWN) && (ret & PBTN_LEFT))  ret &= ~PBTN_LEFT;
-       if ((ret & PBTN_DOWN) && (ret & PBTN_RIGHT)) ret &= ~PBTN_RIGHT;
+       if (ret & (PBTN_UP|PBTN_DOWN))  ret &= ~(PBTN_LEFT|PBTN_RIGHT);
 
        return ret;
 }
@@ -484,6 +535,13 @@ const int *in_get_dev_binds(int dev_id)
        return dev ? dev->binds : NULL;
 }
 
+const int *in_get_dev_kbd_binds(int dev_id)
+{
+       in_dev_t *dev = get_dev(dev_id);
+
+       return dev ? dev->kbd_binds : NULL;
+}
+
 const int *in_get_dev_def_binds(int dev_id)
 {
        in_dev_t *dev = get_dev(dev_id);
@@ -495,7 +553,18 @@ const int *in_get_dev_def_binds(int dev_id)
        return dev->binds + dev->key_count * IN_BINDTYPE_COUNT;
 }
 
-int in_get_config(int dev_id, int what, void *val)
+const int *in_get_dev_kbd_def_binds(int dev_id)
+{
+       in_dev_t *dev = get_dev(dev_id);
+       if (dev == NULL)
+               return NULL;
+       if (dev->binds == NULL)
+               return NULL;
+
+       return dev->kbd_binds;
+}
+
+int in_get_config(int dev_id, enum in_cfg_opt what, void *val)
 {
        int *ival = val;
        in_dev_t *dev;
@@ -550,7 +619,7 @@ static int in_set_blocking(int is_blocking)
        return 0;
 }
 
-int in_set_config(int dev_id, int what, const void *val, int size)
+int in_set_config(int dev_id, enum in_cfg_opt what, const void *val, size_t size)
 {
        const char * const *names;
        const int *ival = val;
@@ -727,6 +796,30 @@ int in_bind_key(int dev_id, int keycode, int mask, int bind_type, int force_unbi
        return 0;
 }
 
+int in_bind_kbd_key(int dev_id, int keycode, int kbd_key)
+{
+       int count;
+       in_dev_t *dev;
+
+       dev = get_dev(dev_id);
+       if (dev == NULL)
+               return -1;
+
+       count = dev->key_count;
+
+       if (dev->kbd_binds == NULL) {
+               dev->kbd_binds = in_alloc_kbd_binds(dev->drv_id, count);
+               if (dev->kbd_binds == NULL)
+                       return -1;
+       }
+
+       if (keycode < 0 || keycode >= count)
+               return -1;
+
+       dev->kbd_binds[keycode] = (kbd_key == -1 ? 0 : kbd_key);
+       return 0;
+}
+
 /*
  * Unbind act_mask on binds with type bind_type
  * - if dev_id_ < 0, affects all devices
@@ -756,9 +849,11 @@ void in_unbind_all(int dev_id_, int act_mask, int bind_type)
                if (act_mask != -1) {
                        for (i = 0; i < count; i++)
                                dev->binds[IN_BIND_OFFS(i, bind_type)] &= ~act_mask;
-               }
-               else
+               } else {
                        memset(dev->binds, 0, sizeof(dev->binds[0]) * count * IN_BINDTYPE_COUNT);
+                       if (dev->kbd_binds)
+                               memset(dev->kbd_binds, 0, sizeof(dev->kbd_binds[0]) * count);
+               }
        }
 }
 
@@ -816,14 +911,9 @@ int in_config_parse_dev(const char *name)
        return i;
 }
 
-int in_config_bind_key(int dev_id, const char *key, int acts, int bind_type)
+static int parse_key(in_dev_t *dev, const char *key)
 {
-       in_dev_t *dev;
-       int i, offs, kc;
-
-       dev = get_dev(dev_id);
-       if (dev == NULL || bind_type >= IN_BINDTYPE_COUNT)
-               return -1;
+       int kc, i;
 
        /* maybe a raw code? */
        if (key[0] == '\\' && key[1] == 'x') {
@@ -859,6 +949,20 @@ int in_config_bind_key(int dev_id, const char *key, int acts, int bind_type)
                }
        }
 
+       return kc;
+}
+
+int in_config_bind_key(int dev_id, const char *key, int acts, int bind_type)
+{
+       in_dev_t *dev;
+       int i, offs, kc;
+
+       dev = get_dev(dev_id);
+       if (dev == NULL || bind_type >= IN_BINDTYPE_COUNT)
+               return -1;
+
+       kc = parse_key(dev, key);
+
        if (kc < 0 || kc >= dev->key_count) {
                lprintf("input: bad key: '%s' for device '%s'\n",
                        key, dev->name);
@@ -878,6 +982,28 @@ int in_config_bind_key(int dev_id, const char *key, int acts, int bind_type)
        return 0;
 }
 
+int in_config_bind_kbd_key(int dev_id, const char *key, int kbd_key)
+{
+       in_dev_t *dev;
+       int kc;
+
+       dev = get_dev(dev_id);
+       if (dev == NULL)
+               return -1;
+
+       kc = parse_key(dev, key);
+
+       if (kc < 0 || kc >= dev->key_count) {
+               lprintf("input: bad key: '%s' for device '%s'\n",
+                       key, dev->name);
+               return -1;
+       }
+
+       dev->kbd_binds[kc] = kbd_key;
+
+       return 0;
+}
+
 void in_clean_binds(void)
 {
        int i;
@@ -937,9 +1063,10 @@ void in_debug_dump(void)
 
 static void in_def_free(void *drv_data) {}
 static int  in_def_clean_binds(void *drv_data, int *b, int *db) { return 1; }
-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_get_config(void *drv_data, enum in_cfg_opt what, int *val) { return -1; }
+static int  in_def_set_config(void *drv_data, enum in_cfg_opt what, int val) { return -1; }
 static int  in_def_update_analog(void *drv_data, int axis_id, int *result) { return -1; }
+static int  in_def_update_pointer(void *drv_data, int id, int *result) { 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, char *ccode) { return 0; }
 static int  in_def_get_key_code(const char *key_name) { return -1; }
@@ -950,7 +1077,9 @@ static const char *in_def_get_key_name(int keycode) { return NULL; }
 
 /* to be called by drivers */
 int in_register_driver(const in_drv_t *drv,
-                       const struct in_default_bind *defbinds, const void *pdata)
+                       const struct in_default_bind *defbinds, 
+                       const struct in_default_bind *kbd_map, 
+                       const void *pdata)
 {
        int count_new = in_driver_count + 1;
        in_drv_t *new_drivers;
@@ -968,6 +1097,7 @@ int in_register_driver(const in_drv_t *drv,
        CHECK_ADD_STUB(new_drivers[in_driver_count], get_config);
        CHECK_ADD_STUB(new_drivers[in_driver_count], set_config);
        CHECK_ADD_STUB(new_drivers[in_driver_count], update_analog);
+       CHECK_ADD_STUB(new_drivers[in_driver_count], update_pointer);
        CHECK_ADD_STUB(new_drivers[in_driver_count], update_keycode);
        CHECK_ADD_STUB(new_drivers[in_driver_count], menu_translate);
        CHECK_ADD_STUB(new_drivers[in_driver_count], get_key_code);
@@ -976,6 +1106,8 @@ int in_register_driver(const in_drv_t *drv,
                new_drivers[in_driver_count].pdata = pdata;
        if (defbinds)
                new_drivers[in_driver_count].defbinds = defbinds;
+       if (kbd_map)
+               new_drivers[in_driver_count].kbd_binds = kbd_map;
        in_drivers = new_drivers;
        in_driver_count = count_new;