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