From: simon Date: Sun, 17 Jun 2012 07:26:23 +0000 (+0000) Subject: Support for dead keys and compose sequences on Unix, by instantiating X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/commitdiff_plain/7b56a33fca0f6c9130188db0d2eb475de9380b02 Support for dead keys and compose sequences on Unix, by instantiating a GtkIMMulticontext and having that filter most keypresses. I think I've got this right so that it doesn't break any previous deliberate keyboard-handling behaviour that's now _after_ the 'if (filter keypress) return' statement. git-svn-id: svn://svn.tartarus.org/sgt/putty@9567 cda61777-01e9-0310-a592-d414129be87e --- diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 550ec8c6..0ce3a4f2 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,10 @@ #include #include +#if GTK_CHECK_VERSION(2,0,0) +#include +#endif + #define PUTTY_DO_GLOBALS /* actually _define_ globals */ #include "putty.h" @@ -68,6 +73,9 @@ struct gui_data { *restartitem; GtkWidget *sessionsmenu; GdkPixmap *pixmap; +#if GTK_CHECK_VERSION(2,0,0) + GtkIMContext *imc; +#endif unifont *fonts[4]; /* normal, bold, wide, widebold */ int xpos, ypos, gotpos, gravity; GdkCursor *rawcursor, *textcursor, *blankcursor, *waitcursor, *currcursor; @@ -489,6 +497,10 @@ gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data) if (inst->term) term_invalidate(inst->term); +#if GTK_CHECK_VERSION(2,0,0) + gtk_im_context_set_client_window(inst->imc, widget->window); +#endif + return TRUE; } @@ -539,21 +551,26 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) * inconvenience in having to type a zero before a single-digit * character code. */ - if (event->type == GDK_KEY_RELEASE && - (event->keyval == GDK_Meta_L || event->keyval == GDK_Alt_L || - event->keyval == GDK_Meta_R || event->keyval == GDK_Alt_R) && - inst->alt_keycode >= 0 && inst->alt_digits > 1) { + if (event->type == GDK_KEY_RELEASE) { + if ((event->keyval == GDK_Meta_L || event->keyval == GDK_Alt_L || + event->keyval == GDK_Meta_R || event->keyval == GDK_Alt_R) && + inst->alt_keycode >= 0 && inst->alt_digits > 1) { #ifdef KEY_DEBUGGING - printf("Alt key up, keycode = %d\n", inst->alt_keycode); + printf("Alt key up, keycode = %d\n", inst->alt_keycode); +#endif + /* + * FIXME: we might usefully try to do something clever here + * about interpreting the generated key code in a way that's + * appropriate to the line code page. + */ + output[0] = inst->alt_keycode; + end = 1; + goto done; + } +#if GTK_CHECK_VERSION(2,0,0) + if (gtk_im_context_filter_keypress(inst->imc, event)) + return TRUE; #endif - /* - * FIXME: we might usefully try to do something clever here - * about interpreting the generated key code in a way that's - * appropriate to the line code page. - */ - output[0] = inst->alt_keycode; - end = 1; - goto done; } if (event->type == GDK_KEY_PRESS) { @@ -669,13 +686,13 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) output_charset = CS_ISO8859_1; strncpy(output+1, event->string, lenof(output)-1); #else + if (gtk_im_context_filter_keypress(inst->imc, event)) + return TRUE; + /* * GDK 2.0 arranges to have done some translation for us: in * GDK 2.0, event->string is encoded in the current locale. * - * (However, it's also deprecated; we really ought to be - * using a GTKIMContext.) - * * So we use the standard C library function mbstowcs() to * convert from the current locale into Unicode; from there * we can convert to whatever PuTTY is currently working in. @@ -1136,6 +1153,14 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) return TRUE; } +#if GTK_CHECK_VERSION(2,0,0) +void input_method_commit_event(GtkIMContext *imc, gchar *str, gpointer data) +{ + struct gui_data *inst = (struct gui_data *)data; + lpage_send(inst->ldisc, CS_UTF8, str, strlen(str), 1); +} +#endif + gboolean button_internal(struct gui_data *inst, guint32 timestamp, GdkEventType type, guint ebutton, guint state, gdouble ex, gdouble ey) @@ -2328,6 +2353,17 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, x*inst->font_width+inst->window_border, y*inst->font_height+inst->window_border, len*widefactor*inst->font_width, inst->font_height); + +#if GTK_CHECK_VERSION(2,0,0) + { + GdkRectangle cursorrect; + cursorrect.x = x*inst->font_width+inst->window_border; + cursorrect.y = y*inst->font_height+inst->window_border; + cursorrect.width = len*widefactor*inst->font_width; + cursorrect.height = inst->font_height; + gtk_im_context_set_cursor_location(inst->imc, &cursorrect); + } +#endif } GdkCursor *make_mouse_ptr(struct gui_data *inst, int cursor_val) @@ -3446,6 +3482,8 @@ int pt_main(int argc, char **argv) extern int cfgbox(Conf *conf); struct gui_data *inst; + setlocale(LC_CTYPE, ""); + /* * Create an instance structure and initialise to zeroes */ @@ -3507,6 +3545,10 @@ int pt_main(int argc, char **argv) inst->area = gtk_drawing_area_new(); +#if GTK_CHECK_VERSION(2,0,0) + inst->imc = gtk_im_multicontext_new(); +#endif + setup_fonts_ucs(inst); init_cutbuffers(); @@ -3597,6 +3639,10 @@ int pt_main(int argc, char **argv) GTK_SIGNAL_FUNC(selection_get), inst); gtk_signal_connect(GTK_OBJECT(inst->area), "selection_clear_event", GTK_SIGNAL_FUNC(selection_clear), inst); +#if GTK_CHECK_VERSION(2,0,0) + g_signal_connect(G_OBJECT(inst->imc), "commit", + G_CALLBACK(input_method_commit_event), inst); +#endif if (conf_get_int(inst->conf, CONF_scrollbar)) gtk_signal_connect(GTK_OBJECT(inst->sbar_adjust), "value_changed", GTK_SIGNAL_FUNC(scrollbar_moved), inst); diff --git a/unix/uxucs.c b/unix/uxucs.c index 20f25d4e..9d8242f8 100644 --- a/unix/uxucs.c +++ b/unix/uxucs.c @@ -29,7 +29,6 @@ int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen, mbstate_t state; memset(&state, 0, sizeof state); - setlocale(LC_CTYPE, ""); while (mblen > 0) { size_t i = mbrtowc(wcstr+n, mbstr, (size_t)mblen, &state); @@ -40,8 +39,6 @@ int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen, mblen -= i; } - setlocale(LC_CTYPE, "C"); - return n; } else if (codepage == CS_NONE) { int n = 0; @@ -73,7 +70,6 @@ int wc_to_mb(int codepage, int flags, const wchar_t *wcstr, int wclen, int n = 0; memset(&state, 0, sizeof state); - setlocale(LC_CTYPE, ""); while (wclen > 0) { int i = wcrtomb(output, wcstr[0], &state); @@ -85,8 +81,6 @@ int wc_to_mb(int codepage, int flags, const wchar_t *wcstr, int wclen, wclen--; } - setlocale(LC_CTYPE, "C"); - return n; } else if (codepage == CS_NONE) { int n = 0;