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 win->input_request_type = unicode? INPUT_REQUEST_CHARACTER_UNICODE : INPUT_REQUEST_CHARACTER;
21 g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler );
25 /* If the request is in a text buffer window, scroll to the end of the
26 text buffer. TODO: This may scroll text off the top of the window that the
27 user hasn't read yet. We need to implement a paging mechanism. */
28 if(win->type == wintype_TextBuffer)
30 GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
32 gtk_text_buffer_get_end_iter(buffer, &iter);
33 gtk_text_buffer_place_cursor(buffer, &iter);
34 gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(win->widget), gtk_text_buffer_get_insert(buffer));
35 /* Why doesn't this always work?? */
38 gtk_widget_grab_focus( GTK_WIDGET(win->widget) );
43 * glk_request_char_event:
44 * @win: A window to request char events from.
46 * Request input of a Latin-1 character or special key. A window cannot have
47 * requests for both character and line input at the same time. Nor can it have
48 * requests for character input of both types (Latin-1 and Unicode). It is
49 * illegal to call glk_request_char_event() if the window already has a pending
50 * request for either character or line input.
53 glk_request_char_event(winid_t win)
55 request_char_event_common(win, FALSE);
59 * glk_request_char_event_uni:
60 * @win: A window to request char events from.
62 * Request input of a Unicode character or special key. See
63 * glk_request_char_event().
66 glk_request_char_event_uni(winid_t win)
68 request_char_event_common(win, TRUE);
72 * glk_cancel_char_event:
73 * @win: A window to cancel the latest char event request on.
75 * This cancels a pending request for character input. (Either Latin-1 or
76 * Unicode.) For convenience, it is legal to call glk_cancel_char_event() even
77 * if there is no charcter input request on that window. Glk will ignore the
81 glk_cancel_char_event(winid_t win)
83 VALID_WINDOW(win, return);
84 g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
86 if(win->input_request_type == INPUT_REQUEST_CHARACTER || win->input_request_type == INPUT_REQUEST_CHARACTER_UNICODE)
88 win->input_request_type = INPUT_REQUEST_NONE;
89 g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
93 /* Internal function: Request either latin-1 or unicode line input, in a text grid window. */
95 text_grid_request_line_event_common(winid_t win, glui32 maxlen, gboolean insert, gchar *inserttext)
99 GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
101 GtkTextMark *cursor = gtk_text_buffer_get_mark(buffer, "cursor_position");
102 GtkTextIter start_iter, end_iter;
103 gtk_text_buffer_get_iter_at_mark(buffer, &start_iter, cursor);
105 /* Determine the maximum length of the line input */
106 gint cursorpos = gtk_text_iter_get_line_offset(&start_iter);
107 /* Odd; the Glk spec says the maximum input length is
108 windowwidth - 1 - cursorposition. I say no, because if cursorposition is
109 zero, then the input should fill the whole line. FIXME??? */
110 win->input_length = MIN(win->width - cursorpos, win->line_input_buffer_max_len);
111 end_iter = start_iter;
112 gtk_text_iter_set_line_offset(&end_iter, cursorpos + win->input_length);
114 /* If the buffer currently has a selection with one bound in the middle of
115 the input field, then deselect it. Otherwise the input field gets trashed */
116 GtkTextIter start_sel, end_sel;
117 if( gtk_text_buffer_get_selection_bounds(buffer, &start_sel, &end_sel) )
119 if( gtk_text_iter_in_range(&start_sel, &start_iter, &end_iter) )
120 gtk_text_buffer_place_cursor(buffer, &end_sel);
121 if( gtk_text_iter_in_range(&end_sel, &start_iter, &end_iter) )
122 gtk_text_buffer_place_cursor(buffer, &start_sel);
125 /* Erase the text currently in the input field and replace it with a GtkEntry */
126 gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
127 win->input_anchor = gtk_text_buffer_create_child_anchor(buffer, &start_iter);
128 win->input_entry = gtk_entry_new();
129 /* Set the entry's font to match that of the window */
130 GtkRcStyle *style = gtk_widget_get_modifier_style(win->widget); /* Don't free */
131 gtk_widget_modify_font(win->input_entry, style->font_desc);
132 /* Make the entry as small as possible to fit with the text */
133 gtk_entry_set_has_frame(GTK_ENTRY(win->input_entry), FALSE);
134 GtkBorder border = { 0, 0, 0, 0 };
135 gtk_entry_set_inner_border(GTK_ENTRY(win->input_entry), &border);
136 gtk_entry_set_max_length(GTK_ENTRY(win->input_entry), win->input_length);
137 gtk_entry_set_width_chars(GTK_ENTRY(win->input_entry), win->input_length);
139 /* Insert pre-entered text if needed */
141 gtk_entry_set_text(GTK_ENTRY(win->input_entry), inserttext);
143 /* Set background color of entry (TODO: implement as property) */
145 gdk_color_parse("grey", &background);
146 gtk_widget_modify_base(win->input_entry, GTK_STATE_NORMAL, &background);
148 g_signal_connect(win->input_entry, "activate", G_CALLBACK(on_input_entry_activate), win);
150 gtk_widget_show(win->input_entry);
151 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(win->widget), win->input_entry, win->input_anchor);
153 g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler );
155 gtk_widget_grab_focus(win->input_entry);
160 /* Internal function: Request either latin-1 or unicode line input, in a text buffer window. */
162 text_buffer_request_line_event_common(winid_t win, glui32 maxlen, gboolean insert, gchar *inserttext)
166 GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
168 /* Move the input_position mark to the end of the window_buffer */
169 GtkTextMark *input_position = gtk_text_buffer_get_mark(buffer, "input_position");
170 GtkTextIter end_iter;
171 gtk_text_buffer_get_end_iter(buffer, &end_iter);
172 gtk_text_buffer_move_mark(buffer, input_position, &end_iter);
174 /* Set the entire contents of the window_buffer as uneditable
175 * (so input can only be entered at the end) */
176 GtkTextIter start_iter;
177 gtk_text_buffer_get_start_iter(buffer, &start_iter);
178 gtk_text_buffer_remove_tag_by_name(buffer, "uneditable", &start_iter, &end_iter);
179 gtk_text_buffer_apply_tag_by_name(buffer, "uneditable", &start_iter, &end_iter);
181 /* Insert pre-entered text if needed */
183 gtk_text_buffer_insert(buffer, &end_iter, inserttext, -1);
185 /* Scroll to input point */
186 gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(win->widget), input_position);
188 gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), TRUE);
189 g_signal_handler_unblock(buffer, win->insert_text_handler);
191 gtk_widget_grab_focus(win->widget);
197 * glk_request_line_event:
198 * @win: A text buffer or text grid window to request line input on.
199 * @buf: A buffer of at least @maxlen bytes.
200 * @maxlen: Length of the buffer.
201 * @initlen: The number of characters in @buf to pre-enter.
203 * Requests input of a line of Latin-1 characters. A window cannot have requests
204 * for both character and line input at the same time. Nor can it have requests
205 * for line input of both types (Latin-1 and Unicode). It is illegal to call
206 * glk_request_line_event() if the window already has a pending request for
207 * either character or line input.
209 * The @buf argument is a pointer to space where the line input will be stored.
210 * (This may not be %NULL.) @maxlen is the length of this space, in bytes; the
211 * library will not accept more characters than this. If @initlen is nonzero,
212 * then the first @initlen bytes of @buf will be entered as pre-existing input
213 * — just as if the player had typed them himself. (The player can continue
214 * composing after this pre-entered input, or delete it or edit as usual.)
216 * The contents of the buffer are undefined until the input is completed (either
217 * by a line input event, or glk_cancel_line_event(). The library may or may not
218 * fill in the buffer as the player composes, while the input is still pending;
219 * it is illegal to change the contents of the buffer yourself.
222 glk_request_line_event(winid_t win, char *buf, glui32 maxlen, glui32 initlen)
224 VALID_WINDOW(win, return);
225 g_return_if_fail(buf);
226 g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
227 g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
228 g_return_if_fail(initlen <= maxlen);
230 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
232 /* Register the buffer */
233 if(glk_data->register_arr)
234 win->buffer_rock = (*glk_data->register_arr)(buf, maxlen, "&+#!Cn");
236 win->input_request_type = INPUT_REQUEST_LINE;
237 win->line_input_buffer = buf;
238 win->line_input_buffer_max_len = maxlen;
240 gchar *inserttext = (initlen > 0)? g_strndup(buf, initlen) : g_strdup("");
243 case wintype_TextBuffer:
244 text_buffer_request_line_event_common(win, maxlen, (initlen > 0), inserttext);
246 case wintype_TextGrid:
247 text_grid_request_line_event_common(win, maxlen, (initlen > 0), inserttext);
254 * glk_request_line_event_uni:
255 * @win: A text buffer or text grid window to request line input on.
256 * @buf: A buffer of at least @maxlen characters.
257 * @maxlen: Length of the buffer.
258 * @initlen: The number of characters in @buf to pre-enter.
260 * Request input of a line of Unicode characters. This works the same as
261 * glk_request_line_event(), except the result is stored in an array of
262 * <type>glui32</type> values instead of an array of characters, and the values
263 * may be any valid Unicode code points.
265 * The result will be in Unicode Normalization Form C. This basically means that
266 * composite characters will be single characters where possible, instead of
267 * sequences of base and combining marks. See
268 * <ulink url="http://www.unicode.org/reports/tr15/">Unicode Standard Annex
269 * #15</ulink> for the details.
272 glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initlen)
274 VALID_WINDOW(win, return);
275 g_return_if_fail(buf);
276 g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
277 g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
278 g_return_if_fail(initlen <= maxlen);
280 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
282 /* Register the buffer */
283 if(glk_data->register_arr)
284 win->buffer_rock = (*glk_data->register_arr)(buf, maxlen, "&+#!Iu");
286 win->input_request_type = INPUT_REQUEST_LINE_UNICODE;
287 win->line_input_buffer_unicode = buf;
288 win->line_input_buffer_max_len = maxlen;
292 utf8 = convert_ucs4_to_utf8(buf, initlen);
301 case wintype_TextBuffer:
302 text_buffer_request_line_event_common(win, maxlen, (initlen > 0), utf8);
304 case wintype_TextGrid:
305 text_grid_request_line_event_common(win, maxlen, (initlen > 0), utf8);
312 * glk_cancel_line_event:
313 * @win: A text buffer or text grid window to cancel line input on.
314 * @event: Will be filled in if the user had already input something.
316 * This cancels a pending request for line input. (Either Latin-1 or Unicode.)
318 * The event pointed to by the event argument will be filled in as if the
319 * player had hit <keycap>enter</keycap>, and the input composed so far will be
320 * stored in the buffer; see below. If you do not care about this information,
321 * pass %NULL as the @event argument. (The buffer will still be filled.)
323 * For convenience, it is legal to call glk_cancel_line_event() even if there
324 * is no line input request on that window. The event type will be set to
325 * %evtype_None in this case.
328 glk_cancel_line_event(winid_t win, event_t *event)
330 VALID_WINDOW(win, return);
331 g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
334 event->type = evtype_None;
340 if(win->input_request_type != INPUT_REQUEST_LINE && win->input_request_type != INPUT_REQUEST_LINE_UNICODE)
343 g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
345 int chars_written = 0;
347 if(win->type == wintype_TextGrid) {
348 g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
349 chars_written = finish_text_grid_line_input(win, FALSE);
350 } else if(win->type == wintype_TextBuffer) {
351 GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
352 g_signal_handler_block(window_buffer, win->insert_text_handler);
353 chars_written = finish_text_buffer_line_input(win, FALSE);
356 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
357 if(glk_data->unregister_arr)
359 if(win->input_request_type == INPUT_REQUEST_LINE_UNICODE)
360 (*glk_data->unregister_arr)(win->line_input_buffer_unicode, win->line_input_buffer_max_len, "&+#!Iu", win->buffer_rock);
362 (*glk_data->unregister_arr)(win->line_input_buffer, win->line_input_buffer_max_len, "&+#!Cn", win->buffer_rock);
365 if(event != NULL && chars_written > 0) {
366 event->type = evtype_LineInput;
367 event->val1 = chars_written;
371 /* 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. */
373 on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win)
375 /* If this is a text grid window, and line input is active, then redirect the key press to the line input GtkEntry */
376 if( win->type == wintype_TextGrid && (win->input_request_type == INPUT_REQUEST_LINE || win->input_request_type == INPUT_REQUEST_LINE_UNICODE) )
378 if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up
379 || event->keyval == GDK_Down || event->keyval == GDK_KP_Down
380 || event->keyval == GDK_Left || event->keyval == GDK_KP_Left
381 || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
382 || event->keyval == GDK_Tab || event->keyval == GDK_KP_Tab
383 || event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up
384 || event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down
385 || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
386 || event->keyval == GDK_End || event->keyval == GDK_KP_End)
387 return FALSE; /* Don't redirect these keys */
388 gtk_widget_grab_focus(win->input_entry);
389 gtk_editable_set_position(GTK_EDITABLE(win->input_entry), -1);
390 gboolean retval = TRUE;
391 g_signal_emit_by_name(win->input_entry, "key-press-event", event, &retval);
392 return retval; /* Block this key event if the entry handled it */
394 if(win->input_request_type != INPUT_REQUEST_CHARACTER &&
395 win->input_request_type != INPUT_REQUEST_CHARACTER_UNICODE)
398 glui32 keycode = keyval_to_glk_keycode(event->keyval, win->input_request_type == INPUT_REQUEST_CHARACTER_UNICODE);
400 ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(widget, CHIMARA_TYPE_GLK));
402 event_throw(glk, evtype_CharInput, win, keycode, 0);
403 g_signal_emit_by_name(glk, "char-input", win->rock, event->keyval);
405 /* Only one keypress will be handled */
406 win->input_request_type = INPUT_REQUEST_NONE;
407 g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
412 /* Internal function: finish handling a line input request, for both text grid and text buffer windows. */
414 write_to_window_buffer(winid_t win, const gchar *inserted_text)
418 /* Convert the string from UTF-8 to Latin-1 or Unicode */
419 if(win->input_request_type == INPUT_REQUEST_LINE)
422 gchar *latin1 = convert_utf8_to_latin1(inserted_text, &bytes_written);
427 /* Place input in the echo stream */
428 if(win->echo_stream != NULL)
429 glk_put_string_stream(win->echo_stream, latin1);
431 /* Copy the string (bytes_written does not include the NULL at the end) */
432 copycount = MIN(win->line_input_buffer_max_len, bytes_written);
433 memcpy(win->line_input_buffer, latin1, copycount);
436 else if(win->input_request_type == INPUT_REQUEST_LINE_UNICODE)
439 gunichar *unicode = convert_utf8_to_ucs4(inserted_text, &items_written);
444 /* Place input in the echo stream */
445 if(win->echo_stream != NULL)
446 glk_put_string_stream_uni(win->echo_stream, unicode);
448 /* Copy the string (but not the NULL at the end) */
449 copycount = MIN(win->line_input_buffer_max_len, items_written);
450 memcpy(win->line_input_buffer_unicode, unicode, copycount * sizeof(gunichar));
454 WARNING("Wrong input request type");
456 win->input_request_type = INPUT_REQUEST_NONE;
460 /* Internal function: Retrieves the input of a TextBuffer window and stores it in the window buffer.
461 * Returns the number of characters written, suitable for inclusion in a line input event. */
463 finish_text_buffer_line_input(winid_t win, gboolean emit_signal)
465 VALID_WINDOW(win, return 0);
466 g_return_val_if_fail(win->type == wintype_TextBuffer, 0);
468 GtkTextIter start_iter, end_iter, last_character;
470 GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
471 GtkTextMark *input_position = gtk_text_buffer_get_mark(window_buffer, "input_position");
472 gtk_text_buffer_get_iter_at_mark(window_buffer, &start_iter, input_position);
473 gtk_text_buffer_get_end_iter(window_buffer, &end_iter);
474 gtk_text_buffer_get_end_iter(window_buffer, &last_character);
475 gtk_text_iter_backward_cursor_position(&last_character);
477 gchar* last_char = gtk_text_buffer_get_text(window_buffer, &last_character, &end_iter, FALSE);
479 if( strchr(last_char, '\n') != NULL )
480 gtk_text_iter_backward_cursor_position(&end_iter);
482 gchar* inserted_text = gtk_text_buffer_get_text(window_buffer, &start_iter, &end_iter, FALSE);
484 int chars_written = write_to_window_buffer(win, inserted_text);
487 ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
489 g_signal_emit_by_name(glk, "line-input", win->rock, inserted_text);
491 g_free(inserted_text);
493 return chars_written;
496 /* Internal function: Retrieves the input of a TextGrid window and stores it in the window buffer.
497 * Returns the number of characters written, suitable for inclusion in a line input event. */
499 finish_text_grid_line_input(winid_t win, gboolean emit_signal)
501 VALID_WINDOW(win, return 0);
502 g_return_val_if_fail(win->type == wintype_TextGrid, 0);
504 GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
506 gchar *text = g_strdup( gtk_entry_get_text(GTK_ENTRY(win->input_entry)) );
507 /* Move the focus back into the text view */
508 gtk_widget_grab_focus(win->widget);
509 /* Remove entry widget from text view */
510 /* Should be ok even though this is the widget's own signal handler */
511 gtk_container_remove( GTK_CONTAINER(win->widget), GTK_WIDGET(win->input_entry) );
512 win->input_entry = NULL;
513 /* Delete the child anchor */
514 GtkTextIter start, end;
515 gtk_text_buffer_get_iter_at_child_anchor(buffer, &start, win->input_anchor);
517 gtk_text_iter_forward_char(&end); /* Point after the child anchor */
518 gtk_text_buffer_delete(buffer, &start, &end);
519 win->input_anchor = NULL;
521 gchar *spaces = g_strnfill(win->input_length - g_utf8_strlen(text, -1), ' ');
522 gchar *text_to_insert = g_strconcat(text, spaces, NULL);
524 gtk_text_buffer_insert(buffer, &start, text_to_insert, -1);
525 g_free(text_to_insert);
527 int chars_written = write_to_window_buffer(win, text);
530 ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
532 g_signal_emit_by_name(glk, "line-input", win->rock, text);
536 return chars_written;
539 /* Internal function: Callback for signal insert-text on a text buffer window.
540 Runs after the default handler has already inserted the text.
541 FIXME: This function assumes that newline was the last character typed into the
542 window. That assumption is wrong if, for example, text containing a newline was
543 pasted into the window. */
545 after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, winid_t win)
547 if( strchr(text, '\n') != NULL )
549 /* Remove signal handlers */
550 GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
551 g_signal_handler_block(window_buffer, win->insert_text_handler);
553 /* Make the window uneditable again and retrieve the text that was input */
554 gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), FALSE);
556 int chars_written = finish_text_buffer_line_input(win, TRUE);
557 ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
558 event_throw(glk, evtype_LineInput, win, chars_written, 0);
562 /* Internal function: Callback for signal activate on the line input GtkEntry
563 in a text grid window. */
565 on_input_entry_activate(GtkEntry *input_entry, winid_t win)
567 g_signal_handler_block(win->widget, win->keypress_handler);
569 int chars_written = finish_text_grid_line_input(win, TRUE);
570 ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
571 event_throw(glk, evtype_LineInput, win, chars_written, 0);
575 keyval_to_glk_keycode(guint keyval, gboolean unicode)
580 case GDK_KP_Up: return keycode_Up;
582 case GDK_KP_Down: return keycode_Down;
584 case GDK_KP_Left: return keycode_Left;
586 case GDK_KP_Right: return keycode_Right;
589 case GDK_KP_Enter: return keycode_Return;
592 case GDK_KP_Delete: return keycode_Delete;
593 case GDK_Escape: return keycode_Escape;
595 case GDK_KP_Tab: return keycode_Tab;
597 case GDK_KP_Page_Up: return keycode_PageUp;
599 case GDK_KP_Page_Down: return keycode_PageDown;
601 case GDK_KP_Home: return keycode_Home;
603 case GDK_KP_End: return keycode_End;
605 case GDK_KP_F1: return keycode_Func1;
607 case GDK_KP_F2: return keycode_Func2;
609 case GDK_KP_F3: return keycode_Func3;
611 case GDK_KP_F4: return keycode_Func4;
612 case GDK_F5: return keycode_Func5;
613 case GDK_F6: return keycode_Func6;
614 case GDK_F7: return keycode_Func7;
615 case GDK_F8: return keycode_Func8;
616 case GDK_F9: return keycode_Func9;
617 case GDK_F10: return keycode_Func10;
618 case GDK_F11: return keycode_Func11;
619 case GDK_F12: return keycode_Func12;
621 keycode = gdk_keyval_to_unicode(keyval);
622 /* If keycode is 0, then keyval was not recognized; also return
623 unknown if Latin-1 input was requested and the character is not in
625 if(keycode == 0 || (!unicode && keycode > 255))
626 return keycode_Unknown;
632 force_char_input_from_queue(winid_t win, event_t *event)
634 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
635 guint keyval = GPOINTER_TO_UINT(g_async_queue_pop(glk_data->char_input_queue));
637 glk_cancel_char_event(win);
640 ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
642 g_signal_emit_by_name(glk, "char-input", win->rock, keyval);
645 event->type = evtype_CharInput;
647 event->val1 = keyval_to_glk_keycode(keyval, win->input_request_type == INPUT_REQUEST_CHARACTER_UNICODE);
652 force_line_input_from_queue(winid_t win, event_t *event)
654 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
655 const gchar *text = g_async_queue_pop(glk_data->line_input_queue);
656 glui32 chars_written = 0;
659 if(win->type == wintype_TextBuffer)
661 GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
662 GtkTextIter start, end;
664 /* Remove signal handlers so the line input doesn't get picked up again */
665 g_signal_handler_block(buffer, win->insert_text_handler);
667 /* Erase any text that was already typed */
668 GtkTextMark *input_position = gtk_text_buffer_get_mark(buffer, "input_position");
669 gtk_text_buffer_get_iter_at_mark(buffer, &start, input_position);
670 gtk_text_buffer_get_end_iter(buffer, &end);
671 gtk_text_buffer_delete(buffer, &start, &end);
673 /* Make the window uneditable again */
674 gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), FALSE);
676 /* Insert the forced input into the window */
677 gtk_text_buffer_get_end_iter(buffer, &end);
678 gchar *text_to_insert = g_strconcat(text, "\n", NULL);
679 gtk_text_buffer_insert_with_tags_by_name(buffer, &end, text_to_insert, -1, "input", NULL);
680 chars_written = finish_text_buffer_line_input(win, TRUE);
682 else if(win->type == wintype_TextGrid)
684 /* Remove signal handlers so the line input doesn't get picked up again */
685 g_signal_handler_block(win->widget, win->keypress_handler);
687 /* Insert the forced input into the window */
688 gtk_entry_set_text(GTK_ENTRY(win->input_entry), text);
689 chars_written = finish_text_grid_line_input(win, TRUE);
693 event->type = evtype_LineInput;
695 event->val1 = chars_written;