From bd91448d90b66488ffb2e46a0f8f35dbe75fefa9 Mon Sep 17 00:00:00 2001
From: Sam Hocevar <sam@hocevar.net>
Date: Sun, 23 Nov 2003 03:44:59 +0000
Subject: [PATCH]   * src/caca.c:     + Mouse initialisation in ncurses.   *
 src/io.c:     + Mouse support in ncurses.

---
 examples/demo.c |   2 +-
 src/caca.c      |   6 ++
 src/caca.h      |   2 +-
 src/io.c        | 217 +++++++++++++++++++++++++++---------------------
 4 files changed, 131 insertions(+), 96 deletions(-)

diff --git a/examples/demo.c b/examples/demo.c
index 8af1e27..b19fb7d 100644
--- a/examples/demo.c
+++ b/examples/demo.c
@@ -122,7 +122,7 @@ fprintf(stderr, "w %i, h %i, stride %i\n", bufx, bufy, bufpitch);
         else if(event & CACA_EVENT_KEY_PRESS)
         {
         handle_key:
-            switch(event & 0xff)
+            switch(event & 0xffff)
             {
             case 'q':
             case 'Q':
diff --git a/src/caca.c b/src/caca.c
index d3cae94..9037382 100644
--- a/src/caca.c
+++ b/src/caca.c
@@ -60,6 +60,7 @@ char *_caca_empty_line;
 char *_caca_scratch_line;
 
 #if defined(USE_NCURSES)
+static mmask_t oldmask;
 int _caca_attr[16];
 #endif
 
@@ -124,6 +125,7 @@ int caca_init(void)
 
 #elif defined(USE_NCURSES)
     int i;
+    mmask_t newmask;
 
     initscr();
     keypad(stdscr, TRUE);
@@ -133,6 +135,9 @@ int caca_init(void)
     nodelay(stdscr, TRUE);
     curs_set(0);
 
+    newmask = ALL_MOUSE_EVENTS;
+    mousemask(newmask, &oldmask);
+
     start_color();
 
     init_pair(1 + CACA_COLOR_BLACK,        COLOR_BLACK,   COLOR_BLACK);
@@ -306,6 +311,7 @@ void caca_end(void)
     SLang_reset_tty();
     SLsmg_reset_smg();
 #elif defined(USE_NCURSES)
+    mousemask(oldmask, NULL);
     curs_set(1);
     endwin();
 #elif defined(USE_CONIO)
diff --git a/src/caca.h b/src/caca.h
index a1a2243..c70540d 100644
--- a/src/caca.h
+++ b/src/caca.h
@@ -145,7 +145,7 @@ void caca_end(void);
 /*
  * Events
  */
-int caca_get_event(void);
+unsigned int caca_get_event(void);
 
 /*
  * Character graphics
diff --git a/src/io.c b/src/io.c
index c4fccab..3796cbd 100644
--- a/src/io.c
+++ b/src/io.c
@@ -42,137 +42,166 @@
 #include "caca.h"
 #include "caca_internals.h"
 
-static void _push_key(unsigned char);
-static unsigned char _pop_key(void);
-static unsigned char _read_key(void);
+static void _push_key(unsigned int);
+static unsigned int _pop_key(void);
+static unsigned int _read_key(void);
 
-static unsigned char back[5] = {0, 0, 0, 0, 0};
+#define KEY_BUFLEN 10
+static unsigned int keybuf[KEY_BUFLEN + 1]; /* zero-terminated */
+static int keys = 0;
 
-int caca_get_event(void)
+unsigned int caca_get_event(void)
 {
-    unsigned char key[6];
+    unsigned int event = 0;
 
-    /* If there were legacy keys, pop them */
-    key[0] = _pop_key();
-    if(key[0])
-        return CACA_EVENT_KEY_PRESS | key[0];
+    /* Read all available key events */
+    while(keys < KEY_BUFLEN)
+    {
+        unsigned int key = _read_key();
+        if(!key)
+            break;
+        _push_key(key);
+    }
 
-    key[0] = _read_key();
-    if(!key[0])
+    if(!keys)
         return 0;
 
-    if(key[0] != 0x1b)
-        return CACA_EVENT_KEY_PRESS | key[0];
+#if defined(USE_NCURSES)
+    if(keybuf[0] == KEY_MOUSE)
+    {
+        MEVENT mevent;
+        _pop_key();
+        getmouse(&mevent);
 
-    /*
-     * Handle escape sequences
-     */
+        event |= (1) << 16;
+        event |= (mevent.x) << 8;
+        event |= (mevent.y) << 0;
 
-    key[1] = _read_key();
-    if(!key[1])
-        return CACA_EVENT_KEY_PRESS | key[0];
+        return CACA_EVENT_MOUSE_CLICK | event;
+    }
 
-    key[2] = _read_key();
-    if(!key[2])
+    switch(keybuf[0])
     {
-        _push_key(key[1]);
-        return CACA_EVENT_KEY_PRESS | key[0];
+        case KEY_UP: event = CACA_EVENT_KEY_PRESS | CACA_KEY_UP; break;
+        case KEY_DOWN: event = CACA_EVENT_KEY_PRESS | CACA_KEY_DOWN; break;
+        case KEY_LEFT: event = CACA_EVENT_KEY_PRESS | CACA_KEY_LEFT; break;
+        case KEY_RIGHT: event = CACA_EVENT_KEY_PRESS | CACA_KEY_RIGHT; break;
+
+        case KEY_F(1): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F1; break;
+        case KEY_F(2): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F2; break;
+        case KEY_F(3): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F3; break;
+        case KEY_F(4): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F4; break;
+        case KEY_F(5): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F5; break;
+        case KEY_F(6): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F6; break;
+        case KEY_F(7): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F7; break;
+        case KEY_F(8): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F8; break;
+        case KEY_F(9): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F9; break;
+        case KEY_F(10): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F10; break;
+        case KEY_F(11): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F11; break;
+        case KEY_F(12): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F12; break;
     }
 
-    if(key[1] == 'O')
+    if(event)
     {
-        /* ^[OP ^[OQ ^[OR ^[OS */
-        switch(key[2])
-        {
-        case 'P': return CACA_EVENT_KEY_PRESS | CACA_KEY_F1;
-        case 'Q': return CACA_EVENT_KEY_PRESS | CACA_KEY_F2;
-        case 'R': return CACA_EVENT_KEY_PRESS | CACA_KEY_F3;
-        case 'S': return CACA_EVENT_KEY_PRESS | CACA_KEY_F4;
-        }
+        _pop_key();
+        return event;
     }
-    else if(key[1] == '[')
-    {
-        /* ^[[A ^[[B ^[[C ^[[D */
-        switch(key[2])
-        {
-        case 'A': return CACA_EVENT_KEY_PRESS | CACA_KEY_UP;
-        case 'B': return CACA_EVENT_KEY_PRESS | CACA_KEY_DOWN;
-        case 'C': return CACA_EVENT_KEY_PRESS | CACA_KEY_RIGHT;
-        case 'D': return CACA_EVENT_KEY_PRESS | CACA_KEY_LEFT;
-        }
+#endif
 
-        key[3] = _read_key();
-        key[4] = _read_key();
+    if(keybuf[0] != '\x1b')
+        return CACA_EVENT_KEY_PRESS | _pop_key();
 
-        /* ^[[Mxxx */
-        if(key[2] == 'M')
-        {
-            int event = CACA_EVENT_MOUSE_CLICK;
-
-            key[5] = _read_key();
+    /*
+     * Handle known escape sequences
+     */
 
-            event |= (int)(key[3] - ' ') << 16;
-            event |= (int)(key[4] - '!') << 8;
-            event |= (int)(key[5] - '!') << 0;
+    _pop_key();
 
-            return event;
-        }
+    if(keybuf[0] == 'O' && keybuf[1] >= 'P' && keybuf[1] <= 'S')
+    {
+        /* ^[OP ^[OQ ^[OR ^[OS */
+        static unsigned int keylist[] =
+            { CACA_KEY_F1, CACA_KEY_F2, CACA_KEY_F3, CACA_KEY_F4 };
+        _pop_key();
+        return CACA_EVENT_KEY_PRESS | keylist[_pop_key() - 'P'];
+    }
+    else if(keybuf[0] == '[' && keybuf[1] >= 'A' && keybuf[1] <= 'D')
+    {
+        /* ^[[A ^[[B ^[[C ^[[D */
+        static unsigned int keylist[] =
+            { CACA_KEY_UP, CACA_KEY_DOWN, CACA_KEY_RIGHT, CACA_KEY_LEFT };
+        _pop_key();
+        return CACA_EVENT_KEY_PRESS | keylist[_pop_key() - 'A'];
+    }
+    else if(keybuf[0] == '[' && keybuf[1] == 'M' &&
+            keybuf[2] && keybuf[3] && keybuf[3])
+    {
+        /* ^[[Mxxx */
+        _pop_key();
+        _pop_key();
+        event |= (_pop_key() - ' ') << 16;
+        event |= (_pop_key() - '!') << 8;
+        event |= (_pop_key() - '!') << 0;
 
+        return CACA_EVENT_MOUSE_CLICK | event;
+    }
+    else if(keybuf[0] == '[' && keybuf[1] == '1' && keybuf[3] == '~' &&
+            keybuf[2] >= '5' && keybuf[2] != '6' && keybuf[2] <= '9')
+    {
         /* ^[[15~ ^[[17~ ^[[18~ ^[[19~ */
-        if(key[2] == '1' && key[4] == '~')
-            switch(key[3])
-            {
-            case '5': return CACA_EVENT_KEY_PRESS | CACA_KEY_F5;
-            case '7': return CACA_EVENT_KEY_PRESS | CACA_KEY_F6;
-            case '8': return CACA_EVENT_KEY_PRESS | CACA_KEY_F7;
-            case '9': return CACA_EVENT_KEY_PRESS | CACA_KEY_F8;
-            }
-
+        static unsigned int keylist[] =
+            { CACA_KEY_F5, 0, CACA_KEY_F6, CACA_KEY_F7, CACA_KEY_F8 };
+        _pop_key();
+        _pop_key();
+        event = CACA_EVENT_KEY_PRESS | keylist[_pop_key() - '5'];
+        _pop_key();
+        return event;
+    }
+    else if(keybuf[0] == '[' && keybuf[1] == '2' && keybuf[3] == '~' &&
+            keybuf[2] >= '0' && keybuf[2] != '2' && keybuf[2] <= '4')
+    {
         /* ^[[20~ ^[[21~ ^[[23~ ^[[24~ */
-        if(key[2] == '2' && key[4] == '~')
-            switch(key[3])
-            {
-            case '0': return CACA_EVENT_KEY_PRESS | CACA_KEY_F9;
-            case '1': return CACA_EVENT_KEY_PRESS | CACA_KEY_F10;
-            case '3': return CACA_EVENT_KEY_PRESS | CACA_KEY_F11;
-            case '4': return CACA_EVENT_KEY_PRESS | CACA_KEY_F12;
-            }
-
-        _push_key(key[4]);
-        _push_key(key[3]);
+        static unsigned int keylist[] =
+            { CACA_KEY_F9, CACA_KEY_F10, 0, CACA_KEY_F11, CACA_KEY_F12 };
+        _pop_key();
+        _pop_key();
+        event = CACA_EVENT_KEY_PRESS | keylist[_pop_key() - '0'];
+        _pop_key();
+        return event;
     }
 
-    /* Unknown escape sequence: return each key one after the other */
-    _push_key(key[2]);
-    _push_key(key[1]);
-    return CACA_EVENT_KEY_PRESS | key[0];
+caca_printf(0,0, "unknown esc sequence %2x %2x %2x %2x %2x\n", '\x1b', keybuf[0], keybuf[1], keybuf[2], keybuf[3]);
+    /* Unknown escape sequence: return the ESC key */
+    return CACA_EVENT_KEY_PRESS | '\x1b';
 }
 
-static void _push_key(unsigned char key)
+static void _push_key(unsigned int key)
 {
-    back[4] = back[3];
-    back[3] = back[2];
-    back[2] = back[1];
-    back[1] = back[0];
-    back[0] = key;
+    if(keys == KEY_BUFLEN)
+        return;
+    keybuf[keys] = key;
+    keys++;
+    keybuf[keys] = 0;
 }
 
-static unsigned char _pop_key(void)
+static unsigned int _pop_key(void)
 {
-    unsigned char key = back[0];
-    back[0] = back[1];
-    back[1] = back[2];
-    back[2] = back[3];
-    back[3] = back[4];
+    int i;
+    unsigned int key = keybuf[0];
+    keys--;
+    for(i = 0; i < keys; i++)
+        keybuf[i] = keybuf[i + 1];
+    keybuf[keys] = 0;
+
     return key;
 }
 
-static unsigned char _read_key(void)
+static unsigned int _read_key(void)
 {
 #if defined(USE_SLANG)
     return SLang_input_pending(0) ? SLang_getkey() : 0;
 #elif defined(USE_NCURSES)
-    unsigned char key = getch();
+    int key = getch();
     return (key == ERR) ? 0 : key;
 #elif defined(USE_CONIO)
     return _conio_kbhit() ? getch() : 0;