Add support for Pico Keyboard
authorqufb <93520295+qufb@users.noreply.github.com>
Mon, 27 Jun 2022 21:54:43 +0000 (22:54 +0100)
committerkub <derkub@gmail.com>
Thu, 16 Jan 2025 17:47:50 +0000 (18:47 +0100)
pico/pico.h
pico/pico/memory.c
platform/common/emu.c
platform/common/input_pico.h
platform/common/inputmap_kbd.c
platform/common/menu_pico.c
platform/common/plat_sdl.c
platform/common/plat_sdl.h
platform/libpicofe

index 32522c5..25cf877 100644 (file)
@@ -132,6 +132,8 @@ typedef struct PicoInterface
 \r
        void (*mcdTrayOpen)(void);\r
        void (*mcdTrayClose)(void);\r
+\r
+       unsigned int ps2;   // PS/2 peripherals, e.g. Pico Keyboard\r
 } PicoInterface;\r
 \r
 extern PicoInterface PicoIn;\r
@@ -151,6 +153,32 @@ struct PicoEState;
 \r
 // pico.c\r
 #define XPCM_BUFFER_SIZE 64\r
+enum {\r
+  KEY_RELEASED = 0,\r
+  KEY_DOWN,\r
+  KEY_UP,\r
+};\r
+enum {\r
+  SHIFT_RELEASED = 0,\r
+  SHIFT_DOWN,\r
+  SHIFT_UP_HELD_DOWN,\r
+  SHIFT_RELEASED_HELD_DOWN,\r
+  SHIFT_UP\r
+};\r
+typedef struct\r
+{\r
+    uint8_t i;\r
+    uint8_t mode;\r
+    uint8_t neg;\r
+    uint8_t has_read;\r
+    uint8_t caps_lock;\r
+    uint8_t has_caps_lock;\r
+    uint32_t mem;\r
+    uint64_t start_time_keydown;\r
+    uint64_t time_keydown;\r
+    uint8_t key_state;\r
+    uint8_t shift_state;\r
+} picohw_kb;\r
 typedef struct\r
 {\r
        int pen_pos[2];\r
@@ -160,6 +188,9 @@ typedef struct
        unsigned int reserved[3];\r
        unsigned char xpcm_buffer[XPCM_BUFFER_SIZE+4];\r
        unsigned char *xpcm_ptr;\r
+       int is_kb_active;\r
+       int inp_mode;\r
+       picohw_kb kb;\r
 } picohw_state;\r
 extern picohw_state PicoPicohw;\r
 \r
index f294b03..c2e0904 100644 (file)
@@ -8,6 +8,8 @@
  */
 #include "../pico_int.h"
 #include "../memory.h"
+#include <platform/common/input_pico.h>
+#include <sys/time.h>
 
 /*
 void dump(u16 w)
@@ -25,6 +27,20 @@ void dump(u16 w)
 }
 */
 
+u64 get_ticks(void)
+{
+    struct timeval tv;
+    u64 ret;
+
+    gettimeofday(&tv, NULL);
+
+    ret = (unsigned)tv.tv_sec * 1000;
+    /* approximate /= 1000 */
+    ret += ((unsigned)tv.tv_usec * 4195) >> 22;
+
+    return ret;
+}
+
 static u32 PicoRead16_pico(u32 a)
 {
   u32 d = 0;
@@ -40,7 +56,15 @@ static u32 PicoRead16_pico(u32 a)
     case 0x06: d =  PicoPicohw.pen_pos[0] & 0xff; break;
     case 0x08: d = (PicoPicohw.pen_pos[1] >> 8);  break;
     case 0x0a: d =  PicoPicohw.pen_pos[1] & 0xff; break;
-    case 0x0c: d = (1 << (PicoPicohw.page & 7)) - 1; break;
+    case 0x0c: d = (1 << (PicoPicohw.page & 7)) - 1;
+               if (PicoPicohw.is_kb_active) {
+                 // Apply 1 of 2 bitmasks, depending on which one preserves the highest set bit.
+                 if (PicoPicohw.page % 2 == 0)
+                   d &= 0x2a; // 0b00101010
+                 else
+                   d &= 0x15; // 0b00010101
+               }
+               break;
     case 0x10: d = (PicoPicohw.fifo_bytes > 0x3f) ? 0 : (0x3f - PicoPicohw.fifo_bytes); break;
     case 0x12: d = (PicoPicohw.fifo_bytes | !PicoPicoPCMBusyN()) ? 0 : 0x8000;
                d |= PicoPicohw.r12 & 0x7fff;
@@ -111,6 +135,178 @@ static void PicoWrite16_pico(u32 a, u32 d)
     elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
 }
 
