Replace printf/fprintf with own print_info() / print_error() using SDL_log
[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 "../libsdl/print.h"
24 #include "keyboard.h"
25
26 //#define DEBUG_KEYS
27
28 /* stolen from UAE */
29 static struct keycodes {
30         const char *key;
31         uint8_t code;
32 } keycodes[] = {
33         { "A", 0x20 }, { "B", 0x35 }, { "C", 0x33 }, { "D", 0x22 },
34         { "E", 0x12 }, { "F", 0x23 }, { "G", 0x24 }, { "H", 0x25 },
35         { "I", 0x17 }, { "J", 0x26 }, { "K", 0x27 }, { "L", 0x28 },
36         { "M", 0x37 }, { "N", 0x36 }, { "O", 0x18 }, { "P", 0x19 },
37         { "Q", 0x10 }, { "R", 0x13 }, { "S", 0x21 }, { "T", 0x14 },
38         { "U", 0x16 }, { "V", 0x34 }, { "W", 0x11 }, { "X", 0x32 },
39         { "Y", 0x15 }, { "Z", 0x31 },
40
41         { "0", 0x0A }, { "1", 0x01 }, { "2", 0x02 }, { "3", 0x03 },
42         { "4", 0x04 }, { "5", 0x05 }, { "6", 0x06 }, { "7", 0x07 },
43         { "8", 0x08 }, { "9", 0x09 },
44
45         { "NP0", 0x0F }, { "NP1", 0x1D }, { "NP2", 0x1E }, { "NP3", 0x1F },
46         { "NP4", 0x2D }, { "NP5", 0x2E }, { "NP6", 0x2F }, { "NP7", 0x3D },
47         { "NP8", 0x3E }, { "NP9", 0x3F },
48
49         { "NPDIV", 0x5C }, { "NPMUL", 0x5D }, { "NPSUB", 0x4A },
50         { "NPADD", 0x5E }, { "NPDEL", 0x3C }, { "NPLPAREN", 0x5A },
51         { "NPRPAREN", 0x5B },
52
53         { "F1", 0x50 }, { "F2", 0x51 }, { "F3", 0x52 }, { "F4", 0x53 },
54         { "F5", 0x54 }, { "F6", 0x55 }, { "F7", 0x56 }, { "F8", 0x57 },
55         { "F9", 0x58 }, { "F10", 0x59 },
56
57         { "UP", 0x4C }, { "DN", 0x4D }, { "LF", 0x4F }, { "RT", 0x4E },
58
59         { "SPC", 0x40 }, { "BS", 0x41 }, { "TAB", 0x42 }, { "ENT", 0x43 },
60         { "RET", 0x44 }, { "ESC", 0x45 }, { "DEL", 0x46 },
61
62         { "LSH", 0x60 }, { "RSH", 0x61 }, { "CAPSLOCK", 0x62 },
63         { "CTRL", 0x63 }, { "LALT", 0x64 }, { "RALT", 0x65 }, { "LAMI", 0x66 },
64         { "RAMI", 0x67 }, { "HELP", 0x5F },
65
66         { "LBRACKET", 0x1A }, { "RBRACKET", 0x1B }, { "SEMICOLON", 0x29 },
67         { "COMMA", 0x38 }, { "PERIOD", 0x39 }, { "SLASH", 0x3A },
68         { "BACKSLASH", 0x0D }, { "QUOTE", 0x2A }, { "NUMBERSIGN", 0x2B },
69         { "LTGT", 0x30 }, { "BACKQUOTE", 0x00 }, { "MINUS", 0x0B },
70         { "EQUAL", 0x0C },
71
72         { NULL, 0 },
73 };
74
75 static uint8_t buffer[16];
76 static int buffer_size = sizeof(buffer), buffer_len = 0;
77 static uint32_t keydown[4] = {0, 0, 0, 0};
78
79 #define ROL(v)          ((v << 1) | (v >> 7))
80
81 #define CIAASDR         0xbfec00
82 #define CIAAICR         0xbfed00
83 #define CIAACRA         0xbfee00
84
85 uint16_t emulate_keyboard_read(uint32_t address)
86 {
87         uint8_t value;
88         int i;
89
90         switch (address) {
91         case CIAAICR:
92                 if (buffer_len)
93                         return 0xff08;
94                 return 0xff00;
95         case CIAASDR:
96                 if (buffer_len == 0)
97                         return 0xffff;
98                 value = buffer[--buffer_len];
99                 /* rotate and negate */
100                 value = ~ROL(value);
101 #ifdef DEBUG_KEYS
102                 printf("sending key code %02x\n", buffer[buffer_len]);
103 #endif
104                 for (i = 0; i < buffer_len; i++)
105                         buffer[i] = buffer[i + 1];
106                 return 0xff00 | value;
107         }
108
109         return 0xffff;
110 }
111
112 void set_key(const char *key, int down)
113 {
114         int code = -1, isdown;
115         int i;
116
117         for (i = 0; keycodes[i].key; i++) {
118                 if (!strcmp(keycodes[i].key, key)) {
119                         code = keycodes[i].code;
120                         break;
121                 }
122         }
123         if (code < 0 || code >= 0x80) {
124                 print_error("Key code '%s' unknown, please fix!\n", key);
125                 return;
126         }
127
128         isdown = (keydown[code >> 5] >> (code & 0x1f)) & 1;
129         if (down) {
130                 if (isdown) {
131 //                      printf("key already down\n");
132                         return;
133                 }
134                 keydown[code >> 5] |= (1 << (code & 0x1f));
135         } else {
136                 if (!isdown) {
137 //                      printf("key already up\n");
138                         return;
139                 }
140                 keydown[code >> 5] &= ~(1 << (code & 0x1f));
141                 code |= 0x80;
142         }
143
144         if (buffer_len == buffer_size) {
145                 print_error("keyboard buffer overflow\n");
146                 return;
147         }
148
149         buffer[buffer_len++] = code;
150 #ifdef DEBUG_KEYS
151         printf("Converting key '%s' to code 0x%02x\n", key, code);
152 #endif
153 }
154
155