X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;ds=sidebyside;f=libchimara%2Finput.c;h=7f8038c38793de0242dfa47577f1d98894361f2a;hb=476e8909f7b56201452e6c967fc6839a64fa92b0;hp=df872da5496c6d582142b98b63c692e0e2864dce;hpb=d650d232de0f03f7d6be4a9b50d1bb3c825d24fb;p=projects%2Fchimara%2Fchimara.git
diff --git a/libchimara/input.c b/libchimara/input.c
index df872da..7f8038c 100644
--- a/libchimara/input.c
+++ b/libchimara/input.c
@@ -1,6 +1,7 @@
#include "charset.h"
#include "magic.h"
#include "input.h"
+#include "pager.h"
#include "chimara-glk-private.h"
extern GPrivate *glk_data_key;
@@ -27,20 +28,6 @@ request_char_event_common(winid_t win, gboolean unicode)
g_signal_handler_unblock( win->widget, win->char_input_keypress_handler );
gdk_threads_enter();
-
- /* If the request is in a text buffer window, scroll to the end of the
- text buffer. TODO: This may scroll text off the top of the window that the
- user hasn't read yet. We need to implement a paging mechanism. */
- if(win->type == wintype_TextBuffer)
- {
- GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
- GtkTextIter iter;
- gtk_text_buffer_get_end_iter(buffer, &iter);
- gtk_text_buffer_place_cursor(buffer, &iter);
- gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(win->widget), gtk_text_buffer_get_insert(buffer));
- /* Why doesn't this always work?? */
- }
-
gtk_widget_grab_focus( GTK_WIDGET(win->widget) );
gdk_threads_leave();
@@ -141,7 +128,11 @@ text_grid_request_line_event_common(winid_t win, glui32 maxlen, gboolean insert,
/* Make the entry as small as possible to fit with the text */
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);
@@ -195,9 +186,6 @@ text_buffer_request_line_event_common(winid_t win, glui32 maxlen, gboolean inser
gtk_text_buffer_get_end_iter(buffer, &end_iter); /* update after text insertion */
}
- /* Scroll to input point */
- gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(win->widget), input_position);
-
/* Apply the correct style to the input prompt */
GtkTextIter input_iter;
gtk_text_buffer_get_iter_at_mark(buffer, &input_iter, input_position);
@@ -285,11 +273,28 @@ glk_request_line_event(winid_t win, char *buf, glui32 maxlen, glui32 initlen)
* glui32 values instead of an array of characters, and the values
* may be any valid Unicode code points.
*
- * The result will be in Unicode Normalization Form C. This basically means that
- * composite characters will be single characters where possible, instead of
- * sequences of base and combining marks. See
- * Unicode Standard Annex
- * #15 for the details.
+ * If possible, the library should return fully composed Unicode characters,
+ * rather than strings of base and composition characters.
+ *
+ *
+ * Fully-composed characters are the norm for Unicode text, so an
+ * implementation that ignores this issue will probably produce the right
+ * result. However, the game may not want to rely on that. Another factor is
+ * that case-folding can (occasionally) produce non-normalized text.
+ * Therefore, to cover all its bases, a game should call
+ * glk_buffer_to_lower_case_uni(), followed by
+ * glk_buffer_canon_normalize_uni(), before parsing.
+ *
+ *
+ *
+ * Earlier versions of this spec said that line input must always be in
+ * Unicode Normalization Form C. However, this has not been universally
+ * implemented. It is also somewhat redundant, for the results noted above.
+ * Therefore, we now merely recommend that line input be fully composed. The
+ * game is ultimately responsible for all case-folding and normalization. See
+ * Unicode String
+ * Normalization.
+ *
*/
void
glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initlen)
@@ -306,6 +311,8 @@ glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initl
if(glk_data->register_arr)
win->buffer_rock = (*glk_data->register_arr)(buf, maxlen, "&+#!Iu");
+
+
win->input_request_type = INPUT_REQUEST_LINE_UNICODE;
win->line_input_buffer_unicode = buf;
win->line_input_buffer_max_len = maxlen;
@@ -430,6 +437,15 @@ on_shutdown_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win)
gboolean
on_char_input_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win)
{
+ /* Ignore modifier keys, otherwise the char input will already trigger on
+ the shift key when the user tries to type a capital letter */
+ if(event->is_modifier)
+ return FALSE; /* don't stop the event */
+
+ /* All text up to the input position is now regarded as being read by the user */
+ if(win->type == wintype_TextBuffer)
+ pager_update(win);
+
glui32 keycode = keyval_to_glk_keycode(event->keyval, win->input_request_type == INPUT_REQUEST_CHARACTER_UNICODE);
ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(widget, CHIMARA_TYPE_GLK));
@@ -450,12 +466,16 @@ on_line_input_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win
switch(win->type)
{
case wintype_TextBuffer:
+ /* All text up to the input position is now regarded as being read by the user */
+ pager_update(win);
/* History up/down */
if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up
|| event->keyval == GDK_Down || event->keyval == GDK_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)
&& win->history_pos && win->history_pos->next == NULL)
return TRUE;
@@ -492,7 +512,7 @@ on_line_input_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win
gtk_text_buffer_get_end_iter(buffer, &end);
g_signal_handler_block(buffer, win->insert_text_handler);
- gtk_text_buffer_insert_with_tags_by_name(buffer, &end, win->history_pos->data, -1, "input", NULL);
+ gtk_text_buffer_insert_with_tags_by_name(buffer, &end, win->history_pos->data, -1, "default", "input", NULL);
g_signal_handler_unblock(buffer, win->insert_text_handler);
return TRUE;
}
@@ -909,7 +929,7 @@ force_line_input_from_queue(winid_t win, event_t *event)
/* Insert the forced input into the window */
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, "input", NULL);
+ gtk_text_buffer_insert_with_tags_by_name(buffer, &end, text_to_insert, -1, "default", "input", NULL);
chars_written = finish_text_buffer_line_input(win, TRUE);
}
else if(win->type == wintype_TextGrid)
@@ -950,3 +970,77 @@ cancel_old_input_request(winid_t win)
WARNING("Could not cancel pending input request: unknown input request");
}
}
+
+/**
+ * glk_set_echo_line_event:
+ * @win: The window in which to change the echoing behavior.
+ * @val: Zero to turn off echoing, nonzero for normal echoing.
+ *
+ * Normally, after line input is completed or cancelled in a buffer window, the
+ * library ensures that the complete input line (or its latest state, after
+ * cancelling) is displayed at the end of the buffer, followed by a newline.
+ * This call allows you to suppress this behavior. If the @val argument is zero,
+ * all subsequent line input requests in the given window
+ * will leave the buffer unchanged after the input is completed or cancelled;
+ * the player's input will not be printed. If @val is nonzero, subsequent input
+ * requests will have the normal printing behavior.
+ *
+ *
+ * Note that this feature is unrelated to the window's echo stream.
+ *
+ *
+ * If you turn off line input echoing, you can reproduce the standard input
+ * behavior by following each line input event (or line input cancellation) by
+ * printing the input line, in the Input style, followed by a newline in the
+ * original style.
+ *
+ * The glk_set_echo_line_event() does not affect a pending line input request.
+ * It also has no effect in non-buffer windows.
+ *
+ * In a grid window, the game can overwrite the input area at will, so there
+ * is no need for this distinction.
+ *
+ *
+ * Not all libraries support this feature. You can test for it with
+ * %gestalt_LineInputEcho.
+ */
+void
+glk_set_echo_line_event(winid_t win, glui32 val)
+{
+ VALID_WINDOW(win, return);
+}
+
+/**
+ * glk_set_terminators_line_event:
+ * @win: The window for which to set the line input terminator keys.
+ * @keycodes: An array of keycode_ constants, of length @count.
+ * @count: The array length of @keycodes.
+ *
+ * It is possible to request that other keystrokes complete line input as well.
+ * (This allows a game to intercept function keys or other special keys during
+ * line input.) To do this, call glk_set_terminators_line_event(), and pass an
+ * array of @count keycodes. These must all be special keycodes (see Character Input). Do not include
+ * regular printable characters in the array, nor %keycode_Return (which
+ * represents the default enter key and will always be
+ * recognized). To return to the default behavior, pass a %NULL or empty array.
+ *
+ * The glk_set_terminators_line_event() affects subsequent
+ * line input requests in the given window. It does not affect a pending line
+ * input request.
+ *
+ *
+ * This distinction makes life easier for interpreters that set up UI
+ * callbacks only at the start of input.
+ *
+ *
+ * A library may not support this feature; if it does, it may not support all
+ * special keys as terminators. (Some keystrokes are reserved for OS or
+ * interpreter control.) You can test for this with %gestalt_LineTerminators and
+ * %gestalt_LineTerminatorKey.
+ */
+void
+glk_set_terminators_line_event(winid_t win, glui32 *keycodes, glui32 count)
+{
+ VALID_WINDOW(win, return);
+}
\ No newline at end of file