Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
input_devices.c
Go to the documentation of this file.
1 /* The Xemu project.
2  Copyright (C)2016-2019 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
3 
4  This is the Commander X16 emulation. Note: the source is overcrowded with comments by intent :)
5  That it can useful for other people as well, or someone wants to contribute, etc ...
6 
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
20 
21 #include "xemu/emutools.h"
22 #include "xemu/emutools_hid.h"
23 #include "input_devices.h"
24 #include "commander_x16.h"
25 #include <string.h>
26 
27 struct ps2_keymap_st {
28  SDL_Scancode key;
29  int ps2_code; // + 0x100 for extended codes
30 };
31 
32 // This table is taken from Mist's X16 emulator, but converted into a table
33 // >0xFF codes are extended keys (and only the low byte should be treated then as the PS/2 keycode)
34 static const struct ps2_keymap_st ps2_keymap[] = {
35  {SDL_SCANCODE_GRAVE, 0x0e}, {SDL_SCANCODE_BACKSPACE, 0x66}, {SDL_SCANCODE_TAB, 0xd}, {SDL_SCANCODE_CLEAR, 0}, {SDL_SCANCODE_RETURN, 0x5a},
36  {SDL_SCANCODE_PAUSE, 0}, {SDL_SCANCODE_ESCAPE, 0x76}, {SDL_SCANCODE_SPACE, 0x29}, {SDL_SCANCODE_APOSTROPHE, 0x52}, {SDL_SCANCODE_COMMA, 0x41},
37  {SDL_SCANCODE_MINUS, 0x4e}, {SDL_SCANCODE_PERIOD, 0x49}, {SDL_SCANCODE_SLASH, 0x4a}, {SDL_SCANCODE_0, 0x45}, {SDL_SCANCODE_1, 0x16},
38  {SDL_SCANCODE_2, 0x1e}, {SDL_SCANCODE_3, 0x26}, {SDL_SCANCODE_4, 0x25}, {SDL_SCANCODE_5, 0x2e}, {SDL_SCANCODE_6, 0x36},
39  {SDL_SCANCODE_7, 0x3d}, {SDL_SCANCODE_8, 0x3e}, {SDL_SCANCODE_9, 0x46}, {SDL_SCANCODE_SEMICOLON, 0x4c}, {SDL_SCANCODE_EQUALS, 0x55},
40  {SDL_SCANCODE_LEFTBRACKET, 0x54}, {SDL_SCANCODE_BACKSLASH, 0x5d}, {SDL_SCANCODE_RIGHTBRACKET, 0x5b}, {SDL_SCANCODE_A, 0x1c}, {SDL_SCANCODE_B, 0x32},
41  {SDL_SCANCODE_C, 0x21}, {SDL_SCANCODE_D, 0x23}, {SDL_SCANCODE_E, 0x24}, {SDL_SCANCODE_F, 0x2b}, {SDL_SCANCODE_G, 0x34},
42  {SDL_SCANCODE_H, 0x33}, {SDL_SCANCODE_I, 0x43}, {SDL_SCANCODE_J, 0x3B}, {SDL_SCANCODE_K, 0x42}, {SDL_SCANCODE_L, 0x4B},
43  {SDL_SCANCODE_M, 0x3A}, {SDL_SCANCODE_N, 0x31}, {SDL_SCANCODE_O, 0x44}, {SDL_SCANCODE_P, 0x4D}, {SDL_SCANCODE_Q, 0x15},
44  {SDL_SCANCODE_R, 0x2D}, {SDL_SCANCODE_S, 0x1B}, {SDL_SCANCODE_T, 0x2C}, {SDL_SCANCODE_U, 0x3C}, {SDL_SCANCODE_V, 0x2A},
45  {SDL_SCANCODE_W, 0x1D}, {SDL_SCANCODE_X, 0x22}, {SDL_SCANCODE_Y, 0x35}, {SDL_SCANCODE_Z, 0x1A}, {SDL_SCANCODE_DELETE, 0},
46  {SDL_SCANCODE_UP, 0x175}, {SDL_SCANCODE_DOWN, 0x172}, {SDL_SCANCODE_RIGHT, 0x174}, {SDL_SCANCODE_LEFT, 0x16b}, {SDL_SCANCODE_INSERT, 0},
47  {SDL_SCANCODE_HOME, 0x16c}, {SDL_SCANCODE_END, 0}, {SDL_SCANCODE_PAGEUP, 0}, {SDL_SCANCODE_PAGEDOWN, 0}, {SDL_SCANCODE_F1, 0x05},
48  {SDL_SCANCODE_F2, 0x06}, {SDL_SCANCODE_F3, 0x04}, {SDL_SCANCODE_F4, 0x0c}, {SDL_SCANCODE_F5, 0x03}, {SDL_SCANCODE_F6, 0x0b},
49  {SDL_SCANCODE_F7, 0x83}, {SDL_SCANCODE_F8, 0x0a}, {SDL_SCANCODE_F9, 0x01}, {SDL_SCANCODE_F10, 0x09}, {SDL_SCANCODE_F11, 0x78},
50  {SDL_SCANCODE_F12, 0x07}, {SDL_SCANCODE_RSHIFT, 0x59}, {SDL_SCANCODE_LSHIFT, 0x12}, {SDL_SCANCODE_LCTRL, 0x14}, {SDL_SCANCODE_RCTRL, 0x114},
51  {SDL_SCANCODE_LALT, 0x11}, {SDL_SCANCODE_RALT, 0x111}, {SDL_SCANCODE_NONUSBACKSLASH, 0x61}, {SDL_SCANCODE_KP_ENTER, 0x15a}, {SDL_SCANCODE_KP_0, 0x70},
52  {SDL_SCANCODE_KP_1, 0x69}, {SDL_SCANCODE_KP_2, 0x72}, {SDL_SCANCODE_KP_3, 0x7a}, {SDL_SCANCODE_KP_4, 0x6b}, {SDL_SCANCODE_KP_5, 0x73},
53  {SDL_SCANCODE_KP_6, 0x74}, {SDL_SCANCODE_KP_7, 0x6c}, {SDL_SCANCODE_KP_8, 0x75}, {SDL_SCANCODE_KP_9, 0x7d}, {SDL_SCANCODE_KP_PERIOD, 0x71},
54  {SDL_SCANCODE_KP_PLUS, 0x79}, {SDL_SCANCODE_KP_MINUS, 0x7b}, {SDL_SCANCODE_KP_MULTIPLY, 0x7c}, {SDL_SCANCODE_KP_DIVIDE, 0x14a}, {0, -1}
55 };
56 
57 void clear_emu_events ( void )
58 {
60 }
61 
62 
63 
64 
65 
66 static Uint8 ps2_stream[128];
67 static int ps2_stream_w_pos = 0;
68 static Uint64 virt_cycle_last_read;
69 
70 
71 int read_ps2_port ( void )
72 {
73  static int clk = 2;
74  static int data = 1;
75  if (ps2_stream_w_pos) {
76  Uint64 since = all_virt_cycles - virt_cycle_last_read;
77  // This is BAD, since actually the keyboard sends data the CPU takes care or not, it won't "pause" just because PS/2 lines are not checked ...
78  if (since > 333) {
79  virt_cycle_last_read = all_virt_cycles;
80  //while (since > 333 && ps2_stream_w_pos) {
81  clk ^= 2;
82  if (!clk) {
83  data = ps2_stream[0];
84  memmove(ps2_stream, ps2_stream + 1, --ps2_stream_w_pos);
85  }
86  // since -= 333;
87  //}
88  }
89  } else {
90  clk = 2;
91  data = 1;
92  }
93  return clk | data;
94 }
95 
96 
97 static void queue_ps2_device_packet ( Uint8 data )
98 {
99  //DEBUGPRINT("PS2: queuing protocol byte $%02X" NL, data);
100  ps2_stream[ps2_stream_w_pos++] = 0; // start bit, always zero
101  int parity = 1; // odd parity, we start with '1'.
102  for (int a = 0; a < 8; a++, data >>=1 ) {
103  ps2_stream[ps2_stream_w_pos++] = (data & 1);
104  if ((data & 1))
105  parity ^= 1;
106  }
107  ps2_stream[ps2_stream_w_pos++] = parity;
108  ps2_stream[ps2_stream_w_pos++] = 1; // stop bit, always one
109 }
110 
111 
112 static XEMU_INLINE void emit_ps2_event ( SDL_Scancode key, int pressed )
113 {
114  const struct ps2_keymap_st *p = ps2_keymap;
115  while (p->ps2_code >= 0)
116  if (key == p->key) {
117  if (ps2_stream_w_pos < sizeof(ps2_stream) - 12 * 3) {
118  int ps2 = p->ps2_code;
119  //fprintf(stderr, "FOUND KEY: SDL=%d PS2=%d PRESSED=%s\n", p->key, ps2, pressed ? "pressed" : "released");
120  if (ps2 >= 0x100)
121  queue_ps2_device_packet(0xE0); // extended key, emit E0
122  if (!pressed)
123  queue_ps2_device_packet(0xF0); // "break" code, ie, release of a key
124  queue_ps2_device_packet(ps2 & 0xFF);
125  } else
126  DEBUGPRINT("PS2: protocol stream is full :-(" NL);
127  return;
128  } else
129  p++;
130  //DEBUGPRINT("PS2: KEY NOT FOUND SDL=%d PRESSED=%s" NL, key, pressed ? "pressed" : "released");
131 }
132 
133 
134 // HID needs this to be defined, it's up to the emulator if it uses or not ...
135 // NOTE: Commander X16 is a special case, as it's not matrix based with keyboard implementation.
136 // Thus, we skip the matrix stuff more or less, and use the callback of the HID subsystem to
137 // inject the emulated PS/2 sequences then. We want to use some queue anyway ...
138 int emu_callback_key ( int pos, SDL_Scancode key, int pressed, int handled )
139 {
140 /* DEBUGPRINT("KEY EVENT: pos=%d scancode=%d pressed=%d handled=%d" NL,
141  pos, key, pressed, handled
142  );*/
143  if (pos == -1 && handled == 0)
144  emit_ps2_event(key, pressed);
145  return 0;
146 }
commander_x16.h
ps2_keymap_st::key
SDL_Scancode key
Definition: input_devices.c:28
emutools.h
ps2_keymap_st
Definition: input_devices.c:27
XEMU_INLINE
#define XEMU_INLINE
Definition: emutools_basicdefs.h:126
m65-memcontent-generator.data
data
Definition: m65-memcontent-generator.py:119
read_ps2_port
int read_ps2_port(void)
Definition: input_devices.c:71
hid_reset_events
void hid_reset_events(int burn)
Definition: emutools_hid.c:170
Uint8
uint8_t Uint8
Definition: fat32.c:51
ps2_keymap_st::ps2_code
int ps2_code
Definition: input_devices.c:29
emu_callback_key
int emu_callback_key(int pos, SDL_Scancode key, int pressed, int handled)
Definition: input_devices.c:138
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
clear_emu_events
void clear_emu_events(void)
Definition: input_devices.c:57
input_devices.h
NL
#define NL
Definition: fat32.c:37
emutools_hid.h
all_virt_cycles
Uint64 all_virt_cycles
Definition: commander_x16.c:277