Wrote all remaining Unicode input and output functions.
[rodin/chimara.git] / src / input.c
index b3255cf5d926b4dd6eb6dcb4898691b5dd586d9b..8956c2c53438dad52dd3446d88acd3012c54a1f3 100644 (file)
@@ -1,3 +1,4 @@
+#include "charset.h"
 #include "input.h"
 
 /** glk_request_char_event:
@@ -83,6 +84,8 @@ text_grid_request_line_event_common(winid_t win, glui32 maxlen, gboolean insert,
     
     gtk_widget_show(win->input_entry);
     gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(win->widget), win->input_entry, win->input_anchor);
+       
+       g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler );
 }
     
 /* Internal function: Request either latin-1 or unicode line input, in a text buffer window. */
@@ -201,14 +204,9 @@ glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initl
 
        gchar *utf8;
        if(initlen > 0) {
-               GError *error = NULL;
-               utf8 = g_ucs4_to_utf8(buf, initlen, NULL, NULL, &error);
-                       
+               utf8 = convert_ucs4_to_utf8(buf, initlen);
                if(utf8 == NULL)
-               {
-                       g_warning("Error during unicode->utf8 conversion: %s", error->message);
                        return;
-               }
        }
        else
                utf8 = g_strdup("");
@@ -227,10 +225,29 @@ glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initl
        g_free(utf8);
 }
 
-/* Internal function: Callback for signal key-press-event on a text buffer or text grid window. */
+/* Internal function: General callback for signal key-press-event on a text buffer or text grid window. Used in character input on both text buffers and grids, and also in line input on grids, to redirect keystrokes to the line input field. Blocked when not in use. */
 gboolean
 on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win)
-{    
+{
+       /* If this is a text grid window, and line input is active, then redirect the key press to the line input GtkEntry */
+       if( win->type == wintype_TextGrid && (win->input_request_type == INPUT_REQUEST_LINE || win->input_request_type == INPUT_REQUEST_LINE_UNICODE) )
+       {
+               if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up
+                   || event->keyval == GDK_Down || event->keyval == GDK_KP_Down
+                   || event->keyval == GDK_Left || event->keyval == GDK_KP_Left
+                   || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
+                   || event->keyval == GDK_Tab || event->keyval == GDK_KP_Tab
+                   || event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up
+                   || event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down
+                   || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
+                   || event->keyval == GDK_End || event->keyval == GDK_KP_End)
+                       return FALSE; /* Don't redirect these keys */
+               gtk_widget_grab_focus(win->input_entry);
+               gtk_editable_set_position(GTK_EDITABLE(win->input_entry), -1);
+               gboolean retval = TRUE;
+               g_signal_emit_by_name(win->input_entry, "key-press-event", event, &retval);
+               return retval; /* Block this key event if the entry handled it */
+       }
        if(win->input_request_type != INPUT_REQUEST_CHARACTER && 
                win->input_request_type != INPUT_REQUEST_CHARACTER_UNICODE)
                return FALSE;
@@ -304,14 +321,11 @@ end_line_input_request(winid_t win, const gchar *inserted_text)
     /* Convert the string from UTF-8 to Latin-1 or Unicode */
     if(win->input_request_type == INPUT_REQUEST_LINE) 
     {
-        GError *error = NULL;
-        gchar *latin1;
         gsize bytes_written;
-        latin1 = g_convert_with_fallback(inserted_text, -1, "ISO-8859-1", "UTF-8", "?", NULL, &bytes_written, &error);
+        gchar *latin1 = convert_utf8_to_latin1(inserted_text, &bytes_written);
         
         if(latin1 == NULL)
         {
-            g_warning("Error during utf8->latin1 conversion: %s", error->message);
             event_throw(evtype_LineInput, win, 0, 0);
             return;
         }
@@ -328,21 +342,18 @@ end_line_input_request(winid_t win, const gchar *inserted_text)
     }
     else if(win->input_request_type == INPUT_REQUEST_LINE_UNICODE) 
     {
-        gunichar *unicode;
         glong items_written;
-        unicode = g_utf8_to_ucs4_fast(inserted_text, -1, &items_written);
+        gunichar *unicode = convert_utf8_to_ucs4(inserted_text, &items_written);
         
         if(unicode == NULL)
         {
-            g_warning("Error during utf8->unicode conversion");
             event_throw(evtype_LineInput, win, 0, 0);
             return;
         }
 
         /* Place input in the echo stream */
-        /* TODO: glk_put_string_stream_uni not implemented yet
         if(win->echo_stream != NULL) 
-            glk_put_string_stream_uni(window->echo_stream, unicode);*/
+            glk_put_string_stream_uni(win->echo_stream, unicode);
 
         /* Copy the string (but not the NULL at the end) */
         int copycount = MIN(win->line_input_buffer_max_len, items_written);
@@ -357,7 +368,10 @@ end_line_input_request(winid_t win, const gchar *inserted_text)
 }
 
 /* Internal function: Callback for signal insert-text on a text buffer window.
-Runs after the default handler has already inserted the text.*/
+Runs after the default handler has already inserted the text.
+FIXME: This function assumes that newline was the last character typed into the
+window. That assumption is wrong if, for example, text containing a newline was
+pasted into the window. */
 void
 after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, winid_t win) 
 {
@@ -375,6 +389,7 @@ after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar
         GtkTextMark *input_position = gtk_text_buffer_get_mark(window_buffer, "input_position");
         gtk_text_buffer_get_iter_at_mark(window_buffer, &start_iter, input_position);
         gtk_text_buffer_get_end_iter(window_buffer, &end_iter);
+               gtk_text_iter_backward_cursor_position(&end_iter); /* don't include \n */
         
         inserted_text = gtk_text_buffer_get_text(window_buffer, &start_iter, &end_iter, FALSE);
 
@@ -391,7 +406,8 @@ on_input_entry_activate(GtkEntry *input_entry, winid_t win)
        GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
        
        gchar *text = g_strdup(gtk_entry_get_text(input_entry));
-       
+       /* Move the focus back into the text view */
+       gtk_widget_grab_focus(win->widget);
        /* Remove entry widget from text view */
        /* Should be ok even though this is the widget's own signal handler */
        gtk_container_remove( GTK_CONTAINER(win->widget), GTK_WIDGET(input_entry) );
@@ -410,6 +426,8 @@ on_input_entry_activate(GtkEntry *input_entry, winid_t win)
     gtk_text_buffer_insert(buffer, &start, text_to_insert, -1);
     g_free(text_to_insert);
     
+       g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
+       
     end_line_input_request(win, text);
        g_free(text);
 }