X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=libchimara%2Finput.c;h=f6b7fb5113f9f2897ec15e2c51e31e843a83f9a9;hb=1e0dc5378f314f555e3b923c6d95f5017abd528b;hp=6003f501bf7bff13a239e44a07a4ee232794ffb4;hpb=3209dfb968c2e4d87818beda85b5df1ebc56d067;p=projects%2Fchimara%2Fchimara.git diff --git a/libchimara/input.c b/libchimara/input.c index 6003f50..f6b7fb5 100644 --- a/libchimara/input.c +++ b/libchimara/input.c @@ -5,7 +5,7 @@ #include "chimara-glk-private.h" #include "garglk.h" -extern GPrivate *glk_data_key; +extern GPrivate glk_data_key; /* Forward declarations */ static int finish_text_buffer_line_input(winid_t win, gboolean emit_signal); @@ -23,7 +23,15 @@ request_char_event_common(winid_t win, gboolean unicode) flush_window_buffer(win); - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + if(win->type == wintype_TextBuffer) { + /* Move the input_position mark to the end of the window_buffer */ + GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) ); + GtkTextMark *input_position = gtk_text_buffer_get_mark(buffer, "input_position"); + GtkTextIter end_iter; + gtk_text_buffer_get_end_iter(buffer, &end_iter); + gtk_text_buffer_move_mark(buffer, input_position, &end_iter); + } + win->input_request_type = unicode? INPUT_REQUEST_CHARACTER_UNICODE : INPUT_REQUEST_CHARACTER; g_signal_handler_unblock( win->widget, win->char_input_keypress_handler ); @@ -33,6 +41,7 @@ request_char_event_common(winid_t win, gboolean unicode) gdk_threads_leave(); /* Emit the "waiting" signal to let listeners know we are ready for input */ + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); g_signal_emit_by_name(glk_data->self, "waiting"); } @@ -91,6 +100,10 @@ glk_cancel_char_event(winid_t win) static void text_grid_request_line_event_common(winid_t win, glui32 maxlen, gboolean insert, gchar *inserttext) { + /* All outstanding printing _must_ be finished before putting an input entry + into the buffer */ + flush_window_buffer(win); + gdk_threads_enter(); GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) ); @@ -130,10 +143,7 @@ text_grid_request_line_event_common(winid_t win, glui32 maxlen, gboolean insert, gtk_entry_set_has_frame(GTK_ENTRY(win->input_entry), FALSE); GtkBorder border = { 0, 0, 0, 0 }; - /* COMPAT: */ -#if GTK_CHECK_VERSION(2,10,0) gtk_entry_set_inner_border(GTK_ENTRY(win->input_entry), &border); -#endif gtk_entry_set_max_length(GTK_ENTRY(win->input_entry), win->input_length); gtk_entry_set_width_chars(GTK_ENTRY(win->input_entry), win->input_length); @@ -190,7 +200,9 @@ text_buffer_request_line_event_common(winid_t win, glui32 maxlen, gboolean inser /* Apply the correct style to the input prompt */ GtkTextIter input_iter; gtk_text_buffer_get_iter_at_mark(buffer, &input_iter, input_position); + gtk_text_buffer_apply_tag_by_name(buffer, "default", &input_iter, &end_iter); gtk_text_buffer_apply_tag_by_name(buffer, "input", &input_iter, &end_iter); + gtk_text_buffer_apply_tag_by_name(buffer, "glk-input", &input_iter, &end_iter); gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), TRUE); @@ -235,7 +247,7 @@ glk_request_line_event(winid_t win, char *buf, glui32 maxlen, glui32 initlen) cancel_old_input_request(win); - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); /* Register the buffer */ if(glk_data->register_arr) @@ -308,7 +320,7 @@ glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initl g_return_if_fail(initlen <= maxlen); cancel_old_input_request(win); - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); /* Register the buffer */ if(glk_data->register_arr) @@ -392,7 +404,7 @@ glk_cancel_line_event(winid_t win, event_t *event) } gdk_threads_leave(); - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); if(glk_data->unregister_arr) { if(win->input_request_type == INPUT_REQUEST_LINE_UNICODE) @@ -429,10 +441,10 @@ on_shutdown_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win) g_node_traverse(priv->root_window, G_IN_ORDER, G_TRAVERSE_LEAVES, -1, (GNodeTraverseFunc)turn_off_handler, NULL); /* Signal the Glk library that it can shut everything down now */ - g_mutex_lock(priv->shutdown_lock); - g_cond_signal(priv->shutdown_key_pressed); - g_mutex_unlock(priv->shutdown_lock); - + g_mutex_lock(&priv->shutdown_lock); + g_cond_signal(&priv->shutdown_key_pressed); + g_mutex_unlock(&priv->shutdown_lock); + return TRUE; /* block the event */ } @@ -470,40 +482,53 @@ on_line_input_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win { case wintype_TextBuffer: { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(win->widget)); + GtkTextMark *input_position_mark = gtk_text_buffer_get_mark(buffer, "input_position"); + GtkTextIter input_position_iter; + gtk_text_buffer_get_iter_at_mark(buffer, &input_position_iter, input_position_mark); + GtkTextIter end_iter; + gtk_text_buffer_get_end_iter(buffer, &end_iter); + + /* Check whether the cursor is at the prompt or somewhere else in the text */ + GtkTextIter selection_start, selection_end; + gtk_text_buffer_get_selection_bounds(buffer, &selection_start, &selection_end); + if(gtk_text_iter_compare(&selection_start, &input_position_iter) < 0) { + // Cursor is somewhere else in the text, place it at the end if the user starts typing + if(event->keyval >= GDK_KEY_space && event->keyval <= GDK_KEY_asciitilde) { + gtk_text_buffer_place_cursor(buffer, &end_iter); + } else { + // User is walking around, let him be. + return FALSE; + } + } + /* All text up to the input position is now regarded as being read by the user */ pager_update(win); - GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(win->widget)); - /* History up/down */ - if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up - || event->keyval == GDK_Down || event->keyval == GDK_KP_Down) + if(event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up + || event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down) { /* Prevent falling off the end of the history list */ if(win->history == NULL) return TRUE; - if( (event->keyval == GDK_Up || event->keyval == GDK_KP_Up) + if( (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up) && win->history_pos && win->history_pos->next == NULL) return TRUE; - if( (event->keyval == GDK_Down || event->keyval == GDK_KP_Down) + if( (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down) && (win->history_pos == NULL || win->history_pos->prev == NULL) ) return TRUE; - GtkTextIter start, end; /* Erase any text that was already typed */ - GtkTextMark *input_position = gtk_text_buffer_get_mark(buffer, "input_position"); - gtk_text_buffer_get_iter_at_mark(buffer, &start, input_position); - gtk_text_buffer_get_end_iter(buffer, &end); - if(win->history_pos == NULL) { - gchar *current_input = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); + gchar *current_input = gtk_text_buffer_get_text(buffer, &input_position_iter, &end_iter, FALSE); win->history = g_list_prepend(win->history, current_input); win->history_pos = win->history; } - gtk_text_buffer_delete(buffer, &start, &end); + gtk_text_buffer_delete(buffer, &input_position_iter, &end_iter); - if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up) + if(event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up) { if(win->history_pos) win->history_pos = g_list_next(win->history_pos); @@ -514,31 +539,30 @@ on_line_input_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win win->history_pos = g_list_previous(win->history_pos); /* Insert the history item into the window */ - gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_get_end_iter(buffer, &end_iter); g_signal_handler_block(buffer, win->insert_text_handler); - gtk_text_buffer_insert_with_tags_by_name(buffer, &end, win->history_pos->data, -1, "default", "input", NULL); + gtk_text_buffer_insert_with_tags_by_name(buffer, &end_iter, win->history_pos->data, -1, "default", "input", "glk-input", NULL); g_signal_handler_unblock(buffer, win->insert_text_handler); + return TRUE; } /* Move to beginning/end of input field */ - else if(event->keyval == GDK_Home) { + else if(event->keyval == GDK_KEY_Home) { GtkTextIter input_iter; GtkTextMark *input_position = gtk_text_buffer_get_mark(buffer, "input_position"); gtk_text_buffer_get_iter_at_mark(buffer, &input_iter, input_position); gtk_text_buffer_place_cursor(buffer, &input_iter); return TRUE; } - else if(event->keyval == GDK_End) { - GtkTextIter end_iter; - gtk_text_buffer_get_end_iter(buffer, &end_iter); + else if(event->keyval == GDK_KEY_End) { gtk_text_buffer_place_cursor(buffer, &end_iter); return TRUE; } /* Handle the line terminators */ - else if(event->keyval == GDK_Return || event->keyval == GDK_KP_Enter + else if(event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter || g_slist_find(win->current_extra_line_terminators, GUINT_TO_POINTER(event->keyval))) { /* Remove signal handlers */ @@ -546,9 +570,9 @@ on_line_input_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win g_signal_handler_block(win->widget, win->line_input_keypress_handler); /* Insert a newline (even if line input was terminated with a different key */ - GtkTextIter end; - gtk_text_buffer_get_end_iter(buffer, &end); - gtk_text_buffer_insert(buffer, &end, "\n", 1); + gtk_text_buffer_get_end_iter(buffer, &end_iter); + gtk_text_buffer_insert(buffer, &end_iter, "\n", 1); + gtk_text_buffer_place_cursor(buffer, &end_iter); /* Make the window uneditable again and retrieve the text that was input */ gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), FALSE); @@ -564,15 +588,15 @@ on_line_input_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win /* If this is a text grid window, then redirect the key press to the line input GtkEntry */ case wintype_TextGrid: { - 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) + if(event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up + || event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down + || event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left + || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right + || event->keyval == GDK_KEY_Tab || event->keyval == GDK_KEY_KP_Tab + || event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_KP_Page_Up + || event->keyval == GDK_KEY_Page_Down || event->keyval == GDK_KEY_KP_Page_Down + || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home + || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_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); @@ -756,7 +780,9 @@ after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar GtkTextIter input_iter; GtkTextMark *input_position = gtk_text_buffer_get_mark(window_buffer, "input_position"); gtk_text_buffer_get_iter_at_mark(window_buffer, &input_iter, input_position); + gtk_text_buffer_apply_tag_by_name(window_buffer, "default", &input_iter, &end_iter); gtk_text_buffer_apply_tag_by_name(window_buffer, "input", &input_iter, &end_iter); + gtk_text_buffer_apply_tag_by_name(window_buffer, "glk-input", &input_iter, &end_iter); } /* Internal function: Callback for signal activate on the line input GtkEntry @@ -776,14 +802,14 @@ GtkEntry in a text grid window. */ gboolean on_input_entry_key_press_event(GtkEntry *input_entry, GdkEventKey *event, winid_t win) { - if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up - || event->keyval == GDK_Down || event->keyval == GDK_KP_Down) + if(event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up + || event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down) { /* Prevent falling off the end of the history list */ - if( (event->keyval == GDK_Up || event->keyval == GDK_KP_Up) + if( (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up) && win->history_pos && win->history_pos->next == NULL) return TRUE; - if( (event->keyval == GDK_Down || event->keyval == GDK_KP_Down) + if( (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down) && (win->history_pos == NULL || win->history_pos->prev == NULL) ) return TRUE; @@ -794,7 +820,7 @@ on_input_entry_key_press_event(GtkEntry *input_entry, GdkEventKey *event, winid_ win->history_pos = win->history; } - if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up) + if(event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up) { if(win->history_pos) win->history_pos = g_list_next(win->history_pos); @@ -810,6 +836,11 @@ on_input_entry_key_press_event(GtkEntry *input_entry, GdkEventKey *event, winid_ g_signal_handler_unblock(input_entry, win->line_input_entry_changed); return TRUE; } + else if(g_slist_find(win->current_extra_line_terminators, GUINT_TO_POINTER(event->keyval))) + { + /* If this key was a line terminator, pretend we pressed enter */ + on_input_entry_activate(input_entry, win); + } return FALSE; } @@ -830,47 +861,47 @@ keyval_to_glk_keycode(guint keyval, gboolean unicode) { glui32 keycode; switch(keyval) { - case GDK_Up: - case GDK_KP_Up: return keycode_Up; - case GDK_Down: - case GDK_KP_Down: return keycode_Down; - case GDK_Left: - case GDK_KP_Left: return keycode_Left; - case GDK_Right: - case GDK_KP_Right: return keycode_Right; - case GDK_Linefeed: - case GDK_Return: - case GDK_KP_Enter: return keycode_Return; - case GDK_Delete: - case GDK_BackSpace: - case GDK_KP_Delete: return keycode_Delete; - case GDK_Escape: return keycode_Escape; - case GDK_Tab: - case GDK_KP_Tab: return keycode_Tab; - case GDK_Page_Up: - case GDK_KP_Page_Up: return keycode_PageUp; - case GDK_Page_Down: - case GDK_KP_Page_Down: return keycode_PageDown; - case GDK_Home: - case GDK_KP_Home: return keycode_Home; - case GDK_End: - case GDK_KP_End: return keycode_End; - case GDK_F1: - case GDK_KP_F1: return keycode_Func1; - case GDK_F2: - case GDK_KP_F2: return keycode_Func2; - case GDK_F3: - case GDK_KP_F3: return keycode_Func3; - case GDK_F4: - case GDK_KP_F4: return keycode_Func4; - case GDK_F5: return keycode_Func5; - case GDK_F6: return keycode_Func6; - case GDK_F7: return keycode_Func7; - case GDK_F8: return keycode_Func8; - case GDK_F9: return keycode_Func9; - case GDK_F10: return keycode_Func10; - case GDK_F11: return keycode_Func11; - case GDK_F12: return keycode_Func12; + case GDK_KEY_Up: + case GDK_KEY_KP_Up: return keycode_Up; + case GDK_KEY_Down: + case GDK_KEY_KP_Down: return keycode_Down; + case GDK_KEY_Left: + case GDK_KEY_KP_Left: return keycode_Left; + case GDK_KEY_Right: + case GDK_KEY_KP_Right: return keycode_Right; + case GDK_KEY_Linefeed: + case GDK_KEY_Return: + case GDK_KEY_KP_Enter: return keycode_Return; + case GDK_KEY_Delete: + case GDK_KEY_BackSpace: + case GDK_KEY_KP_Delete: return keycode_Delete; + case GDK_KEY_Escape: return keycode_Escape; + case GDK_KEY_Tab: + case GDK_KEY_KP_Tab: return keycode_Tab; + case GDK_KEY_Page_Up: + case GDK_KEY_KP_Page_Up: return keycode_PageUp; + case GDK_KEY_Page_Down: + case GDK_KEY_KP_Page_Down: return keycode_PageDown; + case GDK_KEY_Home: + case GDK_KEY_KP_Home: return keycode_Home; + case GDK_KEY_End: + case GDK_KEY_KP_End: return keycode_End; + case GDK_KEY_F1: + case GDK_KEY_KP_F1: return keycode_Func1; + case GDK_KEY_F2: + case GDK_KEY_KP_F2: return keycode_Func2; + case GDK_KEY_F3: + case GDK_KEY_KP_F3: return keycode_Func3; + case GDK_KEY_F4: + case GDK_KEY_KP_F4: return keycode_Func4; + case GDK_KEY_F5: return keycode_Func5; + case GDK_KEY_F6: return keycode_Func6; + case GDK_KEY_F7: return keycode_Func7; + case GDK_KEY_F8: return keycode_Func8; + case GDK_KEY_F9: return keycode_Func9; + case GDK_KEY_F10: return keycode_Func10; + case GDK_KEY_F11: return keycode_Func11; + case GDK_KEY_F12: return keycode_Func12; default: keycode = gdk_keyval_to_unicode(keyval); /* If keycode is 0, then keyval was not recognized; also return @@ -885,7 +916,7 @@ keyval_to_glk_keycode(guint keyval, gboolean unicode) void force_char_input_from_queue(winid_t win, event_t *event) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); guint keyval = GPOINTER_TO_UINT(g_async_queue_pop(glk_data->char_input_queue)); glk_cancel_char_event(win); @@ -905,7 +936,7 @@ force_char_input_from_queue(winid_t win, event_t *event) void force_line_input_from_queue(winid_t win, event_t *event) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); const gchar *text = g_async_queue_pop(glk_data->line_input_queue); glui32 chars_written = 0; @@ -933,7 +964,7 @@ force_line_input_from_queue(winid_t win, event_t *event) { gtk_text_buffer_get_end_iter(buffer, &end); gchar *text_to_insert = g_strconcat(text, "\n", NULL); - gtk_text_buffer_insert_with_tags_by_name(buffer, &end, text_to_insert, -1, "default", "input", NULL); + gtk_text_buffer_insert_with_tags_by_name(buffer, &end, text_to_insert, -1, "default", "input", "glk-input", NULL); } chars_written = finish_text_buffer_line_input(win, TRUE); @@ -1028,55 +1059,55 @@ keycode_to_gdk_keyval(glui32 keycode) switch (keycode) { case keycode_Left: - return GDK_Left; + return GDK_KEY_Left; case keycode_Right: - return GDK_Right; + return GDK_KEY_Right; case keycode_Up: - return GDK_Up; + return GDK_KEY_Up; case keycode_Down: - return GDK_Down; + return GDK_KEY_Down; case keycode_Return: - return GDK_Return; + return GDK_KEY_Return; case keycode_Delete: - return GDK_Delete; + return GDK_KEY_Delete; case keycode_Escape: - return GDK_Escape; + return GDK_KEY_Escape; case keycode_Tab: - return GDK_Tab; + return GDK_KEY_Tab; case keycode_PageUp: - return GDK_Page_Up; + return GDK_KEY_Page_Up; case keycode_PageDown: - return GDK_Page_Down; + return GDK_KEY_Page_Down; case keycode_Home: - return GDK_Home; + return GDK_KEY_Home; case keycode_End: - return GDK_End; + return GDK_KEY_End; case keycode_Func1: - return GDK_F1; + return GDK_KEY_F1; case keycode_Func2: - return GDK_F2; + return GDK_KEY_F2; case keycode_Func3: - return GDK_F3; + return GDK_KEY_F3; case keycode_Func4: - return GDK_F4; + return GDK_KEY_F4; case keycode_Func5: - return GDK_F5; + return GDK_KEY_F5; case keycode_Func6: - return GDK_F6; + return GDK_KEY_F6; case keycode_Func7: - return GDK_F7; + return GDK_KEY_F7; case keycode_Func8: - return GDK_F8; + return GDK_KEY_F8; case keycode_Func9: - return GDK_F9; + return GDK_KEY_F9; case keycode_Func10: - return GDK_F10; + return GDK_KEY_F10; case keycode_Func11: - return GDK_F11; + return GDK_KEY_F11; case keycode_Func12: - return GDK_F12; + return GDK_KEY_F12; case keycode_Erase: - return GDK_BackSpace; + return GDK_KEY_BackSpace; } unsigned keyval = gdk_unicode_to_keyval(keycode); if(keyval < 0x01000000) /* magic number meaning illegal unicode point */ @@ -1156,4 +1187,4 @@ glk_set_terminators_line_event(winid_t win, glui32 *keycodes, glui32 count) else WARNING_S("Ignoring invalid line terminator", gdk_keyval_name(key)); } -} \ No newline at end of file +}