X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=src%2Finput.c;h=e55ed23bb721fe91bf44d448de14bbd46fcaa55f;hb=179cdda7e4d5713b3f90d0f01030c58e14557328;hp=22f321cc1488a672ea66078cf56296989febd8c1;hpb=28f28489053a6956c8fbce493bb9ce18c7d872c8;p=projects%2Fchimara%2Fchimara.git diff --git a/src/input.c b/src/input.c index 22f321c..e55ed23 100644 --- a/src/input.c +++ b/src/input.c @@ -1,6 +1,9 @@ +#include "charset.h" +#include "magic.h" #include "input.h" -/** glk_request_char_event: +/** + * glk_request_char_event: * @win: A window to request char events from. * * Request input of a Latin-1 character or special key. A window cannot have @@ -12,7 +15,7 @@ void glk_request_char_event(winid_t win) { - g_return_if_fail(win); + VALID_WINDOW(win, return); g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE); g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid); @@ -20,7 +23,8 @@ glk_request_char_event(winid_t win) g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler ); } -/** glk_request_char_event_uni: +/** + * glk_request_char_event_uni: * @win: A window to request char events from. * * Request input of a Unicode character or special key. See @@ -29,7 +33,7 @@ glk_request_char_event(winid_t win) void glk_request_char_event_uni(winid_t win) { - g_return_if_fail(win); + VALID_WINDOW(win, return); g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE); g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid); @@ -37,8 +41,23 @@ glk_request_char_event_uni(winid_t win) g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler ); } -/* Internal function: Request either latin-1 or unicode line input, in a text grid window. */ +/** + * glk_cancel_char_event: + * @win: A window to cancel the latest char event request on. + * + * Cancels the last char event request on the given window. + */ void +glk_cancel_char_event(winid_t win) +{ + /* TODO: write me */ + VALID_WINDOW(win, return); + g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE); + g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid); +} + +/* Internal function: Request either latin-1 or unicode line input, in a text grid window. */ +static void text_grid_request_line_event_common(winid_t win, glui32 maxlen, gboolean insert, gchar *inserttext) { GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) ); @@ -56,6 +75,17 @@ text_grid_request_line_event_common(winid_t win, glui32 maxlen, gboolean insert, end_iter = start_iter; gtk_text_iter_set_line_offset(&end_iter, cursorpos + win->input_length); + /* If the buffer currently has a selection with one bound in the middle of + the input field, then deselect it. Otherwise the input field gets trashed */ + GtkTextIter start_sel, end_sel; + if( gtk_text_buffer_get_selection_bounds(buffer, &start_sel, &end_sel) ) + { + if( gtk_text_iter_in_range(&start_sel, &start_iter, &end_iter) ) + gtk_text_buffer_place_cursor(buffer, &end_sel); + if( gtk_text_iter_in_range(&end_sel, &start_iter, &end_iter) ) + gtk_text_buffer_place_cursor(buffer, &start_sel); + } + /* Erase the text currently in the input field and replace it with a GtkEntry */ gtk_text_buffer_delete(buffer, &start_iter, &end_iter); win->input_anchor = gtk_text_buffer_create_child_anchor(buffer, &start_iter); @@ -88,7 +118,7 @@ text_grid_request_line_event_common(winid_t win, glui32 maxlen, gboolean insert, } /* Internal function: Request either latin-1 or unicode line input, in a text buffer window. */ -void +static void text_buffer_request_line_event_common(winid_t win, glui32 maxlen, gboolean insert, gchar *inserttext) { GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) ); @@ -145,7 +175,7 @@ text_buffer_request_line_event_common(winid_t win, glui32 maxlen, gboolean inser void glk_request_line_event(winid_t win, char* buf, glui32 maxlen, glui32 initlen) { - g_return_if_fail(win); + VALID_WINDOW(win, return); g_return_if_fail(buf); g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE); g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid); @@ -164,8 +194,6 @@ glk_request_line_event(winid_t win, char* buf, glui32 maxlen, glui32 initlen) case wintype_TextGrid: text_grid_request_line_event_common(win, maxlen, (initlen > 0), inserttext); break; - default: - g_assert_not_reached(); } g_free(inserttext); } @@ -191,7 +219,7 @@ glk_request_line_event(winid_t win, char* buf, glui32 maxlen, glui32 initlen) void glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initlen) { - g_return_if_fail(win); + VALID_WINDOW(win, return); g_return_if_fail(buf); g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE); g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid); @@ -203,14 +231,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(""); @@ -223,12 +246,37 @@ glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initl case wintype_TextGrid: text_grid_request_line_event_common(win, maxlen, (initlen > 0), utf8); break; - default: - g_assert_not_reached(); } g_free(utf8); } +/** + * glk_cancel_line_event: + * @win: A text buffer or text grid window to cancel line input on. + * @event: Will be filled in if the user had already input something. + * + * This cancels a pending request for line input. (Either Latin-1 or Unicode.) + * + * The event pointed to by the event argument will be filled in as if the + * player had hit enter, and the input composed so far will be stored in the + * buffer; see below. If you do not care about this information, pass NULL as + * the event argument. (The buffer will still be filled.) + * + * For convenience, it is legal to call glk_cancel_line_event() even if there + * is no line input request on that window. The event type will be set to + * evtype_None in this case. + */ +void +glk_cancel_line_event(winid_t win, event_t *event) +{ + /* TODO: write me */ + VALID_WINDOW(win, return); + g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE); + g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid); + + event = NULL; +} + /* 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) @@ -236,10 +284,20 @@ 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) ) { - gboolean retval = TRUE; - g_signal_emit_by_name(win->input_entry, "key-press-event", event, &retval); + 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 && @@ -315,14 +373,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; } @@ -339,21 +394,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); @@ -362,13 +414,16 @@ end_line_input_request(winid_t win, const gchar *inserted_text) event_throw(evtype_LineInput, win, copycount, 0); } else - g_warning("%s: Wrong input request type.", __func__); + WARNING("Wrong input request type"); win->input_request_type = INPUT_REQUEST_NONE; } /* 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) { @@ -386,6 +441,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); @@ -427,3 +483,4 @@ on_input_entry_activate(GtkEntry *input_entry, winid_t win) end_line_input_request(win, text); g_free(text); } +