summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorHavoc Pennington <hp@pobox.com>2000-12-06 05:31:30 +0000
committerHavoc Pennington <hp@src.gnome.org>2000-12-06 05:31:30 +0000
commit36aac0177bfe4dfed46cfcf8568256fe5b05f9b0 (patch)
tree5091a09100b1743bf733d47dde7db34e9b673fc6 /gtk
parent3bc53c742d676a974987ad084f8617a1ab6068fd (diff)
downloadgtk+-36aac0177bfe4dfed46cfcf8568256fe5b05f9b0.tar.gz
add gdkkeys.[hc]
2000-12-03 Havoc Pennington <hp@pobox.com> * gdk/Makefile.am: add gdkkeys.[hc] * gdk/gdkkeys.h, gdk/gdkkeys.c: Move all the keyval stuff to these files from gdk.h, gdk.c; add GdkKeymap type and operations on it. * acconfig.h, configure.in: add checks and command line options for XKB * gdk/x11/gdkkeys-x11.c: Implement the above functions * gdk/x11/gdkevents-x11.c (gdk_event_translate): Put the keycode and group in the key event * gdk/gdkevents.h (struct _GdkEventKey): Add a hardware_keycode field with the low-level hardware key code, and a group field with the keyboard group * gdk/x11/gdkprivate-x11.h: include config.h for HAVE_XKB, and declare a couple globals used for keymap handling * gtk/gtkimcontextsimple.c: Implement ISO 14755 input method, hold down Shift-Control and type a hex number to get a Unicode character corresponding to the hex number (gtk_im_context_simple_get_preedit_string): Fix cursor position (return bytes not chars)
Diffstat (limited to 'gtk')
-rw-r--r--gtk/gtkimcontextsimple.c273
-rw-r--r--gtk/gtkimcontextsimple.h2
-rw-r--r--gtk/gtktextiter.h7
3 files changed, 241 insertions, 41 deletions
diff --git a/gtk/gtkimcontextsimple.c b/gtk/gtkimcontextsimple.c
index 990fedad4e..78c254728a 100644
--- a/gtk/gtkimcontextsimple.c
+++ b/gtk/gtkimcontextsimple.c
@@ -794,7 +794,7 @@ gtk_im_context_simple_class_init (GtkIMContextSimpleClass *class)
static void
gtk_im_context_simple_init (GtkIMContextSimple *im_context_simple)
-{
+{
}
static void
@@ -823,6 +823,8 @@ gtk_im_context_simple_commit_char (GtkIMContext *context,
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;
@@ -916,45 +918,86 @@ check_table (GtkIMContextSimple *context_simple,
return FALSE;
}
+/* 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.
+ */
+
+#define ISO_14755_MOD_MASK (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
+
static gboolean
-gtk_im_context_simple_filter_keypress (GtkIMContext *context,
- GdkEventKey *event)
+check_hex (GtkIMContextSimple *context_simple,
+ gint n_compose)
{
- GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
- GSList *tmp_list;
+ /* See if this is a hex sequence, return TRUE if so */
+ gint i;
+ GString *str;
+ gulong n;
+ gchar *nptr = NULL;
- gunichar ch;
- int n_compose = 0;
- int i;
+ str = g_string_new (NULL);
+
+ i = 0;
+ while (i < n_compose)
+ {
+ gunichar ch;
+ gchar buf[7];
+
+ ch = gdk_keyval_to_unicode (context_simple->compose_buffer[i]);
+
+ if (ch == 0)
+ return FALSE;
- /* Ignore modifier key presses, and any presses with modifiers set
- */
- for (i=0; i < G_N_ELEMENTS (gtk_compose_ignore); i++)
- if (event->keyval == gtk_compose_ignore[i])
- return FALSE;
+ if (!g_unichar_isxdigit (ch))
+ return FALSE;
- if (event->state &
- (gtk_accelerator_get_default_mod_mask () & ~GDK_SHIFT_MASK))
- return FALSE;
-
- /* Then, check for compose sequences
- */
- while (context_simple->compose_buffer[n_compose] != 0)
- n_compose++;
+ buf[g_unichar_to_utf8 (ch, buf)] = '\0';
- context_simple->compose_buffer[n_compose++] = event->keyval;
- context_simple->compose_buffer[n_compose] = 0;
+ g_string_append (str, buf);
+
+ ++i;
+ }
- tmp_list = context_simple->tables;
- while (tmp_list)
+ n = strtoul (str->str, &nptr, 16);
+
+ /* if strtoul fails it probably means non-latin digits were used;
+ * we should in principle handle that, but we probably don't.
+ */
+ if (str->str == nptr)
{
- if (check_table (context_simple, tmp_list->data, n_compose))
- return TRUE;
- tmp_list = tmp_list->next;
+ g_string_free (str, TRUE);
+ return FALSE;
}
+ else
+ g_string_free (str, TRUE);
+
+ if (n > 0xFFFF)
+ return FALSE; /* too many digits */
+
+ if (n == 0)
+ return FALSE; /* don't insert nul bytes */
+
+ context_simple->tentative_match = n;
+ context_simple->tentative_match_len = n_compose;
+
+ gtk_signal_emit_by_name (GTK_OBJECT (context_simple),
+ "preedit-changed");
+
+ return TRUE;
+}
+
+static gboolean
+no_sequence_matches (GtkIMContextSimple *context_simple,
+ gint n_compose,
+ GdkEventKey *event)
+{
+ GtkIMContext *context;
+ gunichar ch;
- if (check_table (context_simple, &gtk_compose_table, n_compose))
- return TRUE;
+ context = GTK_IM_CONTEXT (context_simple);
/* No compose sequences found, check first if we have a partial
* match pending.
@@ -997,6 +1040,139 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
}
}
+static gboolean
+is_hex_keyval (guint keyval)
+{
+ gunichar ch = gdk_keyval_to_unicode (keyval);
+
+ return g_unichar_isxdigit (ch);
+}
+
+static guint
+canonical_hex_keyval (GdkEventKey *event)
+{
+ guint keyval;
+ guint *keyvals = NULL;
+ gint n_vals = 0;
+ gint i;
+
+ /* See if the keyval is already a hex digit */
+ if (is_hex_keyval (event->keyval))
+ return event->keyval;
+
+ /* See if this key would have generated a hex keyval in
+ * any other state, and return that hex keyval if so
+ */
+ gdk_keymap_get_entries_for_keycode (NULL,
+ event->hardware_keycode, NULL,
+ &keyvals, &n_vals);
+
+ keyval = 0;
+ i = 0;
+ while (i < n_vals)
+ {
+ if (is_hex_keyval (keyvals[i]))
+ {
+ keyval = keyvals[i];
+ break;
+ }
+
+ ++i;
+ }
+
+ g_free (keyvals);
+
+ if (keyval)
+ return keyval;
+ else
+ /* just return the keyval unchanged, we couldn't figure
+ * out a way to make it a hex digit
+ */
+ return event->keyval;
+}
+
+static gboolean
+gtk_im_context_simple_filter_keypress (GtkIMContext *context,
+ GdkEventKey *event)
+{
+ GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
+ GSList *tmp_list;
+ int n_compose = 0;
+ int i;
+
+ /* FIXME? 14755 says you have to commit the char on release of the shift/control
+ * keys. But instead we wait for the user to type another char, or to lose focus.
+ */
+
+ /* Ignore modifier key presses
+ */
+ for (i=0; i < G_N_ELEMENTS (gtk_compose_ignore); i++)
+ if (event->keyval == gtk_compose_ignore[i])
+ return FALSE;
+
+ while (context_simple->compose_buffer[n_compose] != 0)
+ n_compose++;
+
+ /* First key in sequence; decide if it's a 14755 hex sequence */
+ if (n_compose == 0)
+ context_simple->in_hex_sequence =
+ ((event->state & (ISO_14755_MOD_MASK)) == ISO_14755_MOD_MASK);
+
+ /* If we are already in a non-hex sequence, or
+ * the 14755 modifiers are not held down, filter all
+ * key events with accelerator modifiers held down.
+ */
+ if (!context_simple->in_hex_sequence ||
+ ((event->state & (ISO_14755_MOD_MASK)) != ISO_14755_MOD_MASK))
+ {
+ if (event->state &
+ (gtk_accelerator_get_default_mod_mask () & ~GDK_SHIFT_MASK))
+ return FALSE;
+ }
+
+ /* Then, check for compose sequences
+ */
+ if (context_simple->in_hex_sequence)
+ context_simple->compose_buffer[n_compose++] = canonical_hex_keyval (event);
+ else
+ context_simple->compose_buffer[n_compose++] = event->keyval;
+
+ context_simple->compose_buffer[n_compose] = 0;
+
+ if (context_simple->in_hex_sequence)
+ {
+ /* If the modifiers are still held down, consider the sequence again */
+ if ((event->state & (ISO_14755_MOD_MASK)) == ISO_14755_MOD_MASK)
+ {
+ /* space ends the sequence, and we eat the space */
+ if (n_compose > 1 && event->keyval == GDK_space)
+ {
+ gtk_im_context_simple_commit_char (context, context_simple->tentative_match);
+ context_simple->compose_buffer[0] = 0;
+ return TRUE;
+ }
+ else if (check_hex (context_simple, n_compose))
+ return TRUE;
+ }
+ }
+ else
+ {
+ tmp_list = context_simple->tables;
+ while (tmp_list)
+ {
+ if (check_table (context_simple, tmp_list->data, n_compose))
+ return TRUE;
+ tmp_list = tmp_list->next;
+ }
+
+ if (check_table (context_simple, &gtk_compose_table, n_compose))
+ return TRUE;
+ }
+
+ /* The current compose_buffer doesn't match anything */
+ return no_sequence_matches (context_simple, n_compose, event);
+}
+
static void
gtk_im_context_simple_reset (GtkIMContext *context)
{
@@ -1006,6 +1182,8 @@ gtk_im_context_simple_reset (GtkIMContext *context)
if (context_simple->tentative_match)
gtk_im_context_simple_commit_char (context, context_simple->tentative_match);
+
+ context_simple->in_hex_sequence = FALSE;
}
static void
@@ -1014,32 +1192,51 @@ gtk_im_context_simple_get_preedit_string (GtkIMContext *context,
PangoAttrList **attrs,
gint *cursor_pos)
{
- char outbuf[7];
+ char outbuf[25]; /* up to 4 hex digits */
int len = 0;
-
+
GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
if (context_simple->tentative_match)
- len = g_unichar_to_utf8 (context_simple->tentative_match, outbuf);
-
+ {
+ 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);
+ }
+
+ g_assert (len <= 25);
+ outbuf[len] = '\0';
+ }
+
if (str)
- *str = g_strndup (outbuf, len);
+ *str = g_strdup (outbuf);
if (attrs)
{
*attrs = pango_attr_list_new();
-
+
if (len)
{
PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
attr->start_index = 0;
- attr->end_index = len;
+ attr->end_index = len;
pango_attr_list_insert (*attrs, attr);
}
}
if (cursor_pos)
- *cursor_pos = context_simple->tentative_match ? 1 : 0;
+ *cursor_pos = (context_simple->tentative_match ? len : 0);
}
/**
diff --git a/gtk/gtkimcontextsimple.h b/gtk/gtkimcontextsimple.h
index f166d82b47..af563d67af 100644
--- a/gtk/gtkimcontextsimple.h
+++ b/gtk/gtkimcontextsimple.h
@@ -49,6 +49,8 @@ struct _GtkIMContextSimple
guint compose_buffer[GTK_MAX_COMPOSE_LEN + 1];
gunichar tentative_match;
gint tentative_match_len;
+
+ guint in_hex_sequence : 1;
};
struct _GtkIMContextSimpleClass
diff --git a/gtk/gtktextiter.h b/gtk/gtktextiter.h
index 1c32fdaeb0..a2d4eacd6c 100644
--- a/gtk/gtktextiter.h
+++ b/gtk/gtktextiter.h
@@ -84,12 +84,13 @@ gint gtk_text_iter_get_line_index (const GtkTextIter *iter);
*/
gunichar gtk_text_iter_get_char (const GtkTextIter *iter);
-/* includes the 0xFFFD char for pixmaps/widgets, so char offsets
- into the returned string map properly into buffer char offsets */
+/* includes the 0xFFFC char for pixmaps/widgets, so char offsets
+ * into the returned string map properly into buffer char offsets
+ */
gchar *gtk_text_iter_get_slice (const GtkTextIter *start,
const GtkTextIter *end);
-/* includes only text, no 0xFFFD */
+/* includes only text, no 0xFFFC */
gchar *gtk_text_iter_get_text (const GtkTextIter *start,
const GtkTextIter *end);
/* exclude invisible chars */