actually use ring buffer in hw_keyboard.c
[dcpu16] / hw_keyboard.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4
5 #ifdef HAVE_LIBVNCSERVER
6 #include <rfb/rfb.h>
7 #include <rfb/keysym.h>
8 #endif /* HAVE_LIBVNCSERVER */
9
10 #include "dcpu16.h"
11 #include "hw_keyboard.h"
12
13 #define BUF_SZ 32
14
15 static dcpu16_hw_signal_t keyboard_reset_;
16 static dcpu16_hw_signal_t keyboard_cycle_;
17 static dcpu16_hw_signal_t keyboard_hwi_;
18 static struct dcpu16_hw hw_ = {
19 .vm = NULL,
20 .name_ = "Generic Keyboard (compatible)",
21 .id_l = 0x7406,
22 .id_h = 0x30cf,
23 .ver = 0x0001,
24 .mfg_l = 0x0000,
25 .mfg_h = 0x0000,
26 .hwi = keyboard_hwi_,
27 .cycle = keyboard_cycle_,
28 .reset = keyboard_reset_,
29 .data = (struct keyboard_ *)NULL
30 };
31
32 struct keyboard_ {
33 char *buf;
34 size_t buf_sz;
35 size_t buf_head;
36 size_t buf_tail;
37 DCPU16_WORD interrupt_message;
38 unsigned char keys_pressed[256];
39 };
40
41 #ifdef HAVE_LIBVNCSERVER
42
43 static const struct keysym_map_ {
44 unsigned int rfb_start;
45 unsigned int rfb_end;
46 DCPU16_WORD dcpu_start;
47 } keymap_[] = {
48 { XK_space, XK_asciitilde, 0x20 }, /* ASCII range */
49 { XK_Delete, XK_Delete, 0x7f }, /* ASCII del */
50 { XK_BackSpace, XK_BackSpace, 0x10 }, /* bs */
51 { XK_Return, XK_Return, 0x11 }, /* ret */
52 { XK_Insert, XK_Insert, 0x12 }, /* ins */
53 { XK_Delete, XK_Delete, 0x13 }, /* del */
54 { XK_Up, XK_Up, 0x80 }, /* arrow up */
55 { XK_Down, XK_Down, 0x81 }, /* arrow down */
56 { XK_Left, XK_Left, 0x82 }, /* arrow left */
57 { XK_Right, XK_Right, 0x83 }, /* arrow right */
58 { XK_Shift_L, XK_Shift_R, 0x90 }, /* shift range */
59 { XK_Control_L, XK_Control_R, 0x91 }, /* control range */
60 { 0, 0, 0x0 }
61 };
62
63 static int keysym_rfbtodcpu(unsigned int rfb, DCPU16_WORD *dcpu) {
64 const struct keysym_map_ *map;
65
66 for (map = keymap_; map->rfb_start; map++) {
67 if (rfb >= map->rfb_start
68 && rfb <= map->rfb_end) {
69 *dcpu = (map->dcpu_start + (rfb - map->rfb_start));
70 return 0;
71 }
72 }
73
74 *dcpu = 0x00;
75 return -1;
76 }
77
78 static
79 void keyboard_rfbevent_(rfbBool down, rfbKeySym key, rfbClientPtr cl) {
80 DCPU16_WORD dcpu_key;
81 struct dcpu16_hw *hw = (struct dcpu16_hw *)cl->screen->screenData;
82 struct keyboard_ *keyboard = (struct keyboard_ *)hw->data;
83
84 keysym_rfbtodcpu(key, &dcpu_key);
85
86 fprintf(stderr, "%s: down:%u key:0x%04x dcpu_key:0x%04x\n", __func__,
87 down, key, dcpu_key);
88
89 fprintf(stderr, "%s: hw:%p name:%s vm:%p\n", __func__, hw, hw->name_, hw->vm);
90
91 keyboard->keys_pressed[dcpu_key] = (down ? 1 : 0);
92 if (down) {
93 if ((keyboard->buf_tail + 1) % keyboard->buf_sz == keyboard->buf_head) {
94 hw->vm->warn_cb_("keyboard buffer overflow");
95 return;
96 }
97 keyboard->buf[keyboard->buf_tail] = dcpu_key;
98 keyboard->buf_tail += 1;
99 keyboard->buf_tail %= keyboard->buf_sz;
100 }
101 if (keyboard->interrupt_message) {
102 dcpu16_interrupt(hw->vm, keyboard->interrupt_message);
103 }
104 }
105
106 void keyboard_vnc_associate(struct dcpu16_hw *hw, rfbScreenInfoPtr rfbScreen) {
107 rfbScreen->screenData = hw;
108 rfbScreen->kbdAddEvent = keyboard_rfbevent_;
109 }
110 #endif /* HAVE_LIBVNCSERVER */
111
112 static
113 void keyboard_reset_(struct dcpu16 *vm, void *data) {
114 struct keyboard_ *keyboard = (struct keyboard_ *)data;
115
116 (void)vm;
117
118 keyboard->interrupt_message = 0;
119 memset(keyboard->buf, 0, keyboard->buf_sz);
120 }
121
122 static
123 void keyboard_cycle_(struct dcpu16 *vm, void *data) {
124 struct keyboard_ *keyboard = (struct keyboard_ *)data;
125
126 (void)vm, (void)keyboard;
127 }
128
129 static
130 void keyboard_hwi_(struct dcpu16 *vm, void *data) {
131 struct keyboard_ *keyboard = (struct keyboard_ *)data;
132 DCPU16_WORD reg_a = vm->reg[DCPU16_REG_A];
133 DCPU16_WORD reg_b = vm->reg[DCPU16_REG_B];
134
135 switch (reg_a) {
136 case 0: /* clear keyboard buffer */
137 memset(keyboard->buf, 0, keyboard->buf_sz);
138 keyboard->buf_head = 0;
139 keyboard->buf_tail = 0;
140 break;
141
142 case 1: /* get next key from buffer as C */
143 if (keyboard->buf_head == keyboard->buf_tail)
144 break;
145 vm->reg[DCPU16_REG_C] = keyboard->buf[keyboard->buf_head];
146 keyboard->buf_head += 1;
147 keyboard->buf_head %= keyboard->buf_sz;
148 break;
149
150 case 2: /* get currently-pressed-state of key in B as C */
151 vm->reg[DCPU16_REG_C] = keyboard->keys_pressed[reg_b & 0x00ff];
152 break;
153
154 case 3: /* set interrupt state */
155 keyboard->interrupt_message = reg_b;
156 break;
157
158 }
159 }
160
161 struct dcpu16_hw *keyboard_new(struct dcpu16 *vm) {
162 struct dcpu16_hw *hw;
163 char *b;
164
165 hw = calloc(1, sizeof *hw);
166 if (hw == NULL) {
167 vm->warn_cb_("%s():%s", "calloc", strerror(errno));
168 return NULL;
169 }
170 memcpy(hw, &hw_, sizeof *hw);
171 hw->data = calloc(1, sizeof hw->data);
172 if (hw->data == NULL) {
173 vm->warn_cb_("%s():%s", "calloc", strerror(errno));
174 free(hw);
175 return NULL;
176 }
177
178 b = calloc(BUF_SZ, sizeof *b);
179 if (b == NULL) {
180 vm->warn_cb_("%s():%s", "calloc", strerror(errno));
181 free(hw->data);
182 free(hw);
183 return NULL;
184 }
185 ((struct keyboard_ *)(hw->data))->buf = b;
186 ((struct keyboard_ *)(hw->data))->buf_sz = BUF_SZ;
187
188 hw->vm = vm;
189
190 return hw;
191 }
192
193 void keyboard_del(struct dcpu16_hw **hw) {
194 if (hw) {
195 free(((struct keyboard_ *)((*hw)->data))->buf);
196 ((struct keyboard_ *)((*hw)->data))->buf = NULL;
197
198 free((*hw)->data);
199 (*hw)->data = NULL;
200
201 free(*hw);
202 *hw = NULL;
203 }
204 }