Implement keyboard handling, and use it to enter
authorLuigi Rizzo <rizzo@icir.org>
Wed, 9 Jan 2008 16:44:20 +0000 (16:44 +0000)
committerLuigi Rizzo <rizzo@icir.org>
Wed, 9 Jan 2008 16:44:20 +0000 (16:44 +0000)
a number to dial in the 'message' area under the
keypad.

Now you can make calls using the keypad as a regular phone
(or the keyboard for chars not present on the keypad)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@97488 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/console_board.c
channels/console_gui.c
channels/console_video.c
channels/console_video.h

index 9096a85..9c913f8 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "asterisk.h"  /* ast_strdupa */
 #include "asterisk/utils.h"    /* ast_strdupa */
+#include "console_video.h"     /* ast_strdupa */
 
 #ifdef HAVE_SDL        /* we only use this code if SDL is available */
 #include <SDL/SDL.h>
@@ -180,8 +181,8 @@ static void render_board(struct board *b)
        /* blit all characters */
        for (i = first_char, col = 0; i <  last_char; i++) {
                int c = b->text[i] - 32;        /* XXX first 32 chars are not printable */
-               if (c < 0)      /* should not happen, but just in case... */
-                       continue;
+               if (c < 0) /* buffer terminator or anything else is a blank */
+                       c = 0;
                SDL_BlitSurface(b->font, &b->font_rects[c], b->screen, &dst);
                /* point dst to next char position */
                dst.x += dst.w;
@@ -195,11 +196,24 @@ static void render_board(struct board *b)
        SDL_UpdateRects(b->screen, 1, b->p_rect);       /* Update the screen */
 }
 
+/* return the content of a board */
+const char *read_message(const struct board *b)
+{
+       return b->text;
+}
+
+int reset_board(struct board *b)
+{
+       memset(b->text, ' ', b->v_w * b->v_h);  /* fill with spaces */
+       b->cur_col = 0;
+       b->cur_line = 0;
+       render_board(b);
+       return 0;
+}
 /* Store the message on the history board
  * and blit on screen if required.
  * XXX now easy. only regular chars
  */
-int print_message(struct board *b, const char *s);
 int print_message(struct board *b, const char *s)
 {
        int i, l, row, col;
@@ -261,12 +275,14 @@ int print_message(struct board *b, const char *s)
                        col = 0;
                        break;
                case '\n':      /* move to beginning of next line */
+                       dst[col] = '\0'; /* mark the rest of the line as empty */
                        col = 0;
                        dst += b->v_w;
                        break;
                case '\b':      /* one char back */
                        if (col > 0)
                                col--;
+                       dst[col] = ' '; /* delete current char */
                        break;
                default:
                        if (s[i] < 32) /* signed, so take up to 127 */
@@ -280,6 +296,7 @@ int print_message(struct board *b, const char *s)
                        break;
                }
        }
+       dst[col] = '\0'; /* the current position is empty */
        b->cur_col = col;
        /* everything is printed now, must do the rendering */
        render_board(b);
index 7b4cf23..2bdbdf6 100644 (file)
@@ -80,6 +80,7 @@ enum kb_output {
        KO_NONE,
        KO_INPUT,       /* the local input window */
        KO_DIALED,      /* the 'dialed number' window */
+       KO_MESSAGE,     /* the 'message' window */
 };
 
 enum drag_window {     /* which window are we dragging */
@@ -91,14 +92,8 @@ enum drag_window {   /* which window are we dragging */
        DRAG_MESSAGE,   /* message window */
 };
 
-struct board;  /* external. we only need the pointer */
-
 /*! \brief info related to the gui: button status, mouse coords, etc. */
 struct gui_info {
-       char                    inbuf[GUI_BUFFER_LEN];  /* buffer for to-dial buffer */
-       int                     inbuf_pos;      /* next free position in inbuf */
-       char                    msgbuf[GUI_BUFFER_LEN]; /* buffer for text-message buffer */
-       int                     msgbuf_pos;     /* next free position in msgbuf */
        enum kb_output          kb_output;      /* where the keyboard output goes */
        enum drag_window        drag_window;    /* which window are we dragging */
        int                     x_drag;         /* x coordinate where the drag starts */
@@ -238,11 +233,12 @@ enum skin_area {
        KEY_SENDVIDEO = 132,
        KEY_LOCALVIDEO = 133,
        KEY_REMOTEVIDEO = 134,
-       KEY_WRITEMESSAGE = 135,
        KEY_FLASH = 136,
        KEY_GUI_CLOSE = 199,            /* close gui */
 
-       /* regions of the skin - active area, fonts, etc. */
+       /* regions of the skin - displayed area, fonts, etc.
+        * XXX NOTE these are not sensitive areas.
+        */
        KEY_KEYPAD = 200,               /* the keypad - default to the whole image */
        KEY_FONT = 201,         /* the font. Maybe not really useful */
        KEY_MESSAGE = 202,      /* area for incoming messages */
@@ -262,27 +258,6 @@ enum skin_area {
  * Handlers for the various keypad functions
  */
 
-/*! \brief append a character, or reset if  c = '\0' */
-static void append_char(char *str, int *str_pos, const char c)
-{
-       int i = *str_pos;
-       if (c == '\0')
-               i = 0;
-       else if (i < GUI_BUFFER_LEN - 1)
-               str[i++] = c;
-       else
-               i = GUI_BUFFER_LEN - 1; /* unnecessary, i think */
-       str = '\0';
-       *str_pos = i;
-}
-
-/*! \brief append string to a buffer */
-static void append_string(char *str, int *str_pos, const char *s)
-{
-       while (*s)
-               append_char(str, str_pos, *s++);
-}
-
 /* accumulate digits, possibly call dial if in connected mode */
 static void keypad_digit(struct video_desc *env, int digit)
 {      
@@ -292,7 +267,9 @@ static void keypad_digit(struct video_desc *env, int digit)
                f.subclass = digit;
                ast_queue_frame(env->owner, &f);
        } else {                /* no call, accumulate digits */
-               append_char(env->gui->inbuf, &env->gui->inbuf_pos, digit);
+               char buf[2] = { digit, '\0' };
+               if (env->gui->bd_msg) /* XXX not strictly necessary ... */
+                       print_message(env->gui->bd_msg, buf);
        }
 }
 
@@ -340,11 +317,15 @@ static void keypad_pick_up(struct video_desc *env)
 
        if (env->owner) { /* someone is calling us, just answer */
                ast_cli_command(gui->outfd, "console answer");
-       } else if (gui->inbuf_pos) { /* we have someone to call */
-               ast_cli_command(gui->outfd, gui->inbuf);
+       } else { /* we have someone to call */
+               char buf[160];
+               buf[sizeof(buf) - 1] = '\0';
+               snprintf(buf, sizeof(buf) - 1, "console dial %s",
+                       ast_skip_blanks(read_message(gui->bd_msg)));
+               ast_log(LOG_WARNING, "doing <%s>\n", buf);
+               reset_board(gui->bd_msg);
+               ast_cli_command(gui->outfd, buf);
        }
-       append_char(gui->inbuf, &gui->inbuf_pos, '\0'); /* clear buffer */
-       append_string(gui->inbuf, &gui->inbuf_pos, "console dial ");
 }
 
 #if 0 /* still unused */
@@ -474,30 +455,68 @@ static void handle_mousedown(struct video_desc *env, SDL_MouseButtonEvent button
  * depending on the text_mode variable value.
  *
  * key is the SDLKey structure corresponding to the key pressed.
- * XXX needs to be cleaned up when handling returns etc.
+ * Note that SDL returns modifiers (ctrl, shift, alt) as independent
+ * information so the key itself is not enough and we need to
+ * use a translation table, below - one line per entry,
+ * plain, shift, ctrl, ... using the first char as key.
  */
-static void handle_keyboard_input(struct video_desc *env, SDLKey key)
+static const char *us_kbd_map[] = {
+       "`~", "1!", "2@", "3#", "4$", "5%", "6^",
+       "7&", "8*", "9(", "0)", "-_", "=+", "[{",
+       "]}", "\\|", ";:", "'\"", ",<", ".>", "/?",
+       "jJ\n",
+       NULL
+};
+
+static const char map_key(SDL_keysym *ks)
 {
+       const char *s, **p = us_kbd_map;
+       int c = ks->sym;
+
+       if (c == '\r')  /* map cr into lf */
+               c = '\n';
+       if (c >= SDLK_NUMLOCK && c <= SDLK_COMPOSE)
+               return 0;       /* only a modifier */
+       if (ks->mod == 0)
+               return c;
+       while ((s = *p) && s[0] != c)
+               p++;
+       if (s) { /* see if we have a modifier and a chance to use it */
+               int l = strlen(s), mod = 0;
+               if (l > 1)
+                       mod |= (ks->mod & KMOD_SHIFT) ? 1 : 0;
+               if (l > 2 + mod)
+                       mod |= (ks->mod & KMOD_CTRL) ? 2 : 0;
+               if (l > 4 + mod)
+                       mod |= (ks->mod & KMOD_ALT) ? 4 : 0;
+               c = s[mod];
+       }
+       if (ks->mod & (KMOD_CAPS|KMOD_SHIFT) && c >= 'a' && c <='z')
+               c += 'A' - 'a';
+       return c;
+}
+
+static void handle_keyboard_input(struct video_desc *env, SDL_keysym *ks)
+{
+       char buf[2] = { map_key(ks), '\0' };
        struct gui_info *gui = env->gui;
+       if (buf[0] == 0)        /* modifier ? */
+               return;
        switch (gui->kb_output) {
        default:
                break;
-       case KO_INPUT:
-               /* append in the text-message buffer */
-               if (key == SDLK_RETURN) {
-                       /* send the text message and return in normal mode */
-                       gui->kb_output = KO_NONE;
-                       ast_cli_command(gui->outfd, gui->msgbuf);
-                       append_char(gui->msgbuf, &gui->msgbuf_pos, '\0');
-               } else {
-                       /* accumulate the key in the message buffer */
-                       append_char(gui->msgbuf, &gui->msgbuf_pos, key);
+       case KO_INPUT:  /* to be completed */
+               break;
+       case KO_MESSAGE:
+               if (gui->bd_msg) {
+                       print_message(gui->bd_msg, buf);
+                       if (buf[0] == '\r' || buf[0] == '\n') {
+                               keypad_pick_up(env);
+                       }
                }
                break;
-       case KO_DIALED:
-               /* XXX actually, enter should be a 'console dial ' */
-               /* append in the dial buffer */
-               append_char(gui->inbuf, &gui->inbuf_pos, key);
+
+       case KO_DIALED: /* to be completed */
                break;
        }
 
@@ -564,7 +583,7 @@ static void eventhandler(struct video_desc *env, const char *caption)
 #endif
                        switch (ev[i].type) {
                        case SDL_KEYDOWN:
-                               handle_keyboard_input(env, ev[i].key.keysym.sym);
+                               handle_keyboard_input(env, &ev[i].key.keysym);
                                break;
                        case SDL_MOUSEMOTION:
                                if (gui->drag_window == DRAG_LOCAL)
@@ -626,15 +645,10 @@ static struct gui_info *gui_init(const char *keypad_file, const char *font)
        if (gui == NULL)
                return NULL;
        /* initialize keypad status */
-       gui->kb_output = KO_DIALED;
+       gui->kb_output = KO_MESSAGE;    /* XXX temp */
        gui->drag_window = DRAG_NONE;
        gui->outfd = -1;
 
-       /* initialize keyboard buffer */
-       append_char(gui->inbuf, &gui->inbuf_pos, '\0');
-       append_string(gui->inbuf, &gui->inbuf_pos, "console dial ");
-       append_char(gui->msgbuf, &gui->msgbuf_pos, '\0');
-
        keypad_setup(gui, keypad_file);
        if (gui->keypad == NULL)        /* no keypad, we are done */
                return gui;
@@ -896,7 +910,6 @@ static struct _s_k gui_key_map[] = {
         {"SENDVIDEO",  KEY_SENDVIDEO },
         {"LOCALVIDEO", KEY_LOCALVIDEO },
         {"REMOTEVIDEO",        KEY_REMOTEVIDEO },
-        {"WRITEMESSAGE", KEY_WRITEMESSAGE },
         {"GUI_CLOSE",  KEY_GUI_CLOSE },
         {"KEYPAD",     KEY_KEYPAD },   /* x0 y0 w h - active area of the keypad */
         {"MESSAGE",    KEY_MESSAGE },  /* x0 y0 w h - incoming messages */
index 4cc0809..5c7e87e 100644 (file)
@@ -667,8 +667,6 @@ static struct ast_frame *get_video_frames(struct video_desc *env, struct ast_fra
        return v->enc->enc_encap(&v->enc_out, v->mtu, tail);
 }
 
-int print_message(struct board *b, const char *s);
-
 /*
  * Helper thread to periodically poll the video source and enqueue the
  * generated frames to the channel's queue.
@@ -725,10 +723,6 @@ static void *video_thread(void *arg)
                int fd;
                char *caption = NULL, buf[160];
 
-               sprintf(buf, "%d   \r", count);
-               if (env->gui)
-                       print_message(env->gui->bd_msg, buf);
-
                /* determine if video format changed */
                if (count++ % 10 == 0) {
                        if (env->out.sendvideo)
index 3d3975a..8314da3 100644 (file)
@@ -86,5 +86,16 @@ int console_video_config(struct video_desc **penv, const char *var, const char *
 void console_video_uninit(struct video_desc *env);
 void console_video_start(struct video_desc *env, struct ast_channel *owner);
 
+/* console_board.c */
+struct board;
+/* !\brief print a message on a board */
+int print_message(struct board *b, const char *s);
+
+/*! \brief return the whole text from a board */
+const char *read_message(const struct board *b);
+
+/*! \brief reset the board to blank */
+int reset_board(struct board *b);
+
 #endif /* CONSOLE_VIDEO_H */
 /* end of file */