+static u32 PicoRead8_pico_kb(u32 a)
+{
+  u32 d = 0;
+  if (PicoPicohw.is_kb_active == 0) {
+    elprintf(EL_PICOHW, "kb: r @%06X %04X = %04X\n", SekPc, a, d);
+    return d;
+  }
+
+  PicoPicohw.kb.has_read = 1;
+
+  u32 key_shift = (PicoIn.ps2 & 0xff00) >> 8;
+  u32 key = (PicoIn.ps2 & 0x00ff);
+
+  // The Shift key requires 2 key up events to be registered:
+  // SHIFT_UP_HELD_DOWN to allow the game to register the key down event
+  // for the next held down key(s), and SHIFT_UP when the Shift key
+  // is no longer held down.
+  //
+  // For the second key up event, we need to
+  // override the parsed key code with PEVB_PICO_PS2_LSHIFT,
+  // otherwise it will be zero and the game won't clear its Shift key state.
+  u32 key_code = (key_shift
+      && !key
+      && PicoPicohw.kb.key_state != KEY_UP
+      && PicoPicohw.kb.shift_state != SHIFT_UP_HELD_DOWN)
+    ? key_shift
+    : PicoPicohw.kb.shift_state == SHIFT_UP ? PEVB_PICO_PS2_LSHIFT : key;
+  u32 key_code_7654 = (key_code & 0xf0) >> 4;
+  u32 key_code_3210 = (key_code & 0x0f);
+  switch(PicoPicohw.kb.i) {
+    case 0x0: d = 1; // m5id
+      break;
+    case 0x1: d = 3; // m6id
+      break;
+    case 0x2: d = 4; // data size
+      break;
+    case 0x3: d = 0; // pad1 rldu
+      break;
+    case 0x4: d = 0; // pad2 sacb
+      break;
+    case 0x5: d = 0; // pad3 rxyz
+      break;
+    case 0x6: d = 0; // l&kbtype
+      break;
+    case 0x7: // cap/num/scr
+      if (PicoPicohw.inp_mode == 3) {
+        if (key == PEVB_PICO_PS2_CAPSLOCK && PicoPicohw.kb.has_caps_lock == 1) {
+          PicoPicohw.kb.caps_lock = PicoPicohw.kb.caps_lock == 4 ? 0 : 4;
+          PicoPicohw.kb.has_caps_lock = 0;
+        }
+        d = PicoPicohw.kb.caps_lock;
+      }
+      break;
+    case 0x8:
+      d = 6;
+      if (PicoPicohw.inp_mode == 3) {
+        if (key) {
+          PicoPicohw.kb.key_state = KEY_DOWN;
+        }
+        if (!key) {
+          PicoPicohw.kb.key_state = !PicoPicohw.kb.key_state ? 0 : (PicoPicohw.kb.key_state + 1) % (KEY_UP + 1);
+          PicoPicohw.kb.start_time_keydown = 0;
+        }
+        if (key_shift && !key) {
+          if (PicoPicohw.kb.shift_state < SHIFT_RELEASED_HELD_DOWN) {
+            PicoPicohw.kb.shift_state++;
+          }
+          PicoPicohw.kb.start_time_keydown = 0;
+        }
+        if (!key_shift) {
+          PicoPicohw.kb.shift_state = !PicoPicohw.kb.shift_state ? 0 : (PicoPicohw.kb.shift_state + 1) % (SHIFT_UP + 1);
+        }
+
+        if (PicoPicohw.kb.key_state == KEY_DOWN || PicoPicohw.kb.shift_state == SHIFT_DOWN) {
+          if (PicoPicohw.kb.start_time_keydown == 0) {
+            d |= 8; // Send key down a.k.a. make
+            PicoPicohw.kb.time_keydown = 0;
+            PicoPicohw.kb.start_time_keydown = get_ticks();
+           if (PicoPicohw.kb.key_state == KEY_DOWN)
+              elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: KEY DOWN\n");
+           else
+              elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: SHIFT DOWN\n");
+          }
+          // Simulate key repeat while held down a.k.a. typematic
+          PicoPicohw.kb.time_keydown = get_ticks() - PicoPicohw.kb.start_time_keydown;
+          if (PicoPicohw.kb.time_keydown > 350
+                  // Modifier keys don't have typematic
+                  && key_code != PEVB_PICO_PS2_CAPSLOCK
+                  && key_code != PEVB_PICO_PS2_LSHIFT) {
+            d |= 8; // Send key down a.k.a. make
+           if (PicoPicohw.kb.key_state == KEY_DOWN)
+              elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: KEY DOWN\n");
+           else
+              elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: SHIFT DOWN\n");
+          }
+        }
+        if (PicoPicohw.kb.key_state == KEY_UP
+            || PicoPicohw.kb.shift_state == SHIFT_UP_HELD_DOWN
+            || PicoPicohw.kb.shift_state == SHIFT_UP) {
+          d |= 1; // Send key up a.k.a. break
+          PicoPicohw.kb.start_time_keydown = 0;
+           if (PicoPicohw.kb.key_state == KEY_UP)
+              elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: KEY UP\n");
+           else
+              elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: SHIFT UP\n");
+        }
+      }
+      break;
+    case 0x9: d = key_code_7654; // data 7654
+      break;
+    case 0xa: d = key_code_3210; // data 3210
+      break;
+    case 0xb: d = 0; // ?
+      break;
+    case 0xc: d = 0; // ?
+      break;
+    default:
+      d = 0;
+      break;
+  }
+
+  if (PicoPicohw.kb.neg) {
+      d |= 0xfffffff0;
+  }
+
+  elprintf(EL_PICOHW, "kb: r @%06X %04X = %04X\n", SekPc, a, d);
+  return d;
+}
+
+static u32 PicoRead16_pico_kb(u32 a)
+{
+  u32 d = PicoPicohw.kb.mem;
+
+  elprintf(EL_PICOHW, "kb: r16 @%06X %04X = %04X\n", SekPc, a, d);
+  return d;
+}
+
+static void PicoWrite8_pico_kb(u32 a, u32 d)
+{
+  elprintf(EL_PICOHW, "kb: w @%06X %04X = %04X\n", SekPc, a, d);
+
+  switch(d) {
+    case 0x0:
+      PicoPicohw.kb.neg = 0;
+      PicoPicohw.kb.i++;
+      break;
+    case 0x20:
+      PicoPicohw.kb.neg = 1;
+      if (PicoPicohw.kb.has_read == 1) {
+        PicoPicohw.kb.i++;
+      }
+      break;
+    case 0x40:
+      break;
+    case 0x60:
+      PicoPicohw.kb.mode = !PicoPicohw.kb.mode;
+      PicoPicohw.kb.i = 0;
+      PicoPicohw.kb.has_read = 0;
+      break;
+    default:
+      break;
+  }
+
+  PicoPicohw.kb.mem = (PicoPicohw.kb.mem & 0xff00) | d;
+}
+
+static void PicoWrite16_pico_kb(u32 a, u32 d)
+{
+  elprintf(EL_PICOHW, "kb: w16 @%06X %04X = %04X\n", SekPc, a, d);
+
+  PicoPicohw.kb.mem = d;
+}
 
 PICO_INTERNAL void PicoMemSetupPico(void)
 {
@@ -124,5 +320,12 @@ PICO_INTERNAL void PicoMemSetupPico(void)
   cpu68k_map_set(m68k_read16_map,  0x800000, 0x80ffff, PicoRead16_pico, 1);
   cpu68k_map_set(m68k_write8_map,  0x800000, 0x80ffff, PicoWrite8_pico, 1);
   cpu68k_map_set(m68k_write16_map, 0x800000, 0x80ffff, PicoWrite16_pico, 1);
-}
 
+  m68k_map_unmap(0x200000, 0x20ffff);
+
+  // map Pico PS/2 Peripheral I/O
+  cpu68k_map_set(m68k_read8_map,   0x200000, 0x20ffff, PicoRead8_pico_kb, 1);
+  cpu68k_map_set(m68k_read16_map,  0x200000, 0x20ffff, PicoRead16_pico_kb, 1);
+  cpu68k_map_set(m68k_write8_map,  0x200000, 0x20ffff, PicoWrite8_pico_kb, 1);
+  cpu68k_map_set(m68k_write16_map, 0x200000, 0x20ffff, PicoWrite16_pico_kb, 1);
+}
index e2b540b..9ca71a2 100644 (file)
@@ -1142,6 +1142,9 @@ void run_events_pico(unsigned int events)
        }\r
        if (events & PEV_PICO_PAD) {\r
                if (pico_inp_mode == 2) {\r
+                       pico_inp_mode = (PicoPicohw.is_kb_active ? 3 : 0);\r
+                       emu_status_msg("Input: %s", pico_inp_mode ? "Keyboard" : "D-Pad");\r
+               } else if (pico_inp_mode == 3) {\r
                        pico_inp_mode = 0;\r
                        emu_status_msg("Input: D-Pad");\r
                } else {\r
@@ -1160,7 +1163,15 @@ void run_events_pico(unsigned int events)
                pico_inp_mode = 0;\r
                emu_status_msg("Input: D-Pad");\r
        }\r
-       if (pico_inp_mode == 0)\r
+       if (events & PEV_PICO_SWPS2) {\r
+               PicoPicohw.is_kb_active = !PicoPicohw.is_kb_active;\r
+               if (pico_inp_mode == 3) pico_inp_mode = 0;\r
+               emu_status_msg("Keyboard %sconnected", PicoPicohw.is_kb_active ? "" : "dis");\r
+       }\r
+\r
+       PicoPicohw.inp_mode = pico_inp_mode;\r
+\r
+       if (pico_inp_mode == 0 || pico_inp_mode == 3)\r
                return;\r
 \r
        /* handle other input modes */\r
@@ -1282,42 +1293,71 @@ void emu_update_input(void)
 {\r
        static int prev_events = 0;\r
        int actions[IN_BINDTYPE_COUNT] = { 0, };\r
+       int actions_pico_ps2[IN_BIND_LAST] = { 0, };\r
        int pl_actions[4];\r
        int events;\r
 \r
        in_update(actions);\r
+       in_update_pico_ps2(actions_pico_ps2);\r
+       PicoIn.ps2 = 0;\r
+       for (int i = 0; i < IN_BIND_LAST; i++) {\r
+               if (actions_pico_ps2[i]) {\r
+                       unsigned int action = actions_pico_ps2[i];\r
+                       if ((action & 0xff) == PEVB_PICO_PS2_LSHIFT) {\r
+                               PicoIn.ps2 = (PicoIn.ps2 & 0x00ff) | (action << 8);\r
+                       } else {\r
+                               PicoIn.ps2 = (PicoIn.ps2 & 0xff00) | action;\r
+                       }\r
+               }\r
+       }\r
 \r
        pl_actions[0] = actions[IN_BINDTYPE_PLAYER12];\r
        pl_actions[1] = actions[IN_BINDTYPE_PLAYER12] >> 16;\r
        pl_actions[2] = actions[IN_BINDTYPE_PLAYER34];\r
        pl_actions[3] = actions[IN_BINDTYPE_PLAYER34] >> 16;\r
 \r
-       PicoIn.pad[0] = pl_actions[0] & 0xfff;\r
-       PicoIn.pad[1] = pl_actions[1] & 0xfff;\r
-       PicoIn.pad[2] = pl_actions[2] & 0xfff;\r
-       PicoIn.pad[3] = pl_actions[3] & 0xfff;\r
-\r
-       if (pl_actions[0] & 0x7000)\r
-               do_turbo(&PicoIn.pad[0], pl_actions[0]);\r
-       if (pl_actions[1] & 0x7000)\r
-               do_turbo(&PicoIn.pad[1], pl_actions[1]);\r
-       if (pl_actions[2] & 0x7000)\r
-               do_turbo(&PicoIn.pad[2], pl_actions[2]);\r
-       if (pl_actions[3] & 0x7000)\r
-               do_turbo(&PicoIn.pad[3], pl_actions[3]);\r
-\r
        events = actions[IN_BINDTYPE_EMU] & PEV_MASK;\r
 \r
+       if (pico_inp_mode == 3) {\r
+               // FIXME: Only passthrough joystick input to avoid collisions\r
+               // with PS/2 bindings. Ideally we should check if the device this\r
+               // input originated from is the same as the device used for\r
+               // PS/2 input, and passthrough if they are different devices.\r
+               PicoIn.pad[0] = pl_actions[0] & 0xf;\r
+               PicoIn.pad[1] = pl_actions[1] & 0xf;\r
+               PicoIn.pad[2] = pl_actions[2] & 0xf;\r
+               PicoIn.pad[3] = pl_actions[3] & 0xf;\r
+\r
+               // Ignore events mapped to bindings that collide with PS/2 peripherals.\r
+               // Note that calls to emu_set_fastforward() should be avoided as well,\r
+               // since fast-forward activates even with parameter set_on = 0.\r
+               events &= ~PEV_MENU;\r
+       } else {\r
+               PicoIn.pad[0] = pl_actions[0] & 0xfff;\r
+               PicoIn.pad[1] = pl_actions[1] & 0xfff;\r
+               PicoIn.pad[2] = pl_actions[2] & 0xfff;\r
+               PicoIn.pad[3] = pl_actions[3] & 0xfff;\r
+\r
+               if (pl_actions[0] & 0x7000)\r
+                       do_turbo(&PicoIn.pad[0], pl_actions[0]);\r
+               if (pl_actions[1] & 0x7000)\r
+                       do_turbo(&PicoIn.pad[1], pl_actions[1]);\r
+               if (pl_actions[2] & 0x7000)\r
+                       do_turbo(&PicoIn.pad[2], pl_actions[2]);\r
+               if (pl_actions[3] & 0x7000)\r
+                       do_turbo(&PicoIn.pad[3], pl_actions[3]);\r
+\r
+               if ((events ^ prev_events) & PEV_FF) {\r
+                       emu_set_fastforward(events & PEV_FF);\r
+                       plat_update_volume(0, 0);\r
+                       reset_timing = 1;\r
+               }\r
+       }\r
+\r
        // volume is treated in special way and triggered every frame\r
        if (events & (PEV_VOL_DOWN|PEV_VOL_UP))\r
                plat_update_volume(1, events & PEV_VOL_UP);\r
 \r
-       if ((events ^ prev_events) & PEV_FF) {\r
-               emu_set_fastforward(events & PEV_FF);\r
-               plat_update_volume(0, 0);\r
-               reset_timing = 1;\r
-       }\r
-\r
        events &= ~prev_events;\r
 \r
        if (PicoIn.AHW == PAHW_PICO)\r
index 2f3de41..47d9554 100644 (file)
@@ -30,7 +30,8 @@
 #define PEVB_PICO_STORY 19
 #define PEVB_PICO_PAD   18
 #define PEVB_PICO_PENST 17
-#define PEVB_RESET      16
+#define PEVB_PICO_SWPS2 16
+#define PEVB_RESET      15
 
 #define PEV_VOL_DOWN    (1 << PEVB_VOL_DOWN)
 #define PEV_VOL_UP      (1 << PEVB_VOL_UP)
 #define PEV_PICO_STORY  (1 << PEVB_PICO_STORY)
 #define PEV_PICO_PAD    (1 << PEVB_PICO_PAD)
 #define PEV_PICO_PENST  (1 << PEVB_PICO_PENST)
+#define PEV_PICO_SWPS2  (1 << PEVB_PICO_SWPS2)
 #define PEV_RESET       (1 << PEVB_RESET)
 
-#define PEV_MASK 0x7fff0000
+#define PEV_MASK 0x7fff8000
+
+/* Keyboard Pico */
+
+// Blue buttons
+#define PEVB_PICO_PS2_SPACE 0x29
+#define PEVB_PICO_PS2_EXCLAIM 0
+#define PEVB_PICO_PS2_QUOTEDBL 0
+#define PEVB_PICO_PS2_HASH 0
+#define PEVB_PICO_PS2_DOLLAR 0
+#define PEVB_PICO_PS2_AMPERSAND 0
+#define PEVB_PICO_PS2_LEFTPAREN 0
+#define PEVB_PICO_PS2_RIGHTPAREN 0
+#define PEVB_PICO_PS2_ASTERISK 0x7c
+#define PEVB_PICO_PS2_PLUS 0x79
+#define PEVB_PICO_PS2_MINUS 0x4e
+#define PEVB_PICO_PS2_COMMA 0x41
+#define PEVB_PICO_PS2_PERIOD 0x49
+#define PEVB_PICO_PS2_SLASH 0x4a
+#define PEVB_PICO_PS2_1 0x16
+#define PEVB_PICO_PS2_2 0x1e
+#define PEVB_PICO_PS2_3 0x26
+#define PEVB_PICO_PS2_4 0x25
+#define PEVB_PICO_PS2_5 0x2e
+#define PEVB_PICO_PS2_6 0x36
+#define PEVB_PICO_PS2_7 0x3d
+#define PEVB_PICO_PS2_8 0x3e
+#define PEVB_PICO_PS2_9 0x46
+#define PEVB_PICO_PS2_0 0x45
+#define PEVB_PICO_PS2_COLON 0x52
+#define PEVB_PICO_PS2_SEMICOLON 0x4c
+#define PEVB_PICO_PS2_LESS 0
+#define PEVB_PICO_PS2_EQUALS 0x55
+#define PEVB_PICO_PS2_GREATER 0
+#define PEVB_PICO_PS2_QUESTION 0
+#define PEVB_PICO_PS2_AT 0
+#define PEVB_PICO_PS2_DAKUTEN 0x54 // ゛
+#define PEVB_PICO_PS2_LEFTBRACKET 0x5b
+#define PEVB_PICO_PS2_RIGHTBRACKET 0x5d
+#define PEVB_PICO_PS2_CARET 0
+#define PEVB_PICO_PS2_UNDERSCORE 0
+#define PEVB_PICO_PS2_YEN 0x6a // ¥
+#define PEVB_PICO_PS2_RO 0x51 // ろ
+#define PEVB_PICO_PS2_KE 0x52 // け
+
+#define PEVB_PICO_PS2_a 0x1c
+#define PEVB_PICO_PS2_b 0x32
+#define PEVB_PICO_PS2_c 0x21
+#define PEVB_PICO_PS2_d 0x23
+#define PEVB_PICO_PS2_e 0x24
+#define PEVB_PICO_PS2_f 0x2b
+#define PEVB_PICO_PS2_g 0x34
+#define PEVB_PICO_PS2_h 0x33
+#define PEVB_PICO_PS2_i 0x43
+#define PEVB_PICO_PS2_j 0x3b
+#define PEVB_PICO_PS2_k 0x42
+#define PEVB_PICO_PS2_l 0x4b
+#define PEVB_PICO_PS2_m 0x3a
+#define PEVB_PICO_PS2_n 0x31
+#define PEVB_PICO_PS2_o 0x44
+#define PEVB_PICO_PS2_p 0x4d
+#define PEVB_PICO_PS2_q 0x15
+#define PEVB_PICO_PS2_r 0x2d
+#define PEVB_PICO_PS2_s 0x1b
+#define PEVB_PICO_PS2_t 0x2c
+#define PEVB_PICO_PS2_u 0x3c
+#define PEVB_PICO_PS2_v 0x2a
+#define PEVB_PICO_PS2_w 0x1d
+#define PEVB_PICO_PS2_x 0x22
+#define PEVB_PICO_PS2_y 0x35
+#define PEVB_PICO_PS2_z 0x1a
+
+// Green button on top-left
+#define PEVB_PICO_PS2_ESCAPE 0x76
+
+// Orange buttons on left
+#define PEVB_PICO_PS2_CAPSLOCK 0x58
+#define PEVB_PICO_PS2_LSHIFT 0x12
+
+// Green buttons on right
+#define PEVB_PICO_PS2_BACKSPACE 0x66
+#define PEVB_PICO_PS2_INSERT 0x81
+#define PEVB_PICO_PS2_DELETE 0x85
+
+// Red button on bottom-right
+#define PEVB_PICO_PS2_RETURN 0x5a
+
+// Orange buttons on bottom
+#define PEVB_PICO_PS2_SOUND 0x67
+#define PEVB_PICO_PS2_HOME 0x64
+#define PEVB_PICO_PS2_CJK 0x13
+#define PEVB_PICO_PS2_ROMAJI 0x17
 
 #endif /* INCLUDE_c48097f3ff2a6a9af1cce8fd7a9b3f0c */
index 8fbb29f..022638d 100644 (file)
@@ -32,7 +32,101 @@ const struct in_default_bind _in_sdl_defbinds[] = {
        { SDLK_F8,     IN_BINDTYPE_EMU, PEVB_PICO_STORY },
        { SDLK_F9,     IN_BINDTYPE_EMU, PEVB_PICO_PAD },
        { SDLK_F10,    IN_BINDTYPE_EMU, PEVB_PICO_PENST },
+       { SDLK_F12,    IN_BINDTYPE_EMU, PEVB_PICO_SWPS2 },
        { SDLK_BACKSPACE, IN_BINDTYPE_EMU, PEVB_FF },
+
+       { 0, 0, 0 }
+};
+
+const struct in_default_bind in_sdl_pico_ps2_map[] = {
+       // Blue buttons
+       { SDLK_SPACE, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_SPACE },
+       { SDLK_EXCLAIM, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_EXCLAIM },
+       { SDLK_QUOTEDBL, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_QUOTEDBL },
+       { SDLK_HASH, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_HASH },
+       { SDLK_DOLLAR, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_DOLLAR },
+       { SDLK_AMPERSAND, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_AMPERSAND },
+       { SDLK_LEFTPAREN, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_LEFTPAREN },
+       { SDLK_RIGHTPAREN, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_RIGHTPAREN },
+       { SDLK_ASTERISK, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_ASTERISK },
+       { SDLK_PLUS, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_PLUS },
+       { SDLK_COMMA, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_COMMA },
+       { SDLK_MINUS, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_MINUS },
+       { SDLK_PERIOD, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_PERIOD },
+       { SDLK_SLASH, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_SLASH },
+       { SDLK_0, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_0 },
+       { SDLK_1, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_1 },
+       { SDLK_2, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_2 },
+       { SDLK_3, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_3 },
+       { SDLK_4, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_4 },
+       { SDLK_5, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_5 },
+       { SDLK_6, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_6 },
+       { SDLK_7, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_7 },
+       { SDLK_8, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_8 },
+       { SDLK_9, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_9 },
+       { SDLK_COLON, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_COLON },
+       { SDLK_SEMICOLON, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_SEMICOLON },
+       { SDLK_LESS, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_LESS },
+       { SDLK_EQUALS, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_EQUALS },
+       { SDLK_GREATER, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_GREATER },
+       { SDLK_QUESTION, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_QUESTION },
+       { SDLK_AT, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_AT },
+       { SDLK_BACKSLASH, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_DAKUTEN },
+       { SDLK_LEFTBRACKET, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_LEFTBRACKET },
+       { SDLK_RIGHTBRACKET, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_RIGHTBRACKET },
+       { SDLK_CARET, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_CARET },
+       { SDLK_UNDERSCORE, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_UNDERSCORE },
+       { SDLK_BACKQUOTE, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_YEN },
+       { SDLK_a, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_a },
+       { SDLK_b, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_b },
+       { SDLK_c, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_c },
+       { SDLK_d, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_d },
+       { SDLK_e, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_e },
+       { SDLK_f, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_f },
+       { SDLK_g, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_g },
+       { SDLK_h, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_h },
+       { SDLK_i, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_i },
+       { SDLK_j, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_j },
+       { SDLK_k, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_k },
+       { SDLK_l, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_l },
+       { SDLK_m, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_m },
+       { SDLK_n, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_n },
+       { SDLK_o, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_o },
+       { SDLK_p, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_p },
+       { SDLK_q, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_q },
+       { SDLK_r, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_r },
+       { SDLK_s, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_s },
+       { SDLK_t, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_t },
+       { SDLK_u, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_u },
+       { SDLK_v, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_v },
+       { SDLK_w, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_w },
+       { SDLK_x, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_x },
+       { SDLK_y, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_y },
+       { SDLK_z, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_z },
+       { SDLK_QUOTE, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_KE },
+       { SDLK_RSHIFT, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_RO },
+
+       // Green button on top-left
+       { SDLK_ESCAPE, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_ESCAPE },
+
+       // Orange buttons on left
+       { SDLK_LCTRL, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_CAPSLOCK }, // Also switches english input
+       { SDLK_LSHIFT, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_LSHIFT },
+
+       // Green buttons on right
+       { SDLK_BACKSPACE, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_BACKSPACE },
+       { SDLK_INSERT, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_INSERT },
+       { SDLK_DELETE, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_DELETE },
+
+       // Red button on bottom-right
+       { SDLK_RETURN, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_RETURN },
+
+       // Orange buttons on bottom
+       { SDLK_END, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_SOUND },
+       { SDLK_HOME, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_HOME },
+       { SDLK_PAGEUP, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_CJK }, // CJK Scripts: Hiragana / Katakana / Kanji (Keyboard Pico); Hangul (Kibodeu Piko)
+       { SDLK_PAGEDOWN, IN_BINDTYPE_PICO_PS2, PEVB_PICO_PS2_ROMAJI }, // English Script
+
        { 0, 0, 0 }
 };
 const struct in_default_bind *in_sdl_defbinds = _in_sdl_defbinds;
index 70e18b4..78342c0 100644 (file)
@@ -375,6 +375,7 @@ me_bind_action emuctrl_actions[] =
        { "Pico Storyware ", PEV_PICO_STORY },
        { "Pico Pad       ", PEV_PICO_PAD },
        { "Pico Pen state ", PEV_PICO_PENST },
+       { "Pico Keyboard  ", PEV_PICO_SWPS2 },
        { NULL,                0 }
 };
 
index 8ba3a8c..7a9d6b9 100644 (file)
@@ -511,6 +511,7 @@ void plat_init(void)
        in_sdl_platform_data.jmap_size = in_sdl_joy_map_sz,
        in_sdl_platform_data.joy_map = in_sdl_joy_map,
        in_sdl_platform_data.key_names = in_sdl_key_names,
+       in_sdl_platform_data.pico_ps2_map = in_sdl_pico_ps2_map,
        in_sdl_init(&in_sdl_platform_data, plat_sdl_event_handler);
        in_probe();
 
index cecdb2b..13f7d0c 100644 (file)
@@ -6,5 +6,6 @@ extern const struct menu_keymap *in_sdl_joy_map;
 extern const int in_sdl_joy_map_sz;
 extern const char * const *in_sdl_key_names;
 extern const char *plat_device;
+extern const struct in_default_bind in_sdl_pico_ps2_map[];
 
 void linux_menu_init(void);
index 86a086e..b047d2e 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 86a086ed64aadc1e87fc58a90703a07d91c9cdbe
+Subproject commit b047d2e2e6375b5fad2f1b716616a536f7b56dc2