len = g_unichar_to_utf8 (ch, buf);
buf[len] = '\0';
- context_simple->in_hex_sequence = FALSE;
-
- if (context_simple->tentative_match)
- {
- context_simple->tentative_match = 0;
- context_simple->tentative_match_len = 0;
- g_signal_emit_by_name (context_simple, "preedit_changed");
- }
+ context_simple->in_hex_sequence = FALSE;
+ context_simple->tentative_match = 0;
+ context_simple->tentative_match_len = 0;
+ g_signal_emit_by_name (context_simple, "preedit_changed");
g_signal_emit_by_name (context, "commit", &buf);
}
{
context_simple->tentative_match = value;
context_simple->tentative_match_len = n_compose;
-
+
g_signal_emit_by_name (context_simple, "preedit_changed");
return TRUE;
}
/* In addition to the table-driven sequences, we allow Unicode hex
- * codes entered with Ctrl-Shift held down as specified in ISO
- * 14755. 14755 actually allows a different set of modifiers to be
- * used at our discretion, but for now using Ctrl-Shift as in their
- * examples. While holding Ctrl-Shift, pressing space commits the
- * character, and pressing a non-hex-digit is an error.
+ * codes to be entered. The method chosen here is similar to the
+ * one recommended in ISO 14755, but not exactly the same, since we
+ * don't want to steal 16 valuable key combinations.
+ *
+ * A hex Unicode sequence must be started with Ctrl-Shift-U, followed
+ * by a sequence of hex digits entered with Ctrl-Shift still held.
+ * Releasing one of the modifiers or pressing space while the modifiers
+ * are still held commits the character. It is possible to erase
+ * digits using backspace.
+ *
+ * As an extension to the above, we also allow to start the sequence
+ * with Ctrl-Shift-U, then release the modifiers before typing any
+ * digits, and enter the digits without modifiers.
*/
-
-#define ISO_14755_MOD_MASK (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
+#define HEX_MOD_MASK (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
static gboolean
check_hex (GtkIMContextSimple *context_simple,
gulong n;
gchar *nptr = NULL;
gchar buf[7];
-
+
+ context_simple->tentative_match = 0;
+ context_simple->tentative_match_len = 0;
+
str = g_string_new (NULL);
i = 0;
else
g_string_free (str, TRUE);
- /* don't allow invalid Unicode or nul bytes */
- if (n == 0 || !g_unichar_validate (n))
- return FALSE;
-
- context_simple->tentative_match = n;
- context_simple->tentative_match_len = n_compose;
-
- g_signal_emit_by_name (context_simple, "preedit_changed");
+ if (g_unichar_validate (n))
+ {
+ context_simple->tentative_match = n;
+ context_simple->tentative_match_len = n_compose;
+ }
return TRUE;
}
GSList *tmp_list;
int n_compose = 0;
gboolean have_hex_mods;
+ gboolean is_hex_start;
+ gboolean is_space;
+ gboolean is_backspace;
guint hex_keyval;
int i;
+ while (context_simple->compose_buffer[n_compose] != 0)
+ n_compose++;
+
if (event->type == GDK_KEY_RELEASE)
{
if (context_simple->in_hex_sequence &&
(event->keyval == GDK_Control_L || event->keyval == GDK_Control_R ||
event->keyval == GDK_Shift_L || event->keyval == GDK_Shift_R))
{
- if (context_simple->tentative_match)
+ if (context_simple->tentative_match &&
+ g_unichar_validate (context_simple->tentative_match))
{
gtk_im_context_simple_commit_char (context, context_simple->tentative_match);
context_simple->compose_buffer[0] = 0;
+
+ }
+ else if (n_compose == 0)
+ {
+ context_simple->modifiers_dropped = TRUE;
}
else
- context_simple->in_hex_sequence = 0;
+ {
+ /* invalid hex sequence */
+ gdk_display_beep (gdk_drawable_get_display (event->window));
+
+ context_simple->tentative_match = 0;
+ context_simple->in_hex_sequence = FALSE;
+ context_simple->compose_buffer[0] = 0;
+
+ g_signal_emit_by_name (context_simple, "preedit_changed");
+ }
return TRUE;
}
return FALSE;
}
- /* Ignore modifier key presses
- */
+ /* Ignore modifier key presses */
for (i=0; i < G_N_ELEMENTS (gtk_compose_ignore); i++)
if (event->keyval == gtk_compose_ignore[i])
return FALSE;
- have_hex_mods = (event->state & (ISO_14755_MOD_MASK)) == ISO_14755_MOD_MASK;
+ if (context_simple->in_hex_sequence && context_simple->modifiers_dropped)
+ have_hex_mods = TRUE;
+ else
+ have_hex_mods = (event->state & (HEX_MOD_MASK)) == HEX_MOD_MASK;
+ is_hex_start = event->keyval == GDK_U;
+ is_space = event->keyval == GDK_space || event->keyval == GDK_KP_Space;
+ is_backspace = event->keyval == GDK_BackSpace;
hex_keyval = canonical_hex_keyval (event);
- while (context_simple->compose_buffer[n_compose] != 0)
- n_compose++;
-
/* If we are already in a non-hex sequence, or
- * this keystroke is not 14755 modifiers + hex digit, don't filter
+ * this keystroke is not hex modifiers + hex digit, don't filter
* key events with accelerator modifiers held down.
*/
- if ((n_compose > 0 && !context_simple->in_hex_sequence) || !have_hex_mods || !hex_keyval)
+ if (!have_hex_mods ||
+ (n_compose > 0 && !context_simple->in_hex_sequence) ||
+ (n_compose == 0 && !context_simple->in_hex_sequence && !is_hex_start) ||
+ (context_simple->in_hex_sequence && !hex_keyval && !is_space && !is_backspace))
{
- if (event->state &
- (gtk_accelerator_get_default_mod_mask () & ~GDK_SHIFT_MASK))
- return FALSE;
+ if (event->state & (gtk_accelerator_get_default_mod_mask () & ~GDK_SHIFT_MASK))
+ return FALSE;
+ }
+
+ /* Handle backspace */
+ if (context_simple->in_hex_sequence && have_hex_mods && is_backspace)
+ {
+ if (n_compose > 0)
+ {
+ n_compose--;
+ context_simple->compose_buffer[n_compose] = 0;
+ check_hex (context_simple, n_compose);
+ }
+ else
+ {
+ context_simple->in_hex_sequence = FALSE;
+ }
+
+ g_signal_emit_by_name (context_simple, "preedit_changed");
+
+ return TRUE;
}
+
+ /* Check for hex sequence start */
+ if (n_compose == 0 && !context_simple->in_hex_sequence && have_hex_mods && is_hex_start)
+ {
+ context_simple->compose_buffer[0] = 0;
+ context_simple->in_hex_sequence = TRUE;
+ context_simple->modifiers_dropped = FALSE;
+ context_simple->tentative_match = 0;
+
+ g_signal_emit_by_name (context_simple, "preedit_changed");
- /* First key in sequence; decide if it's a 14755 hex sequence */
- if (n_compose == 0)
- context_simple->in_hex_sequence = have_hex_mods;
+ return TRUE;
+ }
- /* Then, check for compose sequences
- */
+ /* Then, check for compose sequences */
if (context_simple->in_hex_sequence)
- context_simple->compose_buffer[n_compose++] = hex_keyval ? hex_keyval : event->keyval;
+ {
+ if (hex_keyval)
+ context_simple->compose_buffer[n_compose++] = hex_keyval;
+ else if (!is_space)
+ {
+ /* non-hex character in hex sequence */
+ gdk_display_beep (gdk_drawable_get_display (event->window));
+
+ return TRUE;
+ }
+ }
else
context_simple->compose_buffer[n_compose++] = event->keyval;
if (have_hex_mods)
{
/* space ends the sequence, and we eat the space */
- if (n_compose > 1 &&
- (event->keyval == GDK_space ||
- event->keyval == GDK_KP_Space))
+ if (n_compose > 0 && is_space)
{
- gtk_im_context_simple_commit_char (context, context_simple->tentative_match);
- context_simple->compose_buffer[0] = 0;
- return TRUE;
+ if (context_simple->tentative_match &&
+ g_unichar_validate (context_simple->tentative_match))
+ {
+ gtk_im_context_simple_commit_char (context, context_simple->tentative_match);
+ context_simple->compose_buffer[0] = 0;
+ }
+ else
+ {
+ /* invalid hex sequence */
+ gdk_display_beep (gdk_drawable_get_display (event->window));
+
+ context_simple->tentative_match = 0;
+ context_simple->in_hex_sequence = FALSE;
+ context_simple->compose_buffer[0] = 0;
+ }
}
- else if (check_hex (context_simple, n_compose))
- return TRUE;
+ else if (!check_hex (context_simple, n_compose))
+ gdk_display_beep (gdk_drawable_get_display (event->window));
+
+ g_signal_emit_by_name (context_simple, "preedit_changed");
+
+ return TRUE;
}
}
else
gtk_im_context_simple_reset (GtkIMContext *context)
{
GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
-
+
context_simple->compose_buffer[0] = 0;
if (context_simple->tentative_match)
gtk_im_context_simple_commit_char (context, context_simple->tentative_match);
-
+
context_simple->in_hex_sequence = FALSE;
+
+ g_signal_emit_by_name (context_simple, "preedit_changed");
}
static void
GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
- if (context_simple->tentative_match)
+ if (context_simple->in_hex_sequence)
{
- if (context_simple->in_hex_sequence)
- {
- int hexchars = 0;
-
- while (context_simple->compose_buffer[hexchars] != 0)
- {
- len += g_unichar_to_utf8 (gdk_keyval_to_unicode (context_simple->compose_buffer[hexchars]),
- outbuf + len);
- ++hexchars;
- }
- }
- else
- {
- len = g_unichar_to_utf8 (context_simple->tentative_match, outbuf);
- }
-
+ int hexchars = 0;
+
+ outbuf[0] = 'u';
+ len = 1;
+
+ while (context_simple->compose_buffer[hexchars] != 0)
+ {
+ len += g_unichar_to_utf8 (gdk_keyval_to_unicode (context_simple->compose_buffer[hexchars]),
+ outbuf + len);
+ ++hexchars;
+ }
+
g_assert (len < 25);
outbuf[len] = '\0';
}
+ else if (context_simple->tentative_match)
+ {
+ len = g_unichar_to_utf8 (context_simple->tentative_match, outbuf);
+ }
else
{
outbuf[0] = '\0';
}
-
+
if (str)
*str = g_strdup (outbuf);
}
if (cursor_pos)
- *cursor_pos = (context_simple->tentative_match ? len : 0);
+ *cursor_pos = len;
}
/**