Rework the Unicode hex input code. Now we only steal a single key

2005-09-02  Matthias Clasen  <mclasen@redhat.com>

	* gtk/gtkimcontextsimple.c: Rework the Unicode hex input
	code. Now we only steal a single key combination, Ctrl-Shift-U,
	instead of sixteen.
	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.
	(#82011, Owen Taylor)
This commit is contained in:
Matthias Clasen
2005-09-02 18:14:59 +00:00
committed by Matthias Clasen
parent 92b1967c12
commit 4083637a11
3 changed files with 184 additions and 73 deletions

View File

@ -1,3 +1,18 @@
2005-09-02 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkimcontextsimple.c: Rework the Unicode hex input
code. Now we only steal a single key combination, Ctrl-Shift-U,
instead of sixteen.
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.
(#82011, Owen Taylor)
2005-09-02 Matthias Clasen <mclasen@redhat.com> 2005-09-02 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkmain.c (gtk_get_event_widget): If the window is destroyed, * gtk/gtkmain.c (gtk_get_event_widget): If the window is destroyed,

View File

@ -1,3 +1,18 @@
2005-09-02 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkimcontextsimple.c: Rework the Unicode hex input
code. Now we only steal a single key combination, Ctrl-Shift-U,
instead of sixteen.
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.
(#82011, Owen Taylor)
2005-09-02 Matthias Clasen <mclasen@redhat.com> 2005-09-02 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkmain.c (gtk_get_event_widget): If the window is destroyed, * gtk/gtkmain.c (gtk_get_event_widget): If the window is destroyed,

View File

@ -1033,13 +1033,9 @@ gtk_im_context_simple_commit_char (GtkIMContext *context,
buf[len] = '\0'; buf[len] = '\0';
context_simple->in_hex_sequence = FALSE; context_simple->in_hex_sequence = FALSE;
context_simple->tentative_match = 0;
if (context_simple->tentative_match) context_simple->tentative_match_len = 0;
{ g_signal_emit_by_name (context_simple, "preedit_changed");
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); g_signal_emit_by_name (context, "commit", &buf);
} }
@ -1134,14 +1130,21 @@ check_table (GtkIMContextSimple *context_simple,
} }
/* In addition to the table-driven sequences, we allow Unicode hex /* In addition to the table-driven sequences, we allow Unicode hex
* codes entered with Ctrl-Shift held down as specified in ISO * codes to be entered. The method chosen here is similar to the
* 14755. 14755 actually allows a different set of modifiers to be * one recommended in ISO 14755, but not exactly the same, since we
* used at our discretion, but for now using Ctrl-Shift as in their * don't want to steal 16 valuable key combinations.
* examples. While holding Ctrl-Shift, pressing space commits the *
* character, and pressing a non-hex-digit is an error. * 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 HEX_MOD_MASK (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
#define ISO_14755_MOD_MASK (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
static gboolean static gboolean
check_hex (GtkIMContextSimple *context_simple, check_hex (GtkIMContextSimple *context_simple,
@ -1154,6 +1157,9 @@ check_hex (GtkIMContextSimple *context_simple,
gchar *nptr = NULL; gchar *nptr = NULL;
gchar buf[7]; gchar buf[7];
context_simple->tentative_match = 0;
context_simple->tentative_match_len = 0;
str = g_string_new (NULL); str = g_string_new (NULL);
i = 0; i = 0;
@ -1189,14 +1195,11 @@ check_hex (GtkIMContextSimple *context_simple,
else else
g_string_free (str, TRUE); g_string_free (str, TRUE);
/* don't allow invalid Unicode or nul bytes */ if (g_unichar_validate (n))
if (n == 0 || !g_unichar_validate (n)) {
return FALSE; context_simple->tentative_match = n;
context_simple->tentative_match_len = n_compose;
context_simple->tentative_match = n; }
context_simple->tentative_match_len = n_compose;
g_signal_emit_by_name (context_simple, "preedit_changed");
return TRUE; return TRUE;
} }
@ -1313,22 +1316,43 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
GSList *tmp_list; GSList *tmp_list;
int n_compose = 0; int n_compose = 0;
gboolean have_hex_mods; gboolean have_hex_mods;
gboolean is_hex_start;
gboolean is_space;
gboolean is_backspace;
guint hex_keyval; guint hex_keyval;
int i; int i;
while (context_simple->compose_buffer[n_compose] != 0)
n_compose++;
if (event->type == GDK_KEY_RELEASE) if (event->type == GDK_KEY_RELEASE)
{ {
if (context_simple->in_hex_sequence && if (context_simple->in_hex_sequence &&
(event->keyval == GDK_Control_L || event->keyval == GDK_Control_R || (event->keyval == GDK_Control_L || event->keyval == GDK_Control_R ||
event->keyval == GDK_Shift_L || event->keyval == GDK_Shift_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); gtk_im_context_simple_commit_char (context, context_simple->tentative_match);
context_simple->compose_buffer[0] = 0; context_simple->compose_buffer[0] = 0;
}
else if (n_compose == 0)
{
context_simple->modifiers_dropped = TRUE;
} }
else 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 TRUE;
} }
@ -1336,37 +1360,78 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
return FALSE; return FALSE;
} }
/* Ignore modifier key presses /* Ignore modifier key presses */
*/
for (i=0; i < G_N_ELEMENTS (gtk_compose_ignore); i++) for (i=0; i < G_N_ELEMENTS (gtk_compose_ignore); i++)
if (event->keyval == gtk_compose_ignore[i]) if (event->keyval == gtk_compose_ignore[i])
return FALSE; 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); 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 /* 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. * 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 & if (event->state & (gtk_accelerator_get_default_mod_mask () & ~GDK_SHIFT_MASK))
(gtk_accelerator_get_default_mod_mask () & ~GDK_SHIFT_MASK)) return FALSE;
return FALSE;
} }
/* First key in sequence; decide if it's a 14755 hex sequence */ /* Handle backspace */
if (n_compose == 0) if (context_simple->in_hex_sequence && have_hex_mods && is_backspace)
context_simple->in_hex_sequence = have_hex_mods; {
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;
}
/* Then, check for compose sequences 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");
return TRUE;
}
/* Then, check for compose sequences */
if (context_simple->in_hex_sequence) 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 else
context_simple->compose_buffer[n_compose++] = event->keyval; context_simple->compose_buffer[n_compose++] = event->keyval;
@ -1378,16 +1443,30 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
if (have_hex_mods) if (have_hex_mods)
{ {
/* space ends the sequence, and we eat the space */ /* space ends the sequence, and we eat the space */
if (n_compose > 1 && if (n_compose > 0 && is_space)
(event->keyval == GDK_space ||
event->keyval == GDK_KP_Space))
{ {
gtk_im_context_simple_commit_char (context, context_simple->tentative_match); if (context_simple->tentative_match &&
context_simple->compose_buffer[0] = 0; g_unichar_validate (context_simple->tentative_match))
return TRUE; {
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)) else if (!check_hex (context_simple, n_compose))
return TRUE; gdk_display_beep (gdk_drawable_get_display (event->window));
g_signal_emit_by_name (context_simple, "preedit_changed");
return TRUE;
} }
} }
else else
@ -1419,6 +1498,8 @@ gtk_im_context_simple_reset (GtkIMContext *context)
gtk_im_context_simple_commit_char (context, context_simple->tentative_match); gtk_im_context_simple_commit_char (context, context_simple->tentative_match);
context_simple->in_hex_sequence = FALSE; context_simple->in_hex_sequence = FALSE;
g_signal_emit_by_name (context_simple, "preedit_changed");
} }
static void static void
@ -1432,27 +1513,27 @@ gtk_im_context_simple_get_preedit_string (GtkIMContext *context,
GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context); 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;
{
int hexchars = 0;
while (context_simple->compose_buffer[hexchars] != 0) outbuf[0] = 'u';
{ len = 1;
len += g_unichar_to_utf8 (gdk_keyval_to_unicode (context_simple->compose_buffer[hexchars]),
outbuf + len); while (context_simple->compose_buffer[hexchars] != 0)
++hexchars; {
} len += g_unichar_to_utf8 (gdk_keyval_to_unicode (context_simple->compose_buffer[hexchars]),
} outbuf + len);
else ++hexchars;
{ }
len = g_unichar_to_utf8 (context_simple->tentative_match, outbuf);
}
g_assert (len < 25); g_assert (len < 25);
outbuf[len] = '\0'; outbuf[len] = '\0';
} }
else if (context_simple->tentative_match)
{
len = g_unichar_to_utf8 (context_simple->tentative_match, outbuf);
}
else else
{ {
outbuf[0] = '\0'; outbuf[0] = '\0';
@ -1475,7 +1556,7 @@ gtk_im_context_simple_get_preedit_string (GtkIMContext *context,
} }
if (cursor_pos) if (cursor_pos)
*cursor_pos = (context_simple->tentative_match ? len : 0); *cursor_pos = len;
} }
/** /**