No more borders at OpenGL rendering, if window has different aspect ratio than 1...
[mercenary-reloaded.git] / src / libkeyboard / keyboard.c
1 /* keyboard emulation
2  *
3  * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
4  * All Rights Reserved
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <stdio.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include "../../include/keycodes.h"
24 #include "../libsdl/print.h"
25 #include "keyboard.h"
26
27 //#define DEBUG_KEYS
28
29 /* stolen from UAE */
30 static struct keycodes {
31         enum keycode key;
32         uint8_t code;
33 } keycodes[] = {
34         { KEYCODE_a, 0x20 },
35         { KEYCODE_b, 0x35 },
36         { KEYCODE_c, 0x33 },
37         { KEYCODE_d, 0x22 },
38         { KEYCODE_e, 0x12 },
39         { KEYCODE_f, 0x23 },
40         { KEYCODE_g, 0x24 },
41         { KEYCODE_h, 0x25 },
42         { KEYCODE_i, 0x17 },
43         { KEYCODE_j, 0x26 },
44         { KEYCODE_k, 0x27 },
45         { KEYCODE_l, 0x28 },
46         { KEYCODE_m, 0x37 },
47         { KEYCODE_n, 0x36 },
48         { KEYCODE_o, 0x18 },
49         { KEYCODE_p, 0x19 },
50         { KEYCODE_q, 0x10 },
51         { KEYCODE_r, 0x13 },
52         { KEYCODE_s, 0x21 },
53         { KEYCODE_t, 0x14 },
54         { KEYCODE_u, 0x16 },
55         { KEYCODE_v, 0x34 },
56         { KEYCODE_w, 0x11 },
57         { KEYCODE_x, 0x32 },
58         { KEYCODE_y, 0x15 },
59         { KEYCODE_z, 0x31 },
60
61         { KEYCODE_0, 0x0A },
62         { KEYCODE_1, 0x01 },
63         { KEYCODE_2, 0x02 },
64         { KEYCODE_3, 0x03 },
65         { KEYCODE_4, 0x04 },
66         { KEYCODE_5, 0x05 },
67         { KEYCODE_6, 0x06 },
68         { KEYCODE_7, 0x07 },
69         { KEYCODE_8, 0x08 },
70         { KEYCODE_9, 0x09 },
71
72         { KEYCODE_KP_0, 0x0F },
73         { KEYCODE_KP_1, 0x1D },
74         { KEYCODE_KP_2, 0x1E },
75         { KEYCODE_KP_3, 0x1F },
76         { KEYCODE_KP_4, 0x2D },
77         { KEYCODE_KP_5, 0x2E },
78         { KEYCODE_KP_6, 0x2F },
79         { KEYCODE_KP_7, 0x3D },
80         { KEYCODE_KP_8, 0x3E },
81         { KEYCODE_KP_9, 0x3F },
82
83         { KEYCODE_KP_DIVIDE, 0x5C },
84         { KEYCODE_KP_MULTIPLY, 0x5D },
85         { KEYCODE_KP_MINUS, 0x4A },
86         { KEYCODE_KP_PLUS, 0x5E },
87         { KEYCODE_KP_PERIOD, 0x3C },
88         { KEYCODE_KP_ENTER, 0x43 },
89         { KEYCODE_KP_LPAREN, 0x5A },
90         { KEYCODE_KP_RPAREN, 0x5B },
91
92         { KEYCODE_F1, 0x50 },
93         { KEYCODE_F2, 0x51 },
94         { KEYCODE_F3, 0x52 },
95         { KEYCODE_F4, 0x53 },
96         { KEYCODE_F5, 0x54 },
97         { KEYCODE_F6, 0x55 },
98         { KEYCODE_F7, 0x56 },
99         { KEYCODE_F8, 0x57 },
100         { KEYCODE_F9, 0x58 },
101         { KEYCODE_F10, 0x59 },
102
103         { KEYCODE_UP, 0x4C },
104         { KEYCODE_DOWN, 0x4D },
105         { KEYCODE_LEFT, 0x4F },
106         { KEYCODE_RIGHT, 0x4E },
107
108         { KEYCODE_SPACE, 0x40 },
109         { KEYCODE_BACKSPACE, 0x41 },
110         { KEYCODE_TAB, 0x42 },
111         { KEYCODE_RETURN, 0x44 },
112         { KEYCODE_ESCAPE, 0x45 },
113         { KEYCODE_DELETE, 0x46 },
114
115         { KEYCODE_LSHIFT, 0x60 },
116         { KEYCODE_RSHIFT, 0x61 },
117         { KEYCODE_CAPSLOCK, 0x62 },
118         { KEYCODE_LCTRL, 0x63 },
119         { KEYCODE_RCTRL, 0x63 },
120         { KEYCODE_LALT, 0x64 },
121         { KEYCODE_RALT, 0x65 },
122         { KEYCODE_LAMIGA, 0x66 },
123         { KEYCODE_RAMIGA, 0x67 },
124         { KEYCODE_HELP, 0x5F },
125
126         { KEYCODE_LBRACKET, 0x1A },
127         { KEYCODE_RBRACKET, 0x1B },
128         { KEYCODE_SEMICOLON, 0x29 },
129         { KEYCODE_COMMA, 0x38 },
130         { KEYCODE_PERIOD, 0x39 },
131         { KEYCODE_SLASH, 0x3A },
132         { KEYCODE_BACKSLASH, 0x0D },
133         { KEYCODE_QUOTE, 0x2A },
134         { KEYCODE_NUMBERSIGN, 0x2B },
135         { KEYCODE_LTGT, 0x30 },
136         { KEYCODE_BACKQUOTE, 0x00 },
137         { KEYCODE_MINUS, 0x0B },
138         { KEYCODE_EQUAL, 0x0C },
139
140         { KEYCODE_UNDEFINED, 0xff },
141 };
142
143 static uint8_t buffer[16];
144 static int buffer_size = sizeof(buffer), buffer_len = 0;
145 static uint32_t keydown[4] = {0, 0, 0, 0};
146
147 #define ROL(v)          ((v << 1) | (v >> 7))
148
149 #define CIAASDR         0xbfec00
150 #define CIAAICR         0xbfed00
151 #define CIAACRA         0xbfee00
152
153 uint16_t emulate_keyboard_read(uint32_t address)
154 {
155         uint8_t value;
156         int i;
157
158         switch (address) {
159         case CIAAICR:
160                 if (buffer_len)
161                         return 0xff08;
162                 return 0xff00;
163         case CIAASDR:
164                 if (buffer_len == 0)
165                         return 0xffff;
166                 value = buffer[0];
167 #ifdef DEBUG_KEYS
168                 printf("sending amiga code 0x%02x\n", value);
169 #endif
170                 /* rotate and negate */
171                 value = ~ROL(value);
172                 /* remove first entry from buffer */
173                 buffer_len--;
174                 for (i = 0; i < buffer_len; i++)
175                         buffer[i] = buffer[i + 1];
176                 return 0xff00 | value;
177         }
178
179         return 0xffff;
180 }
181
182 /* schedule given key to queue,
183  * down == 0: up
184  * down == 1: down
185  */
186 void set_amiga_key(enum keycode key, int down)
187 {
188         int code = -1, isdown;
189         int i;
190
191         for (i = 0; keycodes[i].key != KEYCODE_UNDEFINED; i++) {
192                 if (keycodes[i].key == key) {
193                         code = keycodes[i].code;
194                         break;
195                 }
196         }
197         if (code < 0 || code >= 0x80) {
198 #ifdef DEBUG_KEYS
199                 printf("Key code '%d' unknown, ignoring!\n", key);
200 #endif
201                 return;
202         }
203
204         isdown = (keydown[code >> 5] >> (code & 0x1f)) & 1;
205         if (down) {
206                 if (isdown) {
207 //                      printf("key already down\n");
208                         return;
209                 }
210                 keydown[code >> 5] |= (1 << (code & 0x1f));
211         } else {
212                 if (!isdown) {
213 //                      printf("key already up\n");
214                         return;
215                 }
216                 keydown[code >> 5] &= ~(1 << (code & 0x1f));
217                 code |= 0x80;
218         }
219
220         if (buffer_len == buffer_size) {
221                 print_info("keyboard buffer overflow\n");
222                 return;
223         }
224
225         buffer[buffer_len++] = code;
226 #ifdef DEBUG_KEYS
227         printf("Converting keycode %d to amiga code 0x%02x\n", key, code);
228 #endif
229 }
230
231