Re: yiddish input method
- From: Noah Levitt <nlevitt columbia edu>
- To: Raphael Finkel <raphael cs uky edu>
- Cc: gtk-i18n-list gnome org
- Subject: Re: yiddish input method
- Date: Tue, 8 Apr 2003 02:38:06 -0400
On Mon, Apr 07, 2003 at 16:31:39 -0400, Raphael Finkel wrote:
>
> It's a matter of taste, not function. I think it is far more pleasant to have
> the currently determined character visible and then to undo it if it turns out
> to be the wrong choice. Otherwise, there will be cases where more than one
> letter gets delayed, and it will be very annoying.
I agree, but I still think that the backspacing hackery is
unnecessary. Please try my attached version. It doesn't
handle final forms yet, but it will (another day, soon :).
I'm sure it has other bugs, but those should be easy to fix.
Noah
/*
* Copyright (c) 2003 Noah Levitt <nlevitt аt columbia.edu>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* GTK+ Yiddish input module
* modeled after Raphael Finkel's Yiddish input module
*/
#include <gtk/gtkimcontext.h>
#include <gtk/gtkimmodule.h>
#include <gtk/gtkintl.h>
#include <gdk/gdkkeysyms.h>
#include <string.h>
GType type_yiddish = 0;
enum { YIDDISH_MAX_COMPOSE_LEN = 2 };
typedef enum
{
YIDDISH_POSITION_MEDIAL,
YIDDISH_POSITION_INITIAL,
YIDDISH_POSITION_FINAL,
}
YiddishPosition;
/* just like GtkIMContextSimple */
static guint compose_buffer[YIDDISH_MAX_COMPOSE_LEN + 1];
static int n_compose = 0;
/* medial is the sorta default */
typedef struct
{
guint keys[YIDDISH_MAX_COMPOSE_LEN + 1]; /* 0-terminated */
gchar *medial;
gchar *initial;
}
ComposeSequence;
static ComposeSequence yiddish_compose_seqs[] =
{
{ { GDK_a, 0, 0, }, "אַ", NULL, },
{ { GDK_A, 0, 0, }, "א", NULL, },
{ { GDK_b, 0, 0, }, "ב", NULL, },
{ { GDK_B, 0, 0, }, "בֿ", NULL, },
{ { GDK_c, 0, 0, }, "צ", NULL, },
{ { GDK_C, 0, 0, }, "צ", NULL, },
{ { GDK_g, 0, 0, }, "ג", NULL, },
{ { GDK_d, 0, 0, }, "ד", NULL, },
{ { GDK_h, 0, 0, }, "ה", NULL, },
{ { GDK_i, 0, 0, }, "י", "אי", },
{ { GDK_I, 0, 0, }, "יִ", "איִ", },
{ { GDK_v, 0, 0, }, "װ", NULL, },
{ { GDK_z, 0, 0, }, "ז", NULL, },
{ { GDK_H, 0, 0, }, "ח", NULL, },
{ { GDK_t, 0, 0, }, "ט", NULL, },
{ { GDK_T, 0, 0, }, "תּ", NULL, },
{ { GDK_y, 0, 0, }, "י", NULL, },
{ { GDK_x, 0, 0, }, "כ", NULL, },
{ { GDK_X, 0, 0, }, "כ", NULL, },
{ { GDK_l, 0, 0, }, "ל", NULL, },
{ { GDK_m, 0, 0, }, "מ", NULL, },
{ { GDK_M, 0, 0, }, "מ", NULL, },
{ { GDK_n, 0, 0, }, "נ", NULL, },
{ { GDK_N, 0, 0, }, "נ", NULL, },
{ { GDK_s, 0, 0, }, "ס", NULL, },
{ { GDK_S, 0, 0, }, "ת", NULL, },
{ { GDK_e, 0, 0, }, "ע", NULL, },
{ { GDK_E, 0, 0, }, "ײ", "אײ", },
{ { GDK_o, 0, 0, }, "אָ", NULL, },
{ { GDK_O, 0, 0, }, "ױ", "אױ", },
{ { GDK_u, 0, 0, }, "ו", "או", },
{ { GDK_U, 0, 0, }, "וּ", "אוּ", },
{ { GDK_p, 0, 0, }, "פּ", NULL, },
{ { GDK_P, 0, 0, }, "פ", NULL, },
{ { GDK_w, 0, 0, }, "ש", NULL, },
{ { GDK_W, 0, 0, }, "שׂ", NULL, },
{ { GDK_f, 0, 0, }, "פ", NULL, },
{ { GDK_F, 0, 0, }, "פ", NULL, },
{ { GDK_k, 0, 0, }, "ק", NULL, },
{ { GDK_K, 0, 0, }, "כּ", NULL, },
{ { GDK_r, 0, 0, }, "ר", NULL, },
{ { GDK_Y, 0, 0, }, "ײַ", "אײַ", },
{ { GDK_minus, 0, 0, }, "־", NULL, },
{ { GDK_apostrophe, 0, 0, }, "'", NULL, },
{ { GDK_comma, 0, 0, }, ",", NULL, },
{ { GDK_s, GDK_h, 0, }, "ש", NULL, },
{ { GDK_t, GDK_s, 0, }, "צ", NULL, },
{ { GDK_t, GDK_z, 0, }, "צ", NULL, },
{ { GDK_z, GDK_h, 0, }, "זש", NULL, },
{ { GDK_a, GDK_y, 0, }, "ײַ", "אײַ", },
{ { GDK_o, GDK_y, 0, }, "ױ", "אױ", },
{ { GDK_d, GDK_j, 0, }, "דזש", NULL, },
{ { GDK_e, GDK_y, 0, }, "ײ", "אײ", },
{ { GDK_apostrophe, GDK_apostrophe, 0, }, "“", NULL, },
{ { GDK_comma, GDK_comma, 0, }, "„", NULL, },
{ { GDK_k, GDK_h, 0, }, "כ", NULL, },
{ { GDK_c, GDK_h, 0, }, "כ", NULL, },
{ { GDK_u, GDK_v, 0, }, "וּװ", "אוּװ", },
{ { GDK_u, GDK_u, 0, }, "וּו", "אוּו", },
{ { GDK_u, GDK_i, 0, }, "ויִ", "אויִ", },
{ { GDK_u, GDK_y, 0, }, "וּי", "אוּי", },
{ { GDK_v, GDK_u, 0, }, "װוּ", NULL, },
{ { GDK_y, GDK_i, 0, }, "ייִ", NULL, },
{ { GDK_i, GDK_i, 0, }, "יִיִ", "איִיִ", },
{ { GDK_i, GDK_y, 0, }, "יִי", "איִי", },
{ { GDK_E, GDK_i, 0, }, "ײיִ", "אײיִ", },
{ { GDK_i, GDK_e, 0, }, "יִע", "איִע", },
{ { GDK_i, GDK_a, 0, }, "יִאַ", "איִאַ", },
{ { GDK_i, GDK_o, 0, }, "יִאָ", "איִאָ", },
};
static const guint16 yiddish_compose_ignore[] =
{
GDK_Shift_L,
GDK_Shift_R,
GDK_Control_L,
GDK_Control_R,
GDK_Caps_Lock,
GDK_Shift_Lock,
GDK_Meta_L,
GDK_Meta_R,
GDK_Alt_L,
GDK_Alt_R,
GDK_Super_L,
GDK_Super_R,
GDK_Hyper_L,
GDK_Hyper_R,
GDK_Mode_switch
};
/* returns the composed string iff keys exactly matches the compose
* sequence keys */
static ComposeSequence *
find_complete_compose_sequence (guint *keys)
{
gint i, j;
for (i = 0; i < G_N_ELEMENTS (yiddish_compose_seqs); i++)
for (j = 0; j <= YIDDISH_MAX_COMPOSE_LEN; j++)
{
if (keys[j] != yiddish_compose_seqs[i].keys[j])
break;
else if (keys[j] == 0 && keys[j] == yiddish_compose_seqs[i].keys[j])
return yiddish_compose_seqs + i;
}
return NULL;
}
/* returns the composed string iff keys is a substring thang of the compose
* sequence keys */
static ComposeSequence *
find_incomplete_compose_sequence (guint *keys)
{
gint i, j;
for (i = 0; i < G_N_ELEMENTS (yiddish_compose_seqs); i++)
for (j = 0; j <= YIDDISH_MAX_COMPOSE_LEN; j++)
{
if (keys[j] == 0 && yiddish_compose_seqs[i].keys[j] != 0)
return yiddish_compose_seqs + i;
else if (keys[j] != yiddish_compose_seqs[i].keys[j])
break;
}
return NULL;
}
static gchar *
get_appropriate_string (ComposeSequence *comp_seq, YiddishPosition position)
{
if (comp_seq == NULL)
return NULL;
else if (position == YIDDISH_POSITION_INITIAL && comp_seq->initial != NULL)
return comp_seq->initial;
else
return comp_seq->medial;
}
/* is this a character that could appear in a yiddish word */
static gboolean
is_yiddish_word_character (gunichar uc)
{
return (((uc >= 0x0590 && uc <= 0x5ff) || (uc >= 0xfb1d && uc <= 0xfb4f))
&& g_unichar_isdefined (uc) && ! g_unichar_ispunct (uc));
}
/* XXX: does not check for final */
static YiddishPosition
get_yiddish_position (GtkIMContext *context)
{
gchar *text;
gchar *prevp;
gint cursor_index;
gunichar uc;
if (! gtk_im_context_get_surrounding (context, &text, &cursor_index))
return YIDDISH_POSITION_MEDIAL;
prevp = g_utf8_find_prev_char (text, text + cursor_index);
if (prevp == NULL)
return YIDDISH_POSITION_INITIAL;
uc = g_utf8_get_char_validated (prevp, text + cursor_index - prevp);
g_return_val_if_fail (uc != (gunichar)(-1) && uc != (gunichar)(-2),
YIDDISH_POSITION_MEDIAL);
if (is_yiddish_word_character (uc))
return YIDDISH_POSITION_MEDIAL;
else
return YIDDISH_POSITION_INITIAL;
}
static void
yiddish_get_preedit_string (GtkIMContext *context,
gchar **str,
PangoAttrList **attrs,
gint *cursor_pos)
{
gchar *string;
gint len;
string = get_appropriate_string (find_complete_compose_sequence (compose_buffer),
get_yiddish_position (context));
if (string == NULL)
*str = g_strdup ("");
else
*str = g_strdup (string);
len = strlen (*str);
if (attrs)
{
*attrs = pango_attr_list_new ();
if (len != 0)
{
PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
attr->start_index = 0;
attr->end_index = len;
pango_attr_list_insert (*attrs, attr);
}
}
if (cursor_pos)
*cursor_pos = len;
}
static void
yiddish_reset (GtkIMContext *context)
{
memset (compose_buffer, 0, sizeof (compose_buffer));
n_compose = 0;
g_signal_emit_by_name (context, "preedit-changed");
}
static void
commit_string (GtkIMContext *context, gchar *string)
{
g_signal_emit_by_name (context, "commit", string);
yiddish_reset (context);
}
static gboolean
no_sequence_matches (GtkIMContext *context, GdkEventKey *event)
{
gunichar uc;
gchar buf[7];
uc = gdk_keyval_to_unicode (event->keyval);
if (uc != 0)
{
buf[g_unichar_to_utf8 (uc, buf)] = '\0';
commit_string (context, buf);
return TRUE;
}
else
return FALSE;
}
static gboolean
yiddish_filter_keypress (GtkIMContext *context,
GdkEventKey *event)
{
YiddishPosition position;
gchar *string;
gint i;
if (event->type == GDK_KEY_RELEASE)
return FALSE;
for (i = 0; i < G_N_ELEMENTS (yiddish_compose_ignore); i++)
if (event->keyval == yiddish_compose_ignore[i])
return FALSE;
position = get_yiddish_position (context);
compose_buffer[n_compose] = event->keyval;
n_compose++;
if (find_incomplete_compose_sequence (compose_buffer) != NULL)
{
g_signal_emit_by_name (context, "preedit-changed");
return TRUE;
}
else if ((string = get_appropriate_string (find_complete_compose_sequence (compose_buffer), position)) != NULL)
{
commit_string (context, string);
return TRUE;
}
/* the last key shouldn't be in the compose buffer */
n_compose--;
compose_buffer[n_compose] = 0;
/* if we have a sequence in the buffer, commit that, then deal with the
* character again; otherwise we have a character that doesn't start any
* sequence, so commit it standardly */
if (n_compose > 0)
{
string = get_appropriate_string (find_complete_compose_sequence (compose_buffer), position);
commit_string (context, string);
return yiddish_filter_keypress (context, event);
}
else
return no_sequence_matches (context, event);
}
static void
yiddish_class_init (GtkIMContextClass *clazz)
{
clazz->filter_keypress = yiddish_filter_keypress;
clazz->get_preedit_string = yiddish_get_preedit_string;
clazz->reset = yiddish_reset;
}
void
im_module_exit ()
{
}
static void
yiddish_init (GtkIMContext *im_context)
{
}
static void
yiddish_register_type (GTypeModule *module)
{
static const GTypeInfo object_info =
{
sizeof (GtkIMContextClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) yiddish_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GtkIMContext),
0,
(GtkObjectInitFunc) yiddish_init,
};
type_yiddish =
g_type_module_register_type (module,
GTK_TYPE_IM_CONTEXT,
"GtkIMContextYiddish",
&object_info, 0);
}
static const GtkIMContextInfo yiddish_info =
{
"yiddish", /* ID */
N_("Yiddish"), /* Human readable name */
"gtk+", /* Translation domain */
GTK_LOCALEDIR, /* Dir for bindtextdomain */
"yi" /* Languages for which this module is the default */
};
static const GtkIMContextInfo *info_list[] =
{
&yiddish_info,
};
void
im_module_init (GTypeModule *module)
{
yiddish_register_type (module);
}
void
im_module_list (const GtkIMContextInfo ***contexts, gint *n_contexts)
{
*contexts = info_list;
*n_contexts = G_N_ELEMENTS (info_list);
}
GtkIMContext *
im_module_create (const gchar *context_id)
{
if (strcmp (context_id, "yiddish") == 0)
return GTK_IM_CONTEXT (g_object_new (type_yiddish, NULL));
else
return NULL;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]