Home Download Buy Blog Forum Support

Input method support

Re: Input method support

Postby tonytonyjan on Wed Jan 16, 2013 10:13 am

cjacker wrote:This is a dirty fix but at least works. cursor position update also supported.

Use LD_PRELOAD to reimplement gtk_im_context_set_client_window and set im focus in.
use "gdk_region_get_clipbox" to catch the caret position. (It's really difficult to find which function can catch the position....)
...


I've tried your method and got the following result:

Code: Select all
$ gcc -shared -o libsublime-imfix.so sublime_imfix.c  `pkg-config --libs --cflags gtk+-2.0` -fPIC
$ LD_PRELOAD=./libsublime-imfix.so sublime-text
ERROR: ld.so: object './libsublime-imfix.so' from LD_PRELOAD cannot be preloaded: ignored.


Code: Select all
$ uname -ai
Linux tonytonyjan-Latitude-6430U 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:31:23 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux


Is there any message I can give you?
tonytonyjan
 
Posts: 2
Joined: Thu Nov 15, 2012 10:54 am

Re: Input method support

Postby RadarNyan on Wed Feb 13, 2013 8:54 pm

cjacker wrote:This is a dirty fix but at least works. cursor position update also supported.

Use LD_PRELOAD to reimplement gtk_im_context_set_client_window and set im focus in.
use "gdk_region_get_clipbox" to catch the caret position. (It's really difficult to find which function can catch the position....)
[/code]


I tried this on Ubuntu 12.04, it works but only work for FCITX not ibus.
I sure get cursor location update, but there still is some problem (actually a big one) - backspace will erase the text before cursor, not character in IME.

So, I guess I just went back to ibus since it makes me feel better :) Anyway, great work.

Another question: is it possible to bring this cursor location update feature to Windows version of sublime?
IME works better on Windows version of sublime, the only problem is cursor location update. If you can fix that, it will be really great.

Enz0 wrote:For Sublime Text 2, there was a nice plugin for supporting input method.


Thanks dude, that works perfect!
Last edited by RadarNyan on Thu Feb 28, 2013 4:00 am, edited 1 time in total.
RadarNyan
 
Posts: 1
Joined: Wed Feb 13, 2013 8:42 pm

Re: Input method support

Postby Enz0 on Tue Feb 26, 2013 1:30 am

For Sublime Text 2, there was a nice plugin for supporting input method.
https://github.com/chikatoike/IMESuppor ... DME_en.org
Now that Sublime Text 3 has threaded plugin system, the plugin no longer works properly, at least in my environment.
Because the plugin hooks the input, there are some side effects like BracketHighlighter becomes unworkable.
Please support the input method correctly, especially with Sublime Text 3 for Windows.
Enz0
 
Posts: 5
Joined: Tue Dec 18, 2012 2:43 pm

Re: Input method support

Postby dmikalova on Tue May 21, 2013 10:51 pm

I wasn't able to use my compose key at all on Arch Linux running KDE with xim in ST2, I tried scim but it didn't supposed custom compose keys from ~/.XCompose, but I was able to fix this for Linux by changing to scim-uim

To enable this for all GTK apps, put this into your ~/.xprofile after installing scim-uim, and then restart X:
Code: Select all
    GTK_IM_MODULE=uim-scim

Note that there are other ways to do this that make this work for all users on the computer and whatnot.
To run it just for ST2, or test it out without restarting, run this in your preferred console, set it as a bash alias, etc:
Code: Select all
    export GTK_IM_MODULE=uim-scim subl

Compose, and ~/.XCompose should now work.
dmikalova
 
Posts: 4
Joined: Tue May 21, 2013 10:43 pm

Re: Input method support

Postby bodaShandis on Thu Oct 10, 2013 6:31 pm

Sublime text used to be my favorite. Now due to this problem I've had to switch editors. So upsettting.
bodaShandis
 
Posts: 1
Joined: Thu Oct 10, 2013 6:28 pm

Re: Input method support

Postby whitequark on Mon Apr 14, 2014 3:05 am

whitequark
 
Posts: 6
Joined: Wed Aug 29, 2012 6:03 pm

Re: Input method support

Postby cjacker on Mon Jun 09, 2014 11:05 am

Here is the update solution to combine whitequark's fix for XIM immodule.

My original codes only works with fcitx immodule.
Whitequark's codes only workds with xim immodule and without cursor position update support.

Here is the better one to support GTK_IM_MODULE=fcitx or GTK_IM_MODULE=xim and both support cursor position update.

For how to interpose(I am still too lasy to explain it:-D), maybe you can refer to whitequark's blog.

Code: Select all
/*
sublime-imfix.c
Use LD_PRELOAD to interpose some function to fix sublime input method support for linux.
By Cjacker Huang <jianzhong.huang at i-soft.com.cn>
By whitequark@whitequark.org

How to compile:
gcc -shared -o libsublime-imfix.so sublime_imfix.c  `pkg-config --libs --cflags gtk+-2.0` -fPIC
How to use:
LD_PRELOAD=./libsublime-imfix.so sublime_text

Changes:
2014 06-09
1, Fix cursor position update for sublime text 3.
2, Combine the codes from whitequark(fix for xim immodule) and add cursor update support for XIM immodule.
*/

/*for RTLD_NEXT*/
#define _GNU_SOURCE

#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <assert.h>
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#ifdef VERBOSE
#define DEBUG(fmt, ...) do { \
    FILE* err = fopen("/tmp/libsublime-immethod-fix.log", "a"); \
    if (err) { \
      fprintf(err, fmt, __VA_ARGS__); \
      fclose(err); \
    } \
  } while(0)
#else
#define DEBUG(fmt, ...)
#endif


typedef GdkSegment GdkRegionBox;

struct _GdkRegion
{
  long size;
  long numRects;
  GdkRegionBox *rects;
  GdkRegionBox extents;
};

GtkIMContext *local_context;


//this func is interposed to support cursor position update.
void
gdk_region_get_clipbox (const GdkRegion *region,
            GdkRectangle    *rectangle)
{
  g_return_if_fail (region != NULL);
  g_return_if_fail (rectangle != NULL);

  rectangle->x = region->extents.x1;
  rectangle->y = region->extents.y1;
  rectangle->width = region->extents.x2 - region->extents.x1;
  rectangle->height = region->extents.y2 - region->extents.y1;
  GdkRectangle rect;
  rect.x = rectangle->x;
  rect.y = rectangle->y;
  rect.width = 0;
  rect.height = rectangle->height;
  //The caret width is 2 in sublime text 2
  //And is 1 in sublime text 3.
  //Maybe sometimes we will make a mistake, but for most of the time, it should be the caret.
  if((rectangle->width == 2 || rectangle->width == 1)  && GTK_IS_IM_CONTEXT(local_context)) {
        gtk_im_context_set_cursor_location(local_context, rectangle);
  }
}

//this is needed, for example, if you input something in file dialog and return back the edit area
//context will lost, so here we set it again.
static GdkFilterReturn event_filter (GdkXEvent *xevent, GdkEvent *event, gpointer im_context)
{
    XEvent *xev = (XEvent *)xevent;
    if(xev->type == KeyRelease && GTK_IS_IM_CONTEXT(im_context)) {
       GdkWindow * win = g_object_get_data(G_OBJECT(im_context),"window");
       if(GDK_IS_WINDOW(win))
         gtk_im_context_set_client_window(im_context, win);
    }
    return GDK_FILTER_CONTINUE;
}

void gtk_im_context_set_client_window (GtkIMContext *context,
          GdkWindow    *window)
{
    GtkIMContextClass *klass;
    g_return_if_fail (GTK_IS_IM_CONTEXT (context));
    klass = GTK_IM_CONTEXT_GET_CLASS (context);
    if (klass->set_client_window)
        klass->set_client_window (context, window);

    //below is our interposed codes to save the context to local_context.
    if(!GDK_IS_WINDOW (window))
        return;
    g_object_set_data(G_OBJECT(context),"window",window);
    int width = gdk_window_get_width(window);
    int height = gdk_window_get_height(window);
    if(width != 0 && height !=0) {
        gtk_im_context_focus_in(context);
        local_context = context;
    }
    //only add this event_filter when using 'fcitx' immodule.
    //for xim immodule, this function is as same as original from gtk2.
    const gchar * immodule = g_getenv("GTK_IM_MODULE");
    if(immodule && !strcmp(immodule, "fcitx")) {
        gdk_window_add_filter (window, event_filter, context);
    }
}


/*below codes is from whitequark, fix for xim immodule*/

/* See gtkimcontextxim.c */
GType gtk_type_im_context_xim = 0;

#define GTK_TYPE_IM_CONTEXT_XIM            (gtk_type_im_context_xim)
#define GTK_IM_CONTEXT_XIM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_IM_CONTEXT_XIM, GtkIMContextXIM))
#define GTK_IM_CONTEXT_XIM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_IM_CONTEXT_XIM, GtkIMContextXIMClass))
#define GTK_IS_IM_CONTEXT_XIM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_IM_CONTEXT_XIM))
#define GTK_IS_IM_CONTEXT_XIM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_IM_CONTEXT_XIM))
#define GTK_IM_CONTEXT_XIM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_IM_CONTEXT_XIM, GtkIMContextXIMClass))

typedef struct _GtkIMContextXIM       GtkIMContextXIM;
typedef struct _GtkIMContextXIMClass  GtkIMContextXIMClass;

struct _GtkIMContextXIMClass
{
  GtkIMContextClass parent_class;
};

typedef struct _StatusWindow StatusWindow;
typedef struct _GtkXIMInfo GtkXIMInfo;

struct _GtkIMContextXIM
{
  GtkIMContext object;

  GtkXIMInfo *im_info;

  gchar *locale;
  gchar *mb_charset;

  GdkWindow *client_window;
  GtkWidget *client_widget;

  /* The status window for this input context; we claim the
*    * status window when we are focused and have created an XIC
*       */
  StatusWindow *status_window;

  gint preedit_size;
  gint preedit_length;
  gunichar *preedit_chars;
  XIMFeedback *feedbacks;

  gint preedit_cursor;

  XIMCallback preedit_start_callback;
  XIMCallback preedit_done_callback;
  XIMCallback preedit_draw_callback;
  XIMCallback preedit_caret_callback;

  XIMCallback status_start_callback;
  XIMCallback status_done_callback;
  XIMCallback status_draw_callback;

  XIMCallback string_conversion_callback;

  XIC ic;

  guint filter_key_release : 1;
  guint use_preedit : 1;
  guint finalizing : 1;
  guint in_toplevel : 1;
  guint has_focus : 1;
};

static GClassInitFunc orig_gtk_im_context_xim_class_init;
static GType (*orig_g_type_module_register_type)(GTypeModule *,
                                                 GType, const gchar *,
                                                 const GTypeInfo *, GTypeFlags);
static gboolean (*orig_gtk_im_context_xim_filter_keypress)(GtkIMContext *context,
                                                           GdkEventKey *event);

static gboolean
hook_gtk_im_context_xim_filter_keypress(GtkIMContext *context, GdkEventKey *event) {
  GtkIMContextXIM *im_context_xim = GTK_IM_CONTEXT_XIM(context);
  if (!im_context_xim->client_window) {
    DEBUG("im_context_xim == %p\n", im_context_xim);
    DEBUG("event->window == %p\n", event->window);

    gtk_im_context_set_client_window(context, event->window);
  }

  return orig_gtk_im_context_xim_filter_keypress(context, event);
}

static void
hook_gtk_im_context_xim_class_init (GtkIMContextXIMClass *class) {
  orig_gtk_im_context_xim_class_init(class, NULL); /* wat? */

  GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class);

  assert(!orig_gtk_im_context_xim_filter_keypress);
  orig_gtk_im_context_xim_filter_keypress = im_context_class->filter_keypress;
  im_context_class->filter_keypress = hook_gtk_im_context_xim_filter_keypress;
  DEBUG("orig_gtk_im_context_xim_filter_keypress: %p\n",
        orig_gtk_im_context_xim_filter_keypress);
}

GType
g_type_module_register_type (GTypeModule *module,
                             GType parent_type,
                             const gchar *type_name,
                             const GTypeInfo *type_info,
                             GTypeFlags flags) {
  if (!orig_g_type_module_register_type) {
    orig_g_type_module_register_type = dlsym(RTLD_NEXT, "g_type_module_register_type");
    assert(orig_g_type_module_register_type);
  }

  if (type_name && !strcmp(type_name, "GtkIMContextXIM")) {
    assert(!orig_gtk_im_context_xim_class_init);
    orig_gtk_im_context_xim_class_init = type_info->class_init;

    assert(sizeof(GtkIMContextXIM) == type_info->instance_size);

    const GTypeInfo hook_im_context_xim_info =
    {
      type_info->class_size,
      type_info->base_init,
      type_info->base_finalize,
      (GClassInitFunc) hook_gtk_im_context_xim_class_init,
      type_info->class_finalize,
      type_info->class_data,
      type_info->instance_size,
      type_info->n_preallocs,
      type_info->instance_init,
    };

    DEBUG("orig_gtk_im_context_xim_class_init: %p\n", orig_gtk_im_context_xim_class_init);

    gtk_type_im_context_xim =
      orig_g_type_module_register_type(module, parent_type, type_name,
                                       &hook_im_context_xim_info, flags);

    return gtk_type_im_context_xim;
  }

  return orig_g_type_module_register_type(module, parent_type, type_name, type_info, flags);
}

cjacker
 
Posts: 4
Joined: Thu Dec 27, 2012 10:16 am

Re: Input method support

Postby wilo108 on Wed Jul 16, 2014 6:42 am

thank you so much to whitequark and cjacker. i've just invested a few days getting familiar with Sublime Text and talking myself into the making the psychologically wrenching step of switching code editors, and then I ran into this problem, which is a total deal-breaker for me. the interposition works very nicely, but i do find it more than a little disconcerting that the developers seem to have no interest in this issue -- even when the community has effectively discovered, diagnosed and solved it for them... i was already a little uncomfortable using a non-open-source code editor... think i'll delay my purchase a bit longer and see how this plays out.
wilo108
 
Posts: 2
Joined: Wed Jul 09, 2014 4:26 am

Re: Input method support

Postby oglop on Wed Sep 10, 2014 9:52 am

i tried to fork chikatoike's SublimeIBus https://github.com/chikatoike/SublimeIBus to make chinese/english hybrid input work in sublime 2 , but due to my technical skills, i can't figure out how to get rid of the redundent return after you press enter. it's 90% working i could say ...

check my repo https://github.com/oglops/SublimeIBus

check this gyfcat screencast http://gfycat.com/HeartfeltEnlightenedGentoopenguin
oglop
 
Posts: 2
Joined: Mon Sep 08, 2014 3:15 am

Re: Input method support

Postby stevenfrog on Sun Sep 28, 2014 12:24 pm

Hello cjacker:
I'm using ubuntu 12.04, with sublime text3. 3065.

Code: Select all
stevenfrog@frog-Z87P:~$ uname -a
Linux frog-Z87P 3.11.0-26-generic #45~precise1-Ubuntu SMP Tue Jul 15 04:02:35 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux


I meet a strange problem with fcitx.
I can call fcitx in Sublime3 successful, and input chinese successful too.
But I can not type "Backspace", If I type "Backspace", it will not del what I just typed, but del char in sublime view!
For example:
Current sublime view is : "Hello World", and I want to insert a chinese word like "你好", I need type "nihao" and a "space".
But If I type wrong char when inserting chinese like "nihaoxx",
And after I type two "Backspace", view change to "Hellow Wor", and fcitx input box is still "nihaoxx".

And I find If will comment "{ "keys": ["backspace"], "command": "left_delete" }," , it works, but I can not use backspace in sublime too.

Does anyone meet problem like this?
stevenfrog
 
Posts: 1
Joined: Sun Sep 28, 2014 9:10 am

Previous

Return to Technical Support

Who is online

Users browsing this forum: Google [Bot], Yahoo [Bot] and 31 guests