4 #include "chimara-glk-private.h"
6 extern GPrivate *glk_data_key;
8 /* Forward declarations */
9 static int finish_text_buffer_line_input(winid_t win, gboolean emit_signal);
10 static int finish_text_grid_line_input(winid_t win, gboolean emit_signal);
12 /* Internal function: code common to both flavors of char event request */
14 request_char_event_common(winid_t win, gboolean unicode)
16 VALID_WINDOW(win, return);
17 g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
18 g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
20 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
22 win->input_request_type = unicode? INPUT_REQUEST_CHARACTER_UNICODE : INPUT_REQUEST_CHARACTER;
23 g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler );
27 /* If the request is in a text buffer window, scroll to the end of the
28 text buffer. TODO: This may scroll text off the top of the window that the
29 user hasn't read yet. We need to implement a paging mechanism. */
30 if(win->type == wintype_TextBuffer)
32 GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
34 gtk_text_buffer_get_end_iter(buffer, &iter);
35 gtk_text_buffer_place_cursor(buffer, &iter);
36 gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(win->widget), gtk_text_buffer_get_insert(buffer));
37 /* Why doesn't this always work?? */
40 gtk_widget_grab_focus( GTK_WIDGET(win->widget) );
43 /* Emit the "waiting" signal to let listeners know we are ready for input */
44 g_signal_emit_by_name(glk_data->self, "waiting");
48 * glk_request_char_event:
49 * @win: A window to request char events from.
51 * Request input of a Latin-1 character or special key. A window cannot have
52 * requests for both character and line input at the same time. Nor can it have
53 * requests for character input of both types (Latin-1 and Unicode). It is
54 * illegal to call glk_request_char_event() if the window already has a pending
55 * request for either character or line input.
58 glk_request_char_event(winid_t win)
60 request_char_event_common(win, FALSE);
64 * glk_request_char_event_uni:
65 * @win: A window to request char events from.
67 * Request input of a Unicode character or special key. See
68 * glk_request_char_event().
71 glk_request_char_event_uni(winid_t win)
73 request_char_event_common(win, TRUE);
77 * glk_cancel_char_event:
78 * @win: A window to cancel the latest char event request on.
80 * This cancels a pending request for character input. (Either Latin-1 or
81 * Unicode.) For convenience, it is legal to call glk_cancel_char_event() even
82 * if there is no charcter input request on that window. Glk will ignore the
86 glk_cancel_char_event(winid_t win)
88 VALID_WINDOW(win, return);
89 g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
91 if(win->input_request_type == INPUT_REQUEST_CHARACTER || win->input_request_type == INPUT_REQUEST_CHARACTER_UNICODE)
93 win->input_request_type = INPUT_REQUEST_NONE;
94 g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
98 /* Internal function: Request either latin-1 or unicode line input, in a text grid window. */
100 text_grid_request_line_event_common(winid_t win, glui32 maxlen, gboolean insert, gchar *inserttext)
104 GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
106 GtkTextMark *cursor = gtk_text_buffer_get_mark(buffer, "cursor_position");
107 GtkTextIter start_iter, end_iter;
108 gtk_text_buffer_get_iter_at_mark(buffer, &start_iter, cursor);
110 /* Determine the maximum length of the line input */
111 gint cursorpos = gtk_text_iter_get_line_offset(&start_iter);
112 /* Odd; the Glk spec says the maximum input length is
113 windowwidth - 1 - cursorposition. I say no, because if cursorposition is
114 zero, then the input should fill the whole line. FIXME??? */
115 win->input_length = MIN(win->width - cursorpos, win->line_input_buffer_max_len);
116 end_iter = start_iter;
117 gtk_text_iter_set_line_offset(&end_iter, cursorpos + win->input_length);
119 /* If the buffer currently has a selection with one bound in the middle of
120 the input field, then deselect it. Otherwise the input field gets trashed */
121 GtkTextIter start_sel, end_sel;
122 if( gtk_text_buffer_get_selection_bounds(buffer, &start_sel, &end_sel) )
124 if( gtk_text_iter_in_range(&start_sel, &start_iter, &end_iter) )
125 gtk_text_buffer_place_cursor(buffer, &end_sel);
126 if( gtk_text_iter_in_range(&end_sel, &start_iter, &end_iter) )
127 gtk_text_buffer_place_cursor(buffer, &start_sel);
130 /* Erase the text currently in the input field and replace it with a GtkEntry */
131 gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
132 win->input_anchor = gtk_text_buffer_create_child_anchor(buffer, &start_iter);
133 win->input_entry = gtk_entry_new();
134 /* Set the entry's font to match that of the window */
135 GtkRcStyle *style = gtk_widget_get_modifier_style(win->widget); /* Don't free */
136 gtk_widget_modify_font(win->input_entry, style->font_desc);
137 /* Make the entry as small as possible to fit with the text */
138 gtk_entry_set_has_frame(GTK_ENTRY(win->input_entry), FALSE);
139 GtkBorder border = { 0, 0, 0, 0 };
140 gtk_entry_set_inner_border(GTK_ENTRY(win->input_entry), &border);
141 gtk_entry_set_max_length(GTK_ENTRY(win->input_entry), win->input_length);
142 gtk_entry_set_width_chars(GTK_ENTRY(win->input_entry), win->input_length);
144 /* Insert pre-entered text if needed */
146 gtk_entry_set_text(GTK_ENTRY(win->input_entry), inserttext);
148 /* Set background color of entry (TODO: implement as property) */
150 gdk_color_parse("grey", &background);
151 gtk_widget_modify_base(win->input_entry, GTK_STATE_NORMAL, &background);
153 g_signal_connect(win->input_entry, "activate", G_CALLBACK(on_input_entry_activate), win);
155 gtk_widget_show(win->input_entry);
156 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(win->widget), win->input_entry, win->input_anchor);
158 g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler );
160 gtk_widget_grab_focus(win->input_entry);
165 /* Internal function: Request either latin-1 or unicode line input, in a text buffer window. */
167 text_buffer_request_line_event_common(winid_t win, glui32 maxlen, gboolean insert, gchar *inserttext)
171 GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
173 /* Move the input_position mark to the end of the window_buffer */
174 GtkTextMark *input_position = gtk_text_buffer_get_mark(buffer, "input_position");
175 GtkTextIter end_iter;
176 gtk_text_buffer_get_end_iter(buffer, &end_iter);
177 gtk_text_buffer_move_mark(buffer, input_position, &end_iter);
179 /* Set the entire contents of the window_buffer as uneditable
180 * (so input can only be entered at the end) */
181 GtkTextIter start_iter;
182 gtk_text_buffer_get_start_iter(buffer, &start_iter);
183 gtk_text_buffer_remove_tag_by_name(buffer, "uneditable", &start_iter, &end_iter);
184 gtk_text_buffer_apply_tag_by_name(buffer, "uneditable", &start_iter, &end_iter);
186 /* Insert pre-entered text if needed */
188 gtk_text_buffer_insert(buffer, &end_iter, inserttext, -1);
190 /* Scroll to input point */
191 gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(win->widget), input_position);
193 gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), TRUE);
194 g_signal_handler_unblock(buffer, win->insert_text_handler);
196 gtk_widget_grab_focus(win->widget);
202 * glk_request_line_event:
203 * @win: A text buffer or text grid window to request line input on.
204 * @buf: A buffer of at least @maxlen bytes.
205 * @maxlen: Length of the buffer.
206 * @initlen: The number of characters in @buf to pre-enter.
208 * Requests input of a line of Latin-1 characters. A window cannot have requests
209 * for both character and line input at the same time. Nor can it have requests
210 * for line input of both types (Latin-1 and Unicode). It is illegal to call
211 * glk_request_line_event() if the window already has a pending request for
212 * either character or line input.
214 * The @buf argument is a pointer to space where the line input will be stored.
215 * (This may not be %NULL.) @maxlen is the length of this space, in bytes; the
216 * library will not accept more characters than this. If @initlen is nonzero,
217 * then the first @initlen bytes of @buf will be entered as pre-existing input
218 * — just as if the player had typed them himself. (The player can continue
219 * composing after this pre-entered input, or delete it or edit as usual.)
221 * The contents of the buffer are undefined until the input is completed (either
222 * by a line input event, or glk_cancel_line_event(). The library may or may not
223 * fill in the buffer as the player composes, while the input is still pending;
224 * it is illegal to change the contents of the buffer yourself.
227 glk_request_line_event(winid_t win, char *buf, glui32 maxlen, glui32 initlen)
229 VALID_WINDOW(win, return);
230 g_return_if_fail(buf);
231 g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
232 g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
233 g_return_if_fail(initlen <= maxlen);
235 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
237 /* Register the buffer */
238 if(glk_data->register_arr)
239 win->buffer_rock = (*glk_data->register_arr)(buf, maxlen, "&+#!Cn");
241 win->input_request_type = INPUT_REQUEST_LINE;
242 win->line_input_buffer = buf;
243 win->line_input_buffer_max_len = maxlen;
245 gchar *inserttext = (initlen > 0)? g_strndup(buf, initlen) : g_strdup("");
248 case wintype_TextBuffer:
249 text_buffer_request_line_event_common(win, maxlen, (initlen > 0), inserttext);
251 case wintype_TextGrid:
252 text_grid_request_line_event_common(win, maxlen, (initlen > 0), inserttext);
257 /* Emit the "waiting" signal to let listeners know we are ready for input */
258 g_signal_emit_by_name(glk_data->self, "waiting");
262 * glk_request_line_event_uni:
263 * @win: A text buffer or text grid window to request line input on.
264 * @buf: A buffer of at least @maxlen characters.
265 * @maxlen: Length of the buffer.
266 * @initlen: The number of characters in @buf to pre-enter.
268 * Request input of a line of Unicode characters. This works the same as
269 * glk_request_line_event(), except the result is stored in an array of
270 * <type>glui32</type> values instead of an array of characters, and the values
271 * may be any valid Unicode code points.
273 * The result will be in Unicode Normalization Form C. This basically means that
274 * composite characters will be single characters where possible, instead of
275 * sequences of base and combining marks. See
276 * <ulink url="http://www.unicode.org/reports/tr15/">Unicode Standard Annex
277 * #15</ulink> for the details.
280 glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initlen)
282 VALID_WINDOW(win, return);
283 g_return_if_fail(buf);
284 g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
285 g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
286 g_return_if_fail(initlen <= maxlen);
288 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
290 /* Register the buffer */
291 if(glk_data->register_arr)
292 win->buffer_rock = (*glk_data->register_arr)(buf, maxlen, "&+#!Iu");
294 win->input_request_type = INPUT_REQUEST_LINE_UNICODE;
295 win->line_input_buffer_unicode = buf;
296 win->line_input_buffer_max_len = maxlen;
300 utf8 = convert_ucs4_to_utf8(buf, initlen);
309 case wintype_TextBuffer:
310 text_buffer_request_line_event_common(win, maxlen, (initlen > 0), utf8);
312 case wintype_TextGrid:
313 text_grid_request_line_event_common(win, maxlen, (initlen > 0), utf8);
318 /* Emit the "waiting" signal to let listeners know we are ready for input */
319 g_signal_emit_by_name(glk_data->self, "waiting");
323 * glk_cancel_line_event:
324 * @win: A text buffer or text grid window to cancel line input on.
325 * @event: Will be filled in if the user had already input something.
327 * This cancels a pending request for line input. (Either Latin-1 or Unicode.)
329 * The event pointed to by the event argument will be filled in as if the
330 * player had hit <keycap>enter</keycap>, and the input composed so far will be
331 * stored in the buffer; see below. If you do not care about this information,
332 * pass %NULL as the @event argument. (The buffer will still be filled.)
334 * For convenience, it is legal to call glk_cancel_line_event() even if there
335 * is no line input request on that window. The event type will be set to
336 * %evtype_None in this case.
339 glk_cancel_line_event(winid_t win, event_t *event)
341 VALID_WINDOW(win, return);
342 g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
345 event->type = evtype_None;
351 if(win->input_request_type != INPUT_REQUEST_LINE && win->input_request_type != INPUT_REQUEST_LINE_UNICODE)
354 g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
356 int chars_written = 0;
358 if(win->type == wintype_TextGrid) {
359 g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
360 chars_written = finish_text_grid_line_input(win, FALSE);
361 } else if(win->type == wintype_TextBuffer) {
362 GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
363 g_signal_handler_block(window_buffer, win->insert_text_handler);
364 chars_written = finish_text_buffer_line_input(win, FALSE);
367 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
368 if(glk_data->unregister_arr)
370 if(win->input_request_type == INPUT_REQUEST_LINE_UNICODE)
371 (*glk_data->unregister_arr)(win->line_input_buffer_unicode, win->line_input_buffer_max_len, "&+#!Iu", win->buffer_rock);
373 (*glk_data->unregister_arr)(win->line_input_buffer, win->line_input_buffer_max_len, "&+#!Cn", win->buffer_rock);
376 if(event != NULL && chars_written > 0) {
377 event->type = evtype_LineInput;
378 event->val1 = chars_written;
382 /* 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. */
384 on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win)
386 /* If this is a text grid window, and line input is active, then redirect the key press to the line input GtkEntry */
387 if( win->type == wintype_TextGrid && (win->input_request_type == INPUT_REQUEST_LINE || win->input_request_type == INPUT_REQUEST_LINE_UNICODE) )
389 if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up
390 || event->keyval == GDK_Down || event->keyval == GDK_KP_Down
391 || event->keyval == GDK_Left || event->keyval == GDK_KP_Left
392 || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
393 || event->keyval == GDK_Tab || event->keyval == GDK_KP_Tab
394 || event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up
395 || event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down
396 || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
397 || event->keyval == GDK_End || event->keyval == GDK_KP_End)
398 return FALSE; /* Don't redirect these keys */
399 gtk_widget_grab_focus(win->input_entry);
400 gtk_editable_set_position(GTK_EDITABLE(win->input_entry), -1);
401 gboolean retval = TRUE;
402 g_signal_emit_by_name(win->input_entry, "key-press-event", event, &retval);
403 return retval; /* Block this key event if the entry handled it */
405 if(win->input_request_type != INPUT_REQUEST_CHARACTER &&
406 win->input_request_type != INPUT_REQUEST_CHARACTER_UNICODE)
409 glui32 keycode = keyval_to_glk_keycode(event->keyval, win->input_request_type == INPUT_REQUEST_CHARACTER_UNICODE);
411 ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(widget, CHIMARA_TYPE_GLK));
413 event_throw(glk, evtype_CharInput, win, keycode, 0);
414 g_signal_emit_by_name(glk, "char-input", win->rock, event->keyval);
416 /* Only one keypress will be handled */
417 win->input_request_type = INPUT_REQUEST_NONE;
418 g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
423 /* Internal function: finish handling a line input request, for both text grid and text buffer windows. */
425 write_to_window_buffer(winid_t win, const gchar *inserted_text)
429 /* Convert the string from UTF-8 to Latin-1 or Unicode */
430 if(win->input_request_type == INPUT_REQUEST_LINE)
433 gchar *latin1 = convert_utf8_to_latin1(inserted_text, &bytes_written);
438 /* Place input in the echo stream */
439 if(win->echo_stream != NULL)
440 glk_put_string_stream(win->echo_stream, latin1);
442 /* Copy the string (bytes_written does not include the NULL at the end) */
443 copycount = MIN(win->line_input_buffer_max_len, bytes_written);
444 memcpy(win->line_input_buffer, latin1, copycount);
447 else if(win->input_request_type == INPUT_REQUEST_LINE_UNICODE)
450 gunichar *unicode = convert_utf8_to_ucs4(inserted_text, &items_written);
455 /* Place input in the echo stream */
456 if(win->echo_stream != NULL)
457 glk_put_string_stream_uni(win->echo_stream, unicode);
459 /* Copy the string (but not the NULL at the end) */
460 copycount = MIN(win->line_input_buffer_max_len, items_written);
461 memcpy(win->line_input_buffer_unicode, unicode, copycount * sizeof(gunichar));
465 WARNING("Wrong input request type");
467 win->input_request_type = INPUT_REQUEST_NONE;
471 /* Internal function: Retrieves the input of a TextBuffer window and stores it in the window buffer.
472 * Returns the number of characters written, suitable for inclusion in a line input event. */
474 finish_text_buffer_line_input(winid_t win, gboolean emit_signal)
476 VALID_WINDOW(win, return 0);
477 g_return_val_if_fail(win->type == wintype_TextBuffer, 0);
479 GtkTextIter start_iter, end_iter, last_character;
481 GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
482 GtkTextMark *input_position = gtk_text_buffer_get_mark(window_buffer, "input_position");
483 gtk_text_buffer_get_iter_at_mark(window_buffer, &start_iter, input_position);
484 gtk_text_buffer_get_end_iter(window_buffer, &end_iter);
485 gtk_text_buffer_get_end_iter(window_buffer, &last_character);
486 gtk_text_iter_backward_cursor_position(&last_character);
488 gchar* last_char = gtk_text_buffer_get_text(window_buffer, &last_character, &end_iter, FALSE);
490 if( strchr(last_char, '\n') != NULL )
491 gtk_text_iter_backward_cursor_position(&end_iter);
493 gchar* inserted_text = gtk_text_buffer_get_text(window_buffer, &start_iter, &end_iter, FALSE);
495 int chars_written = write_to_window_buffer(win, inserted_text);
498 ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
500 g_signal_emit_by_name(glk, "line-input", win->rock, inserted_text);
502 g_free(inserted_text);
504 return chars_written;
507 /* Internal function: Retrieves the input of a TextGrid window and stores it in the window buffer.
508 * Returns the number of characters written, suitable for inclusion in a line input event. */
510 finish_text_grid_line_input(winid_t win, gboolean emit_signal)
512 VALID_WINDOW(win, return 0);
513 g_return_val_if_fail(win->type == wintype_TextGrid, 0);
515 GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
517 gchar *text = g_strdup( gtk_entry_get_text(GTK_ENTRY(win->input_entry)) );
518 /* Move the focus back into the text view */
519 gtk_widget_grab_focus(win->widget);
520 /* Remove entry widget from text view */
521 /* Should be ok even though this is the widget's own signal handler */
522 gtk_container_remove( GTK_CONTAINER(win->widget), GTK_WIDGET(win->input_entry) );
523 win->input_entry = NULL;
524 /* Delete the child anchor */
525 GtkTextIter start, end;
526 gtk_text_buffer_get_iter_at_child_anchor(buffer, &start, win->input_anchor);
528 gtk_text_iter_forward_char(&end); /* Point after the child anchor */
529 gtk_text_buffer_delete(buffer, &start, &end);
530 win->input_anchor = NULL;
532 gchar *spaces = g_strnfill(win->input_length - g_utf8_strlen(text, -1), ' ');
533 gchar *text_to_insert = g_strconcat(text, spaces, NULL);
535 gtk_text_buffer_insert(buffer, &start, text_to_insert, -1);
536 g_free(text_to_insert);
538 int chars_written = write_to_window_buffer(win, text);
541 ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
543 g_signal_emit_by_name(glk, "line-input", win->rock, text);
547 return chars_written;
550 /* Internal function: Callback for signal insert-text on a text buffer window.
551 Runs after the default handler has already inserted the text.
552 FIXME: This function assumes that newline was the last character typed into the
553 window. That assumption is wrong if, for example, text containing a newline was
554 pasted into the window. */
556 after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, winid_t win)
558 if( strchr(text, '\n') != NULL )
560 /* Remove signal handlers */
561 GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
562 g_signal_handler_block(window_buffer, win->insert_text_handler);
564 /* Make the window uneditable again and retrieve the text that was input */
565 gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), FALSE);
567 int chars_written = finish_text_buffer_line_input(win, TRUE);
568 ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
569 event_throw(glk, evtype_LineInput, win, chars_written, 0);
573 /* Internal function: Callback for signal activate on the line input GtkEntry
574 in a text grid window. */
576 on_input_entry_activate(GtkEntry *input_entry, winid_t win)
578 g_signal_handler_block(win->widget, win->keypress_handler);
580 int chars_written = finish_text_grid_line_input(win, TRUE);
581 ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
582 event_throw(glk, evtype_LineInput, win, chars_written, 0);
586 keyval_to_glk_keycode(guint keyval, gboolean unicode)
591 case GDK_KP_Up: return keycode_Up;
593 case GDK_KP_Down: return keycode_Down;
595 case GDK_KP_Left: return keycode_Left;
597 case GDK_KP_Right: return keycode_Right;
600 case GDK_KP_Enter: return keycode_Return;
603 case GDK_KP_Delete: return keycode_Delete;
604 case GDK_Escape: return keycode_Escape;
606 case GDK_KP_Tab: return keycode_Tab;
608 case GDK_KP_Page_Up: return keycode_PageUp;
610 case GDK_KP_Page_Down: return keycode_PageDown;
612 case GDK_KP_Home: return keycode_Home;
614 case GDK_KP_End: return keycode_End;
616 case GDK_KP_F1: return keycode_Func1;
618 case GDK_KP_F2: return keycode_Func2;
620 case GDK_KP_F3: return keycode_Func3;
622 case GDK_KP_F4: return keycode_Func4;
623 case GDK_F5: return keycode_Func5;
624 case GDK_F6: return keycode_Func6;
625 case GDK_F7: return keycode_Func7;
626 case GDK_F8: return keycode_Func8;
627 case GDK_F9: return keycode_Func9;
628 case GDK_F10: return keycode_Func10;
629 case GDK_F11: return keycode_Func11;
630 case GDK_F12: return keycode_Func12;
632 keycode = gdk_keyval_to_unicode(keyval);
633 /* If keycode is 0, then keyval was not recognized; also return
634 unknown if Latin-1 input was requested and the character is not in
636 if(keycode == 0 || (!unicode && keycode > 255))
637 return keycode_Unknown;
643 force_char_input_from_queue(winid_t win, event_t *event)
645 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
646 guint keyval = GPOINTER_TO_UINT(g_async_queue_pop(glk_data->char_input_queue));
648 glk_cancel_char_event(win);
651 ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
653 g_signal_emit_by_name(glk, "char-input", win->rock, keyval);
656 event->type = evtype_CharInput;
658 event->val1 = keyval_to_glk_keycode(keyval, win->input_request_type == INPUT_REQUEST_CHARACTER_UNICODE);
663 force_line_input_from_queue(winid_t win, event_t *event)
665 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
666 const gchar *text = g_async_queue_pop(glk_data->line_input_queue);
667 glui32 chars_written = 0;
670 if(win->type == wintype_TextBuffer)
672 GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
673 GtkTextIter start, end;
675 /* Remove signal handlers so the line input doesn't get picked up again */
676 g_signal_handler_block(buffer, win->insert_text_handler);
678 /* Erase any text that was already typed */
679 GtkTextMark *input_position = gtk_text_buffer_get_mark(buffer, "input_position");
680 gtk_text_buffer_get_iter_at_mark(buffer, &start, input_position);
681 gtk_text_buffer_get_end_iter(buffer, &end);
682 gtk_text_buffer_delete(buffer, &start, &end);
684 /* Make the window uneditable again */
685 gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), FALSE);
687 /* Insert the forced input into the window */
688 gtk_text_buffer_get_end_iter(buffer, &end);
689 gchar *text_to_insert = g_strconcat(text, "\n", NULL);
690 gtk_text_buffer_insert_with_tags_by_name(buffer, &end, text_to_insert, -1, "input", NULL);
691 chars_written = finish_text_buffer_line_input(win, TRUE);
693 else if(win->type == wintype_TextGrid)
695 /* Remove signal handlers so the line input doesn't get picked up again */
696 g_signal_handler_block(win->widget, win->keypress_handler);
698 /* Insert the forced input into the window */
699 gtk_entry_set_text(GTK_ENTRY(win->input_entry), text);
700 chars_written = finish_text_grid_line_input(win, TRUE);
704 event->type = evtype_LineInput;
706 event->val1 = chars_written;