initial api changes to support hw_ devices as more-generic attachable modules
[dcpu16] / hw_keyboard.c
index 28d66d63c6c0f16a14cdfe57403a104ecd170ca4..90c30b3809590f9882a91da23f67a0af17d476c8 100644 (file)
 
 #define BUF_SZ 32
 
+#ifdef WANT_VARIADIC_VOIDP_CAST
+#define VOIDP(__x__) ((void *)(__x__))
+#else
+#define VOIDP(__x__) (__x__)
+#endif
+
 static dcpu16_hw_signal_t keyboard_reset_;
 static dcpu16_hw_signal_t keyboard_cycle_;
 static dcpu16_hw_signal_t keyboard_hwi_;
@@ -32,6 +38,8 @@ static struct dcpu16_hw hw_ = {
 struct keyboard_ {
     char *buf;
     size_t buf_sz;
+    size_t buf_head;
+    size_t buf_tail;
     DCPU16_WORD interrupt_message;
     unsigned char keys_pressed[256];
 };
@@ -81,14 +89,28 @@ void keyboard_rfbevent_(rfbBool down, rfbKeySym key, rfbClientPtr cl) {
 
     keysym_rfbtodcpu(key, &dcpu_key);
 
-    fprintf(stderr, "%s: down:%u key:0x%04x dcpu_key:0x%04x\n", __func__,
-            down, key, dcpu_key);
+    fprintf(stderr, "%s: down:%u key:0x%04x dcpu_key:0x%04x\n",
+            __func__,
+            down,
+            key,
+            dcpu_key);
 
-    fprintf(stderr, "%s: hw:%p name:%s vm:%p\n", __func__, hw, hw->name_, hw->vm);
+    fprintf(stderr, "%s: hw:%p name:%s vm:%p\n",
+            __func__,
+            VOIDP(hw),
+            hw->name_,
+            VOIDP(hw->vm));
 
     keyboard->keys_pressed[dcpu_key] = (down ? 1 : 0);
-    if (down)
-        keyboard->buf[0] = dcpu_key;
+    if (down) {
+        if ((keyboard->buf_tail + 1) % keyboard->buf_sz == keyboard->buf_head) {
+            hw->vm->warn_cb_("keyboard buffer overflow");
+            return;
+        }
+        keyboard->buf[keyboard->buf_tail] = dcpu_key;
+        keyboard->buf_tail += 1;
+        keyboard->buf_tail %= keyboard->buf_sz;
+    }
     if (keyboard->interrupt_message) {
         dcpu16_interrupt(hw->vm, keyboard->interrupt_message);
     }
@@ -122,19 +144,20 @@ void keyboard_hwi_(struct dcpu16 *vm, void *data) {
     struct keyboard_ *keyboard = (struct keyboard_ *)data;
     DCPU16_WORD reg_a = vm->reg[DCPU16_REG_A];
     DCPU16_WORD reg_b = vm->reg[DCPU16_REG_B];
-    size_t i;
 
     switch (reg_a) {
         case 0: /* clear keyboard buffer */
             memset(keyboard->buf, 0, keyboard->buf_sz);
+            keyboard->buf_head = 0;
+            keyboard->buf_tail = 0;
             break;
 
         case 1: /* get next key from buffer as C */
-            vm->reg[DCPU16_REG_C] = keyboard->buf[0];
-            for (i = 1; i < keyboard->buf_sz; i++) {
-                keyboard->buf[i-1] = keyboard->buf[i];
-            }
-            keyboard->buf[i] = '\0';
+            if (keyboard->buf_head == keyboard->buf_tail)
+                break;
+            vm->reg[DCPU16_REG_C] = keyboard->buf[keyboard->buf_head];
+            keyboard->buf_head += 1;
+            keyboard->buf_head %= keyboard->buf_sz;
             break;
 
         case 2: /* get currently-pressed-state of key in B as C */
@@ -182,13 +205,16 @@ struct dcpu16_hw *keyboard_new(struct dcpu16 *vm) {
 
 void keyboard_del(struct dcpu16_hw **hw) {
     if (hw) {
-        free(((struct keyboard_ *)((*hw)->data))->buf);
-        ((struct keyboard_ *)((*hw)->data))->buf = NULL;
+        if (*hw) {
+            if ((*hw)->data) {
+                free(((struct keyboard_ *)((*hw)->data))->buf);
+                ((struct keyboard_ *)((*hw)->data))->buf = NULL;
 
-        free((*hw)->data);
-        (*hw)->data = NULL;
-
-        free(*hw);
-        *hw = NULL;
+                free((*hw)->data);
+                (*hw)->data = NULL;
+            }
+            free(*hw);
+            *hw = NULL;
+        }
     }
 }