5 #ifdef HAVE_LIBVNCSERVER
7 #include <rfb/keysym.h>
8 #endif /* HAVE_LIBVNCSERVER */
11 #include "hw_keyboard.h"
15 #ifdef WANT_VARIADIC_VOIDP_CAST
16 #define VOIDP(__x__) ((void *)(__x__))
18 #define VOIDP(__x__) (__x__)
21 #define MSG_(__level__, __vm__, ...) do { ((__vm__) ? ((struct dcpu16 *)(__vm__))->msg_cb_ : dcpu16_msg_)(__level__, __VA_ARGS__); } while (0)
22 #define MSG_INFO(__vm__, ...) MSG_(DCPU16_MSG_INFO, __vm__, __VA_ARGS__)
23 #define MSG_ERROR(__vm__, ...) MSG_(DCPU16_MSG_ERROR, __vm__, __VA_ARGS__)
25 #define MSG_DEBUG(__vm__, ...) MSG_(DCPU16_MSG_DEBUG, __vm__, __VA_ARGS__)
27 #define MSG_DEBUG(__vm__, ...) do { } while (0)
35 DCPU16_WORD interrupt_message
;
36 unsigned char keys_pressed
[256];
39 #ifdef HAVE_LIBVNCSERVER
41 static const struct keysym_map_
{
42 unsigned int rfb_start
;
44 DCPU16_WORD dcpu_start
;
46 { XK_space
, XK_asciitilde
, 0x20 }, /* ASCII range */
47 { XK_Delete
, XK_Delete
, 0x7f }, /* ASCII del */
48 { XK_BackSpace
, XK_BackSpace
, 0x10 }, /* bs */
49 { XK_Return
, XK_Return
, 0x11 }, /* ret */
50 { XK_Insert
, XK_Insert
, 0x12 }, /* ins */
51 { XK_Delete
, XK_Delete
, 0x13 }, /* del */
52 { XK_Up
, XK_Up
, 0x80 }, /* arrow up */
53 { XK_Down
, XK_Down
, 0x81 }, /* arrow down */
54 { XK_Left
, XK_Left
, 0x82 }, /* arrow left */
55 { XK_Right
, XK_Right
, 0x83 }, /* arrow right */
56 { XK_Shift_L
, XK_Shift_R
, 0x90 }, /* shift range */
57 { XK_Control_L
, XK_Control_R
, 0x91 }, /* control range */
61 static int keysym_rfbtodcpu(unsigned int rfb
, DCPU16_WORD
*dcpu
) {
62 const struct keysym_map_
*map
;
64 for (map
= keymap_
; map
->rfb_start
; map
++) {
65 if (rfb
>= map
->rfb_start
66 && rfb
<= map
->rfb_end
) {
67 *dcpu
= (map
->dcpu_start
+ (rfb
- map
->rfb_start
));
77 void keyboard_rfbevent_(rfbBool down
, rfbKeySym key
, rfbClientPtr cl
) {
79 struct dcpu16_hw
*hw
= (struct dcpu16_hw
*)cl
->screen
->screenData
;
80 struct keyboard_
*keyboard
= (struct keyboard_
*)hw
->data
;
82 MSG_DEBUG(hw
->vm
, "%s>> down:%u rfb_key:0x%04x", down
, key
);
84 if (keysym_rfbtodcpu(key
, &dcpu_key
)) {
85 /* unhandled key event */
89 keyboard
->keys_pressed
[dcpu_key
] = (down
? 1 : 0);
91 if ((keyboard
->buf_tail
+ 1) % keyboard
->buf_sz
== keyboard
->buf_head
) {
92 MSG_INFO(hw
->vm
, "keyboard buffer overflow");
95 keyboard
->buf
[keyboard
->buf_tail
] = dcpu_key
;
96 keyboard
->buf_tail
+= 1;
97 keyboard
->buf_tail
%= keyboard
->buf_sz
;
99 if (keyboard
->interrupt_message
) {
100 dcpu16_interrupt(hw
->vm
, keyboard
->interrupt_message
);
103 #endif /* HAVE_LIBVNCSERVER */
106 void keyboard_reset_(struct dcpu16
*vm
, struct dcpu16_hw
*hw
) {
107 struct keyboard_
*keyboard
= (struct keyboard_
*)hw
->data
;
111 keyboard
->interrupt_message
= 0;
112 keyboard
->buf_head
= 0;
113 keyboard
->buf_tail
= 0;
114 memset(keyboard
->keys_pressed
, 0, sizeof keyboard
->keys_pressed
);
116 MSG_DEBUG(vm
, "%s>>", __func__
);
120 void keyboard_cycle_(struct dcpu16
*vm
, struct dcpu16_hw
*hw
) {
121 struct keyboard_
*keyboard
= (struct keyboard_
*)hw
->data
;
123 (void)vm
, (void)keyboard
;
127 void keyboard_hwi_(struct dcpu16
*vm
, struct dcpu16_hw
*hw
) {
128 struct keyboard_
*keyboard
= (struct keyboard_
*)hw
->data
;
129 DCPU16_WORD reg_a
= vm
->reg
[DCPU16_REG_A
];
130 DCPU16_WORD reg_b
= vm
->reg
[DCPU16_REG_B
];
133 case 0: /* clear keyboard buffer */
134 memset(keyboard
->buf
, 0, keyboard
->buf_sz
);
135 keyboard
->buf_head
= 0;
136 keyboard
->buf_tail
= 0;
138 MSG_DEBUG(vm
, "%s>> buffer cleared", __func__
);
141 case 1: /* get next key from buffer as C */
142 if (keyboard
->buf_head
== keyboard
->buf_tail
)
144 vm
->reg
[DCPU16_REG_C
] = keyboard
->buf
[keyboard
->buf_head
];
145 keyboard
->buf_head
+= 1;
146 keyboard
->buf_head
%= keyboard
->buf_sz
;
148 MSG_DEBUG(vm
, "%s>> next key: %u", __func__
, vm
->reg
[DCPU16_REG_C
]);
151 case 2: /* get currently-pressed-state of key in B as C */
152 vm
->reg
[DCPU16_REG_C
] = keyboard
->keys_pressed
[reg_b
& 0x00ff];
154 MSG_DEBUG(vm
, "%s>> state of key 0x%02x: %spressed", __func__
, reg_b
& 0x00ff, keyboard
->keys_pressed
[reg_b
& 0x00ff] ? "" : "not ");
157 case 3: /* set interrupt state */
158 keyboard
->interrupt_message
= reg_b
;
160 MSG_DEBUG(vm
, "%s>> interrupt_message:0x%04x", __func__
, reg_b
);
167 int keyboard_data_init_(struct dcpu16_hw
*hw
, void *data
) {
168 size_t buf_sz
= data
? *(size_t *)data
: BUF_SZ
;
170 hw
->data
= calloc(1, sizeof(struct keyboard_
));
171 if (hw
->data
== NULL
) {
172 MSG_ERROR(hw
->vm
, "%s():%s", "calloc", strerror(errno
));
176 ((struct keyboard_
*)(hw
->data
))->buf
= malloc(buf_sz
* sizeof *((struct keyboard_
*)(hw
->data
))->buf
);
177 if (((struct keyboard_
*)(hw
->data
))->buf
== NULL
) {
178 MSG_ERROR(hw
->vm
, "%s():%s", "malloc", strerror(errno
));
184 ((struct keyboard_
*)(hw
->data
))->buf_sz
= buf_sz
;
190 void keyboard_data_free_(struct dcpu16_hw
*hw
) {
193 if (((struct keyboard_
*)(hw
->data
))->buf
) {
194 free(((struct keyboard_
*)(hw
->data
))->buf
);
195 ((struct keyboard_
*)(hw
->data
))->buf
= NULL
;
203 static struct dcpu16_hw_ctl_cmd ctl_
[] = {
204 { "buffer_size", "const size_t *", "size_t *", "get or set current buffer size" },
205 { "associate_rfbScreen", "rfbScreenInfoPtr", "NULL", "associates this keyboard instance with an rfb display" },
206 { NULL
, NULL
, NULL
, NULL
}
209 int keyboard_data_ctl_(struct dcpu16_hw
*hw
, const char *cmd
, void *data_in
, void *data_out
) {
210 if (strcmp(cmd
, "buffer_size") == 0) {
211 struct keyboard_
*keyboard
= (struct keyboard_
*)hw
->data
;
213 const size_t *buf_sz_in
= (const size_t *)data_in
;
214 size_t *buf_sz_out
= (size_t *)data_out
;
217 *buf_sz_out
= keyboard
->buf_sz
;
221 MSG_DEBUG(hw
->vm
, "%s>> resizing buffer from %zu to %zu", __func__
, keyboard
->buf_sz
, *buf_sz_in
);
223 tmp_ptr
= realloc(keyboard
->buf
, *buf_sz_in
);
224 if (tmp_ptr
== NULL
) {
225 MSG_ERROR(hw
->vm
, "%s():%s", "realloc", strerror(errno
));
228 keyboard
->buf
= tmp_ptr
;
229 keyboard
->buf_sz
= *buf_sz_in
;
230 keyboard
->buf_head
= keyboard
->buf_tail
= 0;
233 MSG_DEBUG(hw
->vm
, "%s>> %s now:%zu was:%zu", __func__
, "buffer_size", *buf_sz_in
, *buf_sz_out
);
238 #ifdef HAVE_LIBVNCSERVER
239 if (strcmp(cmd
, "associate_rfbScreen") == 0) {
240 rfbScreenInfoPtr rfbScreen
= (rfbScreenInfoPtr
)data_in
;
243 if (rfbScreen
== NULL
)
246 rfbScreen
->screenData
= hw
;
247 rfbScreen
->kbdAddEvent
= keyboard_rfbevent_
;
249 MSG_DEBUG(hw
->vm
, "%s>> %s rfbScreen:%p", __func__
, "associate_rfbScreen", rfbScreen
);
253 #endif /* HAVE_LIBVNCSERVER */
259 struct dcpu16_hw_module dcpu16_hw_module_keyboard
= {
260 .name_
= "Generic Keyboard (compatible)",
267 .hwi
= keyboard_hwi_
,
268 .cycle
= keyboard_cycle_
,
269 .reset
= keyboard_reset_
,
271 .data_init
= keyboard_data_init_
,
272 .data_free
= keyboard_data_free_
,
273 .ctl
= keyboard_data_ctl_
,