changeset 16:598fcbe482b5

imported patch 19_kinput2-v3.1-ruby.patch
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Mon, 08 Mar 2010 20:38:17 +0900
parents 89750191b165
children 688ac5040e7d
files ChangeLog Kinput2.conf autogen.sh cmd/Imakefile cmd/kinput2.c include/Ruby.h include/RubyP.h lib/Imakefile lib/Prime.rb lib/Ruby.c lib/Ruby.rb lib/Xrubylib/Imakefile lib/Xrubylib/callbacks.txt lib/Xrubylib/memo.txt lib/Xrubylib/misc.c lib/imlib/imxport.c lib/ruby-c.c lib/ruby-c.h lib/ruby/Imakefile lib/ruby/kinput2.rb lib/ruby/kinput2_default.rb lib/ruby/kinput2_prime.rb lib/ruby/test/testPrime.rb
diffstat 23 files changed, 3537 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChangeLog	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,120 @@
+2003-03-25  Hiroyuki Komatsu  <komatsu@taiyaki.org>
+
+	* lib/ruby/kinput2_prime.rb (Repository): 
+	- Change lookup method from lookup_prefix to lookup_hybrid.
+
+2003-02-03  Hiroyuki Komatsu  <komatsu@taiyaki.org>
+
+	* lib/Ruby.c (Repository):
+	- Get $LOAD_PATH in Ruby by execution of ruby command.
+
+2003-01-20  Hiroyuki Komatsu  <komatsu@taiyaki.org>
+
+	* lib/Ruby.c (Repository): 
+	- Create `rubyDialogDisplay', `rubySelectionDisplay' and
+	  `rubySelectionEvent' functions.
+	- Refine the code.
+
+	* lib/Ruby.rb (Repository): 
+	- Create `ConvMode' class.
+	- Create `Window', and `Selection' class.
+	- Create `JEditText' class.
+	
+2003-01-19  Hiroyuki Komatsu  <komatsu@taiyaki.org>
+
+	* lib/Ruby.c (Repository): 
+	- Add some methods for Selection.
+	- Fix SEGV error in `ConvertedString'
+
+	* lib/Ruby.rb (Repository): 
+	- Add PRIME!
+	
+
+2003-01-18  Hiroyuki Komatsu  <komatsu@taiyaki.org>
+
+	* lib/Ruby.rb (Repository): 
+	- Change name dialog to selection.
+	- Create new dialog as AUXSegment.
+
+	* lib/Ruby.c (Repository): 
+	- Create `GetAuxSegments' function for Ruby.
+	- Modify `rubyDisplayPreEdit' for AuxSegments.
+	- Commentout all debug messages which have variables,
+	  because of a unknown bug.
+	
+
+2003-01-17  Hiroyuki Komatsu  <komatsu@taiyaki.org>
+
+	* lib/Ruby.rb (Repository): 
+	- Create a class `TextEdit'.
+	- Improving class structures.
+	- Add methods for input events.
+	- Create Segment functions for cursor motion.
+
+	* lib/Ruby.c (Repository):
+	- Change `InputEvent'.
+	- Modify `GetSegment' function for cursor motion.
+	
+
+2003-01-16  Hiroyuki Komatsu  <komatsu@taiyaki.org>
+
+	* lib/Ruby.c (Repository):
+	- Change `displayPreEdit' to `rubyDisplayPreEdit'.
+	- Modify `NumSegments' for Ruby.
+
+	* lib/Ruby.rb (Repository):
+	- Add `clear' function.
+	- Modify `segment_length' function.
+	
+	* lib/Ruby.c (Repository):
+	- Modified a function `CursorPos' for Ruby.
+	- Modifying a function `GetAuxSegments' for Ruby.
+	To finish the modification, it is required that
+	a definition about a data structure for word parts.
+
+	* lib/Ruby.rb (Repository):
+	Add a new variable 'cand_list'.
+
+	* lib/Ruby.c (Repository): 
+	Add a new function 'rubyEUCArraytoICStringArray'.
+
+2003-01-15  Hiroyuki Komatsu  <komatsu@taiyaki.org>
+
+	* .cvsignore: [NEW FILE]
+
+	* lib/Ruby.c (Repository):
+	Finish to make a function 'rubyEUC2ICString'. It's been working.
+
+2003-01-14  Hiroyuki Komatsu  <komatsu@taiyaki.org>
+
+	* lib/Xrubylib/memo.txt (Repository):
+	Add a description about ICString and it's Memory management.
+
+	* lib/Ruby.c (Repository): Add a function 'rubyEUC2ICString'.
+	However, it has not been working.
+	
+	* lib/Ruby.rb (Repository): Add space-key action.
+		
+2003-01-12  Hiroyuki Komatsu  <komatsu@taiyaki.org>
+
+	* lib/Ruby.rb (Repository): Add comment about keycodes.
+
+2003-01-11  Hiroyuki Komatsu  <komatsu@taiyaki.org>
+
+	* lib/Ruby.c (Repository): 
+	Trap InputEvent and ConvertedString for test.
+
+	* lib/Ruby.rb (Repository): [NEW FILE]
+	Ruby script for Ruby.c
+
+	* lib/Xrubylib/misc.c (Repository): [NEW FILE] 
+	Copy euc2wcs and wcs2euc functions from Xatoklib/misc.c
+
+2003-01-10  Hiroyuki Komatsu  <komatsu@taiyaki.org>
+
+	* lib/ruby-c.c: [NEW FILE] a library to invoke ruby.
+	* lib/ruby-c.h: [NEW FILE] a library to invoke ruby.
+	* lib/Ruby.c: Early stage to use ruby.
+	Almost all functions for canna are not modified yet.
+	
+
--- a/Kinput2.conf	Mon Mar 08 20:38:16 2010 +0900
+++ b/Kinput2.conf	Mon Mar 08 20:38:17 2010 +0900
@@ -20,6 +20,7 @@
 #define UseCanna	/* define if you are going to use Canna */
 #define UseSj3		/* define if you are going to use Sj3 */
 /* #define UseAtok */	/* define if you are going to use Atok */
+/* #define UseRuby */	/* define if you are going to use Ruby */
 
 
 XCOMM Wnn configuration
@@ -137,6 +138,23 @@
 ATOKLIB = -latok12n -latok12util
 
 
+XCOMM Ruby configuration
+/*
+ * If you define UseRuby, set following 2 variables:
+ *	RUBYSRC: Ruby source directory (or directory of installed headers)
+ *	RUBYLIB: Ruby user library
+ */
+
+/*
+ * If you have already installed Ruby header files and libraries..
+ */
+XCOMM use installed headers/libraries
+
+RUBYDIR = /usr/local/lib/site_ruby
+RUBYLIB = -lruby ../lib/Xrubylib/libXrubylib.a
+RUBYINSTDIR = /usr/lib/ruby
+RUBYSRC = $(RUBYINSTDIR)/1.6/i386-linux
+
 /**
  ** Transport configuration:
  **	Kinput2 X Input Method Protocol handler supports
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/autogen.sh	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+xmkmf
+make Makefiles
+make depend
+echo "----------"
+echo "Execute 'make' and 'make install'."
--- a/cmd/Imakefile	Mon Mar 08 20:38:16 2010 +0900
+++ b/cmd/Imakefile	Mon Mar 08 20:38:17 2010 +0900
@@ -38,10 +38,14 @@
          XATOKLIB = ../lib/Xatoklib/libXatoklib.a
              LIBS = $(XATOKLIB) -L$(ATOKLIBDIR) $(ATOKLIB)
 #endif
+#ifdef UseRuby
+             DEFR = -DUSE_RUBY
+             LIBR = $(RUBYLIB)
+#endif
 
           DEPLIBS = $(KI2LIB) $(IMLIB) $(XSJ3CLIB) $(XATOKLIB) XawClientDepLibs
-  LOCAL_LIBRARIES = $(KI2LIB) $(IMLIB) $(LIBW) $(LIBI) $(LIBS) XawClientLibs
-          DEFINES = $(SIGNAL_DEFINES) $(DEFW) $(DEFI) $(DEFS)
+  LOCAL_LIBRARIES = $(KI2LIB) $(IMLIB) $(LIBW) $(LIBI) $(LIBS) $(LIBR) XawClientLibs
+          DEFINES = $(SIGNAL_DEFINES) $(DEFW) $(DEFI) $(DEFS) $(DEFR)
              SRCS = kinput2.c
              OBJS = kinput2.o
 
--- a/cmd/kinput2.c	Mon Mar 08 20:38:16 2010 +0900
+++ b/cmd/kinput2.c	Mon Mar 08 20:38:17 2010 +0900
@@ -38,7 +38,7 @@
 #include "XimpProto.h"
 #include "IMProto.h"
 
-#if !defined(USE_WNN) && !defined(USE_CANNA) && !defined(USE_SJ3) && !defined(USE_ATOK)
+#if !defined(USE_WNN) && !defined(USE_CANNA) && !defined(USE_SJ3) && !defined(USE_ATOK) && !defined(USE_RUBY)
 #define USE_WNN			/* default */
 #endif
 
@@ -58,6 +58,10 @@
 #include "Atok.h"
 #include "WcharDisp.h"
 #endif
+#ifdef USE_RUBY
+#include "Ruby.h"
+#include "WcharDisp.h"
+#endif
 
 #include "DebugPrint.h"
 
@@ -155,6 +159,12 @@
     {"-atokconf",    "*Atok.conf",      XrmoptionSepArg,    NULL},
     {"-atokstyle",   "*Atok.style",     XrmoptionSepArg,    NULL},
 #endif
+#ifdef USE_RUBY
+    {"-ruby",		".conversionEngine",	XrmoptionNoArg,		"ruby"},
+    {"-rubyserver",	"*Canna.cannahost",	XrmoptionSepArg,	NULL},
+    {"-rs",		"*Canna.cannahost",	XrmoptionSepArg,	NULL},
+    {"-rubyfile",	"*Canna.cannafile",	XrmoptionSepArg,	NULL},
+#endif
 };
 
 XtAppContext	apc;
@@ -392,6 +402,11 @@
 	return atokObjectClass;
     }
 #endif
+#ifdef USE_RUBY
+    if (!strcmp(appres.conversionEngine, "ruby")) {
+	return rubyObjectClass;
+    }
+#endif
 
     /* set default input object */
 #ifdef USE_ATOK
@@ -406,6 +421,9 @@
 #ifdef USE_WNN
     class = ccWnnObjectClass;
 #endif
+#ifdef USE_RUBY
+    class = rubyObjectClass;
+#endif
 
     return class;
 }
@@ -560,6 +578,11 @@
 	"-atokconf <file>",             "specify atok customize file",
 	"-atokstyle <file>",            "specify atok style file",
 #endif
+#ifdef USE_RUBY
+	"-ruby",		"use Canna (Iroha) as the conversion engine",
+	"{-rubyserver|-rs} <hostname>[:n]", "specify cannaserver host",
+	"-rubyfile <cannafile>", "specify canna customize file",
+#endif
 	"-bc",			"backward compatible mode",
 	"-font <font>",		"ASCII font to be used",
 	"-kanjifont <font>",	"KANJI font to be used",
@@ -623,6 +646,9 @@
 #ifdef USE_ATOK
     printf("[Atok] ");
 #endif
+#ifdef USE_RUBY
+    printf("[Ruby] ");
+#endif
 #ifdef DEBUG
     printf("[DEBUG] ");
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/Ruby.h	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,73 @@
+/* $Id: Ruby.h,v 1.2 2003/06/10 02:11:19 komatsu Exp $ */
+/*
+ * Copyright (c) 1990  Software Research Associates, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Software Research
+ * Associates makes no representations about the suitability of this software
+ * for any purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * Author:  Makoto Ishisone, Software Research Associates, Inc., Japan
+ */
+
+/* Copyright 1991 NEC Corporation, Tokyo, Japan.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of NEC Corporation
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.  NEC 
+ * Corporation makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * NEC CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN 
+ * NO EVENT SHALL NEC CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 
+ * OTHER TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
+ * PERFORMANCE OF THIS SOFTWARE. 
+ *
+ * Author: Akira Kon, NEC Corporation.  (kon@d1.bs2.mt.nec.co.jp)
+ */
+
+#ifndef _Ruby_h
+#define _Ruby_h
+
+#include "InputConv.h"
+
+/*
+  Ruby new resources:
+
+  name			class		type		default		access
+  ----------------------------------------------------------------------------
+  rubyhost		Rubyhost	String		*1		CG
+  rubyfile		Rubyfile	String		*2		CG
+
+  note:	*1) if not specified, use value of an environment variable "RUBYHOST"
+	*2) if not specified, use value of an environment variable "RUBYFILE"
+*/
+
+#define XtNrubyhost	"rubyhost"
+#define XtCRubyhost	"Rubyhost"
+#define XtNrubyfile	"rubyfile"
+#define XtCRubyfile	"Rubyfile"
+#define XtNsendReturnByString     "sendReturnByString"
+#define XtCSendReturnByString     "SendReturnByString"
+
+typedef struct _RubyClassRec	*RubyObjectClass;
+typedef struct _RubyRec	*RubyObject;
+
+extern WidgetClass	rubyObjectClass;
+
+#endif /* _Ruby_h */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/RubyP.h	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,111 @@
+/* $Id: RubyP.h,v 1.2 2003/06/10 02:11:19 komatsu Exp $ */
+/*
+ * Copyright (c) 1990  Software Research Associates, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Software Research
+ * Associates makes no representations about the suitability of this software
+ * for any purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * Author:  Makoto Ishisone, Software Research Associates, Inc., Japan
+ */
+
+/* Copyright 1991 NEC Corporation, Tokyo, Japan.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of NEC Corporation
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.  NEC 
+ * Corporation makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * NEC CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN 
+ * NO EVENT SHALL NEC CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 
+ * OTHER TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
+ * PERFORMANCE OF THIS SOFTWARE. 
+ *
+ * Author: Akira Kon, NEC Corporation. (kon@d1.bs2.mt.nec.co.jp)
+ */
+
+
+#ifndef _RubyP_h
+#define _RubyP_h
+
+#include "InputConvP.h"
+
+#include "WStr.h"
+#include "Ruby.h"
+
+typedef struct {
+    int foo;
+} RubyClassPart;
+
+typedef struct _RubyClassRec {
+    ObjectClassPart object_class;
+    InputConvClassPart inputConv_class;
+    RubyClassPart ruby_class;
+} RubyClassRec;
+
+#define NConvertedSegments 3
+
+typedef struct {
+  wchar *str[NConvertedSegments + 3];
+  int size[NConvertedSegments + 3];
+  int len[NConvertedSegments + 3];
+  int offset;
+  int curseg;
+  int nseg;
+  int candstat;	/* $B8uJd0lMw9T$N>uBV!#0J2<$r8+$h(B */
+  ICString ics[3];
+  wchar *gline[3];
+  int glsize[3], gllen[3];
+  int curgseg, ngseg;
+  wchar *curmode;
+  int modesize, modelen;
+} iBuf;
+
+#define RUBY_GLINE_Empty	0
+#define RUBY_GLINE_Start	1
+#define RUBY_GLINE_End		2
+#define RUBY_GLINE_Change	3
+
+typedef struct {
+    /* resources */
+    String	rubyhost;
+    String	rubyfile;
+    Boolean     sendReturnByString;
+    /* private data */
+    iBuf	*ibuf;
+    Boolean	textchanged;	/* $BJQ49%F%-%9%H$,JQ$o$C$?$+(B */
+    Boolean	selectionending;/* $BA*Br%b!<%I$r=*N;$7$h$&$H$7$F$$$k$+(B */
+    ICString	*symbollist;
+    int		numsymbols;
+    int		cursymbol;	/* $B5-9fA*Br;~!"8=:_A*Br$5$l$F$$$k5-9f(B */
+    ICString	*candlist;
+    int		candlistsize;
+    int		numcand;	/* $BA*Br%b!<%I$N;~!"8uJd?t(B */
+    int		curcand;	/* $B8uJdA*Br;~!"8=:_A*Br$5$l$F$$$k8uJd(B */
+    int		*cur_addr;	/* $B8uJdA*Br;~8uJdHV9f$rF~$l$k%"%I%l%9(B */
+    Boolean	lastTextLengthIsZero;
+} RubyPart;
+
+typedef struct _RubyRec {
+    ObjectPart  object;
+    InputConvPart inputConv;
+    RubyPart ruby;
+} RubyRec;
+
+#endif
--- a/lib/Imakefile	Mon Mar 08 20:38:16 2010 +0900
+++ b/lib/Imakefile	Mon Mar 08 20:38:17 2010 +0900
@@ -54,14 +54,21 @@
          ATOKINCS = -I$(ATOKINCDIR)
           SUBDIRS = imlib Xatoklib
 #endif
+#ifdef UseRuby
+        RUBYSRCS = Ruby.c ruby-c.c
+        RUBYOBJS = Ruby.o ruby-c.o
+        RUBYINCS = -I$(RUBYSRC)
+         SUBDIRS = imlib Xrubylib ruby
+#         SUBDIRS = imlib Xrubylib
+#endif
 
              SRCS = $(WIDGETSRCS) $(UTILSRCS) \
-                    $(WNNSRCS) $(CANNASRCS) $(SJ3SRCS) $(ATOKSRCS)
+                    $(WNNSRCS) $(CANNASRCS) $(SJ3SRCS) $(ATOKSRCS) $(RUBYSRCS)
              OBJS = $(WIDGETOBJS) $(UTILOBJS) \
-                    $(WNNOBJS) $(CANNAOBJS) $(SJ3OBJS) $(ATOKOBJS)
+                    $(WNNOBJS) $(CANNAOBJS) $(SJ3OBJS) $(ATOKOBJS) $(RUBYOBJS)
 
    LOCAL_INCLUDES = -I../include -Iimlib
-         INCLUDES = $(LOCAL_INCLUDES) $(WNNINCS) $(CANNAINCS) $(SJ3INCS) $(ATOKINCS)
+         INCLUDES = $(LOCAL_INCLUDES) $(WNNINCS) $(CANNAINCS) $(SJ3INCS) $(ATOKINCS) $(RUBYINCS)
 
           DEFINES = $(WNNDEFS) $(SJ3DEFS) $(TRANSPORTDEFS)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Prime.rb	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,303 @@
+PRIME_PATH = '/home/komatsu/src/prime'
+$LOAD_PATH.push (PRIME_PATH)
+
+require 'prime/prime'
+
+class KanjiConv < KanjiConvCore
+  attr_reader :input, :selection, :dialog
+
+  def initialize
+    super
+    @useprime = false
+#    @useprime = true
+    
+    if @useprime then
+      @prime = Prime.new
+    end
+    @input  = JTextEdit.new
+
+    @selection = Selection.new (self)
+    @dialog = Dialog.new (self)
+    @mode = ModeMaster.new (self)
+
+    @fundMode  = FundMode.new(self)
+    @inputMode = InputMode.new(self)
+    @convMode  = ConvMode.new(self)
+    @mode.set(:fund,  @fundMode)
+    @mode.set(:input, @inputMode)
+    @mode.set(:conv,  @convMode)
+    @mode.change(:fund)
+
+    puts "Initialize Done."
+  end
+
+  def reset
+    super
+    @mode.change(:fund)
+    @input.reset
+    reset_cand_list
+  end
+
+  def convert (word)
+    if @useprime then
+      cand_list = @prime.lookup_prefix(word).split("\n").map {|line|
+	line.split("\t")[1]
+      }
+    else
+      cand_list = [word, "Taiyaki", "Hiroyuki", "Komatsu", "$B4A;z(B"]
+    end
+    return cand_list[0,5]
+  end
+
+  ## inputEvent (keynum, keysym = nil, state = nil)
+  ## ReturnValue 1:Pass 0:Trap
+  def inputEvent (keynum, keysym = nil, state = nil)
+    puts "KeyNum: #{keynum}, KeySym: #{keysym}, Status: #{state}"
+
+    if keynum == 0 then
+      return 1
+    end
+    key = [keynum]
+
+    if @mode.current then
+      trap = @mode.current.call (keynum, keysym, state)
+      return ((trap == true) ? 0 : 1)
+    end
+    return 1;
+  end
+
+  def selection_fix (index)
+    fix (index)
+    @mode.change(:fund)
+  end
+
+  def fix (fixed_arg)
+    ### Must NOT chage @mode here, because exceptional case can exist.
+    super (fixed_arg)
+    @input.reset
+    reset_cand_list
+  end
+
+  def insert (keysym, modifiers)
+    puts "insert '#{keysym.chr}'"
+    @input.insert(keysym.chr)
+    set_cand_list (convert(@input.text), 0)
+  end
+end
+
+class PrimeModeCore < ModeCore
+  def initialize (parent)
+    super
+  end
+
+  private
+  def insert (keysym, modifiers)
+    @parent.insert(keysym, modifiers)
+    @parent.mode.change(:input)
+    return true
+  end
+
+  def fix (keysym, modifiers)
+    fix_internal(keysym, modifiers)
+    @parent.mode.change(:fund)
+    return true
+  end
+
+  def fix_and_insert (keysym, modifiers)
+    fix_internal (keysym, modifiers)
+    insert (keysym, modifiers)
+    return true
+  end
+
+  def cursor_right (keysym, modifiers)
+    @parent.input.cursor_right
+    return true
+  end
+  def cursor_left (keysym, modifiers)
+    @parent.input.cursor_left
+    return true
+  end
+  def cursor_beginning (keysym, modifiers)
+    @parent.input.cursor_beginning
+    return true
+  end
+  def cursor_end (keysym, modifiers)
+    @parent.input.cursor_end
+    return true
+  end
+
+  def selection_right (keysym, modifiers)
+    @parent.selection.right
+    return true
+  end
+  def selection_left (keysym, modifiers)
+    @parent.selection.left
+    return true
+  end
+  def selection_beginning (keysym, modifiers)
+    @parent.selection.line_beginning
+    return true
+  end
+  def selection_end (keysym, modifiers)
+    @parent.selection.line_end
+    return true
+  end
+  def selection_up (keysym, modifiers)
+    @parent.selection.up
+    return true
+  end
+  def selection_down (keysym, modifiers)
+    @parent.selection.down
+    return true
+  end
+end
+
+class FundMode < PrimeModeCore
+  def initialize (parent)
+    super
+    @label = '[ $B$"(B ]'
+    @trap  = false
+  end
+
+  def initialize_keys
+    (33..126).each {|char|
+      @keymap.add(char, :insert)
+    }
+  end
+
+  def on (prev_mode = nil)
+    @parent.selection.close
+    @parent.dialog.close
+  end
+end
+
+class InputMode < PrimeModeCore
+  def initialize (parent)
+    super
+    @label   = "[$BF~NO(B]"
+  end
+
+  def initialize_keys
+    (33..126).each {|char|
+      @keymap.add(char, :insert)
+    }
+    (?A..?Z).each {|char|
+      @keymap.add(char, :fix_and_insert)
+    }
+    @keymap.add(:enter, :fix)
+    @keymap.add([?m, :ctrl], :fix)
+    @keymap.add(:space, :convert)
+    @keymap.add(:backspace, :backspace)
+    @keymap.add([?h, :ctrl], :backspace)
+    @keymap.add(:delete, :delete)
+    @keymap.add([?d, :ctrl], :delete)
+    @keymap.add(:left, :cursor_left)
+    @keymap.add([?b, :ctrl], :cursor_left)
+    @keymap.add(:right, :cursor_right)
+    @keymap.add([?f, :ctrl], :cursor_right)
+    @keymap.add([?a, :ctrl], :cursor_beginning)
+    @keymap.add([?e, :ctrl], :cursor_end)
+    @keymap.add([?g, :ctrl], :cancel)
+    @keymap.add(:esc, :cancel)
+  end
+
+  def on (prev_mode = nil)
+    @parent.selection.close
+    @parent.dialog.open
+  end
+
+  def entries
+    return @parent.input.segments
+  end
+
+  private
+  def fix_internal (keysym, modifiers)
+    @parent.fix(@parent.input.text)
+  end
+
+  def backspace (keysym, modifiers)
+    @parent.input.backspace
+    if @parent.input.text.length == 0 then
+      @parent.mode.change(:fund)
+    end
+    return true
+  end
+
+  def delete (keysym, modifiers)
+    @parent.input.delete
+    if @parent.input.text.length == 0 then
+      @parent.mode.change(:fund)
+    end
+    return true
+  end
+
+  def cancel (keysym, modifiers)
+    @parent.input.reset
+    @parent.mode.change(:fund)
+    return true
+  end
+
+  def convert (keysym, modifiers)
+    if @parent.set_cand_list (@parent.convert(@parent.input.text)) then
+      @parent.set_cand_index(0)
+      @parent.mode.change(:conv)
+    end
+    return true
+  end
+end
+
+class ConvMode < PrimeModeCore
+  def initialize (parent)
+    super
+    @label  = "[$BJQ49(B]"
+  end
+
+  def initialize_keys
+    (33..126).each {|char|
+      @keymap.add(char, :fix_and_insert)
+    }
+    @keymap.add(:enter, :fix)
+    @keymap.add([?m, :ctrl], :fix)
+    @keymap.add(:space, :convert)
+#     @keymap.add(:backspace, :backspace)
+#     @keymap.add([?h, :ctrl], :backspace)
+#     @keymap.add(:delete, :delete)
+#     @keymap.add([?d, :ctrl], :delete)
+    @keymap.add(:left, :selection_left)
+    @keymap.add([?b, :ctrl], :selection_left)
+    @keymap.add(:right, :selection_right)
+    @keymap.add([?f, :ctrl], :selection_right)
+    @keymap.add(:down, :selection_down)
+    @keymap.add([?n, :ctrl], :selection_down)
+    @keymap.add(:up, :selection_up)
+    @keymap.add([?p, :ctrl], :selection_up)
+    @keymap.add([?a, :ctrl], :selection_beginning)
+    @keymap.add([?e, :ctrl], :selection_end)
+    @keymap.add([?g, :ctrl], :cancel)
+    @keymap.add(:esc, :cancel)
+  end
+
+  def on (prev_mode = nil)
+    @parent.selection.open
+    @parent.dialog.close
+  end
+
+  def entries
+    return ['', @parent.cand_list[@parent.cand_index]]
+  end
+
+  private
+  def fix_internal (keysym, modifiers)
+    @parent.fix(@parent.cand_list[@parent.cand_index])
+  end
+  
+  def cancel (keysym, modifiers)
+    @parent.mode.change(:input)
+    return true
+  end
+
+  def convert (keysym, modifiers)
+    return selection_right(keysym, modifiers)
+  end
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Ruby.c	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,947 @@
+/*
+ * Copyright (c) 1990  Software Research Associates, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Software Research
+ * Associates makes no representations about the suitability of this software
+ * for any purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * Author:  Makoto Ishisone, Software Research Associates, Inc., Japan
+ */
+
+/* Copyright 1991 NEC Corporation, Tokyo, Japan.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of NEC Corporation
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.  NEC 
+ * Corporation makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * NEC CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN 
+ * NO EVENT SHALL NEC CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 
+ * OTHER TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
+ * PERFORMANCE OF THIS SOFTWARE. 
+ *
+ * Author: Akira Kon, NEC Corporation.  (kon@d1.bs2.mt.nec.co.jp)
+ */
+
+/* Copyright 2003 Hiroyuki Komatsu <komatsu@taiyaki.org> (Ruby.c) */
+
+/* ľ¤µ¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¤È¤³¤í
+
+ ¡¦Destroy ¤¬¸Æ¤Ð¤ì¤Ê¤¤¤Î¤Ç CloseUIContext ¤Ç¤­¤Ê¤¤¡£
+ ¡¦¥â¡¼¥ÉÎΰè¤ÎÂ礭¤µ¡£(¤³¤ì¤Ï¾¤Î¥Õ¥¡¥¤¥ë¤À¤í¤¦¤Ê)
+
+ */
+
+#ifndef lint
+static char *rcsid = "$Id: Ruby.c,v 1.2 2003/06/10 02:11:23 komatsu Exp $";
+#endif
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xmu/Atoms.h>
+#define XK_KATAKANA
+#include <X11/keysym.h>
+#if XtSpecificationRelease > 4
+#include <X11/Xfuncs.h>
+#endif
+
+#include "RubyP.h"
+#include "DebugPrint.h"
+
+#define wchar_t wchar
+
+#include "ruby-c.h"
+
+static XtResource resources[] = {
+#define offset(field) XtOffset(RubyObject, ruby.field)
+    { XtNrubyhost, XtCRubyhost, XtRString, sizeof(String),
+	offset(rubyhost), XtRString, NULL },
+    { XtNrubyfile, XtCRubyfile, XtRString, sizeof(String),
+	offset(rubyfile), XtRString, NULL },
+    { XtNsendReturnByString, XtCSendReturnByString,
+	XtRBoolean, sizeof(Boolean),
+	offset(sendReturnByString), XtRBoolean, False },
+#undef offset
+};
+
+static void ClassInitialize();
+static void Initialize(), Destroy();
+static Boolean SetValues();
+static int InputEvent();
+static ICString *GetMode();
+static int CursorPos();
+static int NumSegments();
+static ICString *GetSegment();
+static int CompareSegment();
+static ICString *GetItemList();
+static int SelectItem();
+static int ConvertedString();
+static int ClearConversion();
+static int GetTriggerKeys();
+static int PreeditString();
+static int StatusString();
+
+static void convend();
+
+#if 1 /* KC_SETLISTCALLBACK */
+static void openSelection();
+#define SELECTION_SET 0 /* SelectionStart ¤ò¤·¤Æ¤âÎɤ¤¤È¸À¤¦¾ðÊó¤òÀßÄꤹ¤ë */
+#define SELECTION_DO  1 /* ¼ÂºÝ¤Ë SelectionStart ¤ò³«»Ï¤¹¤ë */
+#else /* !KC_SETLISTCALLBACK */
+#define openSelection(x, y, z)
+#endif /* !KC_SETLISTCALLBACK */
+
+static ICString *GetAuxSegments();
+
+RubyClassRec rubyClassRec = {
+  { /* object fields */
+    /* superclass		*/	(WidgetClass) &inputConvClassRec,
+    /* class_name		*/	"Ruby",
+    /* widget_size		*/	sizeof(RubyRec),
+    /* class_initialize		*/	ClassInitialize,
+    /* class_part_initialize	*/	NULL,
+    /* class_inited		*/	FALSE,
+    /* initialize		*/	Initialize,
+    /* initialize_hook		*/	NULL,
+    /* obj1			*/	NULL,
+    /* obj2			*/	NULL,
+    /* obj3			*/	0,
+    /* resources		*/	resources,
+    /* num_resources		*/	XtNumber(resources),
+    /* xrm_class		*/	NULLQUARK,
+    /* obj4			*/	FALSE,
+    /* obj5			*/	FALSE,
+    /* obj6			*/	FALSE,
+    /* obj7			*/	FALSE,
+    /* destroy			*/	Destroy,
+    /* obj8			*/	NULL,
+    /* obj9			*/	NULL,
+    /* set_values		*/	SetValues,
+    /* set_values_hook		*/	NULL,
+    /* obj10			*/	NULL,
+    /* get_values_hook		*/	NULL,
+    /* obj11			*/	NULL,
+    /* version			*/	XtVersion,
+    /* callback_private		*/	NULL,
+    /* obj12			*/	NULL,
+    /* obj13			*/	NULL,
+    /* obj14			*/	NULL,
+    /* extension		*/	NULL
+  },
+  { /* inputConv fields */
+    /* InputEvent		*/	InputEvent,
+    /* GetMode			*/	GetMode,
+    /* CursorPos		*/	CursorPos,
+    /* NumSegments		*/	NumSegments,
+    /* GetSegment		*/	GetSegment,
+    /* CompareSegment		*/	CompareSegment,
+    /* GetItemList		*/	GetItemList,
+    /* SelectItem		*/	SelectItem,
+    /* GetConvertedString	*/	ConvertedString,
+    /* ClearConversion		*/	ClearConversion,
+    /* GetAuxSegments		*/	GetAuxSegments,
+    /* SupportMultipleObjects	*/	True,
+    /* GetTriggerKeys		*/	GetTriggerKeys,
+    /* num_trigger_keys		*/	0,
+    /* trigger_keys		*/	NULL,
+    /* GetPreeditString		*/	PreeditString,
+    /* GetStatusString		*/	StatusString,
+    /* NoMoreObjects		*/	False,
+  },
+  { /* ruby fields */
+    /* foo			*/	0,
+  }
+};
+
+WidgetClass rubyObjectClass = (WidgetClass)&rubyClassRec;
+
+static void fix();
+
+static ICString *SymbolList;
+static int NumSymbols;
+
+static void addObject();
+static void deleteObject();
+
+static Display *displaybell = (Display *)0;
+
+static void rubyEUCtoICString();
+static void rubyEUCArraytoICStringArray();
+static void rubySelectionEvent();
+static void rubySelectionDisplay();
+static void rubyDialogDisplay();
+static void rubyDisplayPreEdit();
+
+typedef struct {
+  ICString *array;
+  int length;
+} ICStringArray;
+
+static ICString *ruby_tmp_seg; 
+static ICStringArray *ruby_cand_list;
+
+static void
+ClassInitialize()
+{
+  ruby_init();
+
+  ruby_tmp_seg = XtMalloc(sizeof(ICString));
+  ruby_tmp_seg->nchars = 0;
+  ruby_tmp_seg->nbytes = 0;
+  ruby_cand_list = XtMalloc(sizeof(ICStringArray));
+  ruby_cand_list->length = 0;
+  
+  ruby_eval("$LOAD_PATH.concat(eval(`ruby -e 'p $LOAD_PATH'`))");
+  ruby_eval("$LOAD_PATH.uniq!");
+
+  if (ruby_eval("ENV['KINPUT2_RUBY']") != Qnil) {
+    ruby_eval("require ENV['KINPUT2_RUBY']");
+  } else {
+    ruby_eval("require 'kinput2_default'");
+  }
+  if (ruby_eval("global_variables.member?('$kanjiConv')") == Qfalse) {
+    fprintf(stderr, "Abort: KanjiConv was not initialized.\n");
+    exit (-1);
+  }
+  ruby_eval("kanjiConv = $kanjiConv");
+  TRACE(("RubyObjectClass initialized\n"));
+}
+
+static int
+InputEvent(w, event)
+Widget w;
+XEvent *event;
+{
+    RubyObject obj = (RubyObject)w;
+    char key_buf[200];
+    KeySym keysym;
+    int len, nbytes, functionalChar;
+
+    /* KeyPress°Ê³°¤Ï¼Î¤Æ¤ë */
+    if (event->type != KeyPress /*&& event->type != KeyRelease*/) return 0;
+
+    /* ¼è¤ê¤¢¤¨¤ºÊ¸»ú¤Ëľ¤·¤Æ¤·¤Þ¤¦ */
+    key_buf[0] = '\0';
+    key_buf[1] = '\0';
+    key_buf[2] = '\0';
+    nbytes = XLookupString(event, key_buf, 20, &keysym, NULL);
+
+    if (keysym == XK_space && (event->xkey.state & ShiftMask)) {
+      convend(obj);
+      return 0;
+    }
+
+    /* ¥Ù¥ë¤òÌĤ餹¥Ç¥£¥¹¥×¥ì¥¤¤ÎÀßÄê */
+    displaybell = XtDisplayOfObject((Widget)obj);
+
+    /* ¤«¤Ê´Á»úÊÑ´¹¤¹¤ë */
+    {
+      VALUE pass;
+      printf ("key_buf: `%d'\n", key_buf[0]);
+      printf ("strlen(key_buf): `%d'\n", strlen(key_buf));
+      printf ("nbytes: `%d'\n", nbytes);
+      pass = ruby_evalf ("kanjiConv.inputEvent(%d, %d, %d)",
+			 key_buf[0], (int)keysym, (int)(event->xkey.state));
+      printf ("Input: done\n");
+
+      rubyDisplayPreEdit(obj);
+
+      return NUM2INT(pass); /* 1: pass the key / 0: trap the key */
+    }
+}
+
+
+static void
+rubyDialogDisplay(obj)
+RubyObject obj;
+{
+  ICAuxControlArg arg;
+
+  /* I'm not sure about Aux. */
+  if (ruby_eval("kanjiConv.dialog.visible") == Qfalse) {
+    if (ruby_eval("kanjiConv.dialog.call_open") == Qtrue &&
+	ruby_eval ("kanjiConv.dialog.text.length > 0") == Qtrue) {
+      printf ("Dialog: open\n");
+      arg.command = ICAuxStart;
+      XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
+			 (XtPointer)&arg);
+      ruby_eval("kanjiConv.dialog.open_end");
+    }
+  } else { /* value_dialog_visible == true */
+    if (ruby_eval("kanjiConv.dialog.call_close") == Qtrue) {
+      printf ("Dialog: close\n");
+      arg.command = ICAuxEnd;
+      XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
+			 (XtPointer)&arg);
+      ruby_eval("kanjiConv.dialog.close_end");
+      printf ("Dialog: close...done\n");
+    } else {
+      arg.command = ICAuxChange;
+      XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
+			 (XtPointer)&arg);
+    }
+  }
+}
+
+static void
+rubySelectionEvent(obj)
+RubyObject obj;
+{
+  /*** Right ***/
+  if (ruby_eval("kanjiConv.selection.call_right") == Qtrue) {
+    moveSelection(obj, ICMoveRight);
+    ruby_eval("kanjiConv.selection.right_end");
+  }
+    
+  /*** Left ***/
+  if (ruby_eval("kanjiConv.selection.call_left") == Qtrue) {
+    moveSelection(obj, ICMoveLeft);
+    ruby_eval("kanjiConv.selection.left_end");
+  }
+
+  /*** Down ***/
+  if (ruby_eval("kanjiConv.selection.call_down") == Qtrue) {
+    moveSelection(obj, ICMoveDown);
+    ruby_eval("kanjiConv.selection.down_end");
+  }
+
+  /*** Up ***/
+  if (ruby_eval("kanjiConv.selection.call_up") == Qtrue) {
+    moveSelection(obj, ICMoveUp);
+    ruby_eval("kanjiConv.selection.up_end");
+  }
+
+  /*** Beginning Line ***/
+  if (ruby_eval("kanjiConv.selection.call_line_beginning") == Qtrue) {
+    moveSelection(obj, ICMoveLeftMost);
+    ruby_eval("kanjiConv.selection.line_beginning_end");
+  }
+
+  /*** End Line ***/
+  if (ruby_eval("kanjiConv.selection.call_line_end") == Qtrue) {
+    moveSelection(obj, ICMoveRightMost);
+    ruby_eval("kanjiConv.selection.line_end_end");
+  }
+
+  /*** Get Index ***/
+  {
+    ICSelectionControlArg arg;
+    arg.command = ICSelectionGet;
+    arg.u.current_item = -1;
+
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		       (XtPointer)&arg);
+
+    if (arg.u.current_item >= 0) {
+      ruby_evalf ("kanjiConv.set_cand_index (%d)", arg.u.current_item);
+    }
+  }
+}
+
+static void
+moveSelection(obj, dir)
+RubyObject obj;
+int dir;
+{
+  ICSelectionControlArg arg;
+
+  arg.command = ICSelectionMove;
+  arg.u.dir = dir;
+  XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		     (XtPointer)&arg);
+}
+
+static void
+rubySelectionDisplay(obj)
+RubyObject obj;
+{
+  ICSelectionControlArg arg;
+
+  if (ruby_eval("kanjiConv.selection.call_open") == Qtrue) {
+    printf ("Selection: open\n");
+    arg.command = ICSelectionStart;
+    arg.u.selection_kind = ICSelectionCandidates;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		       (XtPointer)&arg);
+
+    /* set current item */
+    arg.command = ICSelectionSet;
+    arg.u.current_item = 0; /* INDEX of ITEM */
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		       (XtPointer)&arg);
+
+    ruby_eval("kanjiConv.selection.open_end");
+  } else if (ruby_eval("kanjiConv.selection.call_close") == Qtrue) {
+    printf ("Selection: close\n");
+    arg.command = ICSelectionEnd;
+    arg.u.current_item = -1;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		       (XtPointer)&arg);
+    ruby_eval("kanjiConv.selection.close_end");
+  }
+}
+
+
+static void
+rubyDisplayPreEdit(obj)
+RubyObject obj;
+{
+    Widget w = (Widget)obj;
+    
+    if (ruby_eval("kanjiConv.call_fix") == Qtrue) {
+      fix(obj);
+    }
+
+    /* ÆþÎϥ⡼¥É¤ò¥Á¥§¥Ã¥¯¤¹¤ë */
+/* #if 0 */
+/*     if (ks->info & KanjiModeInfo) { */
+/*       printf("modechangecallback\n"); */
+    XtCallCallbackList(w, obj->inputConv.modechangecallback,
+		       (XtPointer)NULL);
+/*     } */
+/* #endif */
+
+    rubyDialogDisplay(obj);
+    rubySelectionEvent(obj);
+    rubySelectionDisplay(obj);
+
+    XtCallCallbackList(w, obj->inputConv.textchangecallback,
+		       (XtPointer)NULL);
+}
+
+
+
+
+static ICString *
+GetMode(w)
+Widget w;
+{
+    rubyEUCtoICString (ruby_eval ("kanjiConv.modeline"), ruby_tmp_seg);
+    ruby_tmp_seg->attr = ICAttrNormalString;
+    return ruby_tmp_seg;
+}
+
+static int
+CursorPos(w, nsegp, ncharp)
+Widget w;
+Cardinal *nsegp;
+Cardinal *ncharp;
+{
+    /*
+    return value : =0 corsor ON  /    =1 OFF
+    nseg: >0 segment index / =0 no segment
+    nchar: number of chars; '¥Æs' == 2
+    */
+    *ncharp = NUM2INT(ruby_eval("kanjiConv.input.cursor"));
+    *nsegp  = 0;
+
+/*     printf ("CursorPos: nseg=%d, nchar=%d\n", (int)*nsegp, (int)*ncharp); */
+
+    return (*ncharp == 0) ? 1: 0;
+}
+
+static int
+NumSegments(w)
+Widget w;
+{
+    int num;
+    printf ("NumSegments\n");
+    num = NUM2INT(ruby_eval("kanjiConv.segment_length"));
+/*     printf ("NumSegments: num=%d\n", num); */
+    return num;
+}
+
+static ICString *
+GetSegment(w, n)
+Widget w;
+Cardinal n;
+{
+    RubyObject obj = (RubyObject)w;
+    static ICString seg;
+
+    printf("GetSegment\n");
+
+    rubyEUCtoICString (ruby_evalf ("kanjiConv.segment_word(%d)", n),
+		       ruby_tmp_seg);
+    if (ruby_evalf("kanjiConv.segment_status(%d) == :highlight", n) == Qtrue) {
+      ruby_tmp_seg->attr = ICAttrConverted | ICAttrCurrentSegment;
+    } else {
+      ruby_tmp_seg->attr = ICAttrNotConverted;
+    }
+    /* ICAttrConverted | ICAttrCurrentSegment : Inversion. */
+    /* |= ICAttrChanged : Non-Underline. */
+    return ruby_tmp_seg;
+}
+
+/* ARGSUSED */
+static int
+CompareSegment(w, seg1, seg2, n)
+Widget w;
+ICString *seg1;
+ICString *seg2;
+Cardinal *n;
+{
+    wchar *p, *q;
+    int len, nsame;
+    int result = 0;
+
+    printf("CompareSegment\n");
+
+    if (seg1->attr != seg2->attr) result |= ICAttrChanged;
+
+    len = seg1->nchars > seg2->nchars ? seg2->nchars : seg1->nchars;
+    nsame = 0;
+    p = (wchar *)seg1->data;
+    q = (wchar *)seg2->data;
+    while (nsame < len && *p++ == *q++) nsame++;
+
+    if (nsame != len || len != seg1->nchars || len != seg2->nchars)
+	result |= ICStringChanged;
+
+    if (n) *n = nsame;
+
+    return result;
+}
+
+static ICString *
+GetItemList(w, n)
+Widget w;
+Cardinal *n;
+{
+    RubyObject obj = (RubyObject)w;
+
+    printf("GetItemList\n");
+    rubyEUCArraytoICStringArray(ruby_eval("kanjiConv.cand_list"),
+				ruby_cand_list);
+    *n = ruby_cand_list->length;
+    return ruby_cand_list->array;
+}
+
+static int
+SelectItem(w, n)
+Widget w;
+int n;
+{
+
+  RubyObject obj = (RubyObject)w;
+  printf ("selectItem\n");
+  ruby_evalf("kanjiConv.selection_fix (%d)", n);
+  /* FIXME: Create new fix function in the feature. */
+  fix (obj);
+  XtCallCallbackList(w, obj->inputConv.textchangecallback,
+		     (XtPointer)NULL);
+  return 0;
+}
+
+static int
+ConvertedString(w, encoding, format, length, string)
+Widget w;
+Atom *encoding;
+int *format;
+int *length;
+XtPointer *string;
+{
+    RubyObject obj = (RubyObject)w;
+    wchar *wbuf, *wp;
+    int len, wlen;
+    extern int convJWStoCT();
+
+    /* ¥á¥â¥ê¤Î²òÊü¤Ï¼«Æ°Åª¤Ë¹Ô¤ï¤ì¤ë. str ¤òľÀܽñ¤­´¹¤¨¤Æ¤Ï¤¤¤±¤Ê¤¤. */
+    unsigned char *str = STR2CSTR(ruby_eval("kanjiConv.value_fixed"));
+
+    printf("ConvertedString\n");
+
+    wbuf = XtMalloc((strlen(str) + 1) * sizeof(wchar));
+    euc2wcs(str, strlen(str), wbuf);
+    wlen = wstrlen(wbuf);
+
+    /*
+     * Ruby ¥ª¥Ö¥¸¥§¥¯¥È¤Ï COMPOUND_TEXT ¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤·¤«¥µ¥Ý¡¼¥È¤·¤Ê¤¤
+     * COMPOUND_TEXT ¤ËÊÑ´¹¤¹¤ë
+     */
+    *encoding = XA_COMPOUND_TEXT(XtDisplayOfObject((Widget)obj));
+    *format = 8;
+
+    /* COMPOUND_TEXT ¤Ï \r ¤¬Á÷¤ì¤Ê¤¤¤Î¤Ç \n ¤ËÊÑ´¹¤·¤Æ¤ª¤¯ */
+    for (wp = wbuf; *wp != 0; wp++) {
+	if (*wp == '\r') *wp = '\n';
+    }
+
+    *length = len = convJWStoCT(wbuf, (unsigned char *)NULL, 0);
+    *string = XtMalloc(len + 1);
+    (void)convJWStoCT(wbuf, (unsigned char *)*string, 0);
+
+    XtFree(wbuf);
+
+    return 0;
+}
+
+static int
+ClearConversion(w)
+Widget w;
+{
+  ruby_eval ("kanjiConv.clear");
+  return 0;
+}
+
+static ICString *
+GetAuxSegments(w, n, ns, nc)
+Widget w;
+Cardinal *n, *ns, *nc;
+{
+  /* I'm not sure about this function's purpose. */
+  /* n  => ngseg ; number of segments (1 <= n <= 3). */
+  /* ns => nseg  ; index of reversed segment (0 or 1). */
+  /* nc => nchar ; length of current segment??? */ 
+  printf ("GetAuxSegments\n");
+
+  if ((ruby_eval ("kanjiConv.dialog.visible") == Qtrue ||
+       ruby_eval ("kanjiConv.dialog.call_open") == Qtrue) &&
+      ruby_eval ("kanjiConv.dialog.text.length > 0") == Qtrue) {
+    if (n) {
+      *n = 1;
+    }
+
+    if (ns) {
+      *ns = 0;
+    }
+
+    rubyEUCtoICString (ruby_eval ("kanjiConv.dialog.text"),
+		       ruby_tmp_seg);
+    ruby_tmp_seg->attr = ICAttrConverted;
+
+    if (nc) {
+      *nc = ruby_tmp_seg->nchars;
+    }
+
+    return ruby_tmp_seg;
+  } else {
+    if (n) {
+      *n = 0;
+    }
+    if (ns) {
+      *ns = 0;
+    }
+    if (nc) {
+      *nc = 0;
+    }
+    return NULL;
+  }
+}
+
+/* ARGSUSED */
+static void
+Initialize(req, new, args, num_args)
+Widget req;
+Widget new;
+ArgList args;
+Cardinal *num_args;
+{
+    RubyObject obj = (RubyObject)new;
+
+    obj->ruby.selectionending = False;
+    obj->ruby.textchanged = False;
+    obj->ruby.symbollist = SymbolList;
+    obj->ruby.numsymbols = NumSymbols;
+    obj->ruby.cursymbol = 0;
+    obj->ruby.candlist = NULL;
+    obj->ruby.candlistsize = 0;
+    obj->ruby.numcand = 0;
+    obj->ruby.lastTextLengthIsZero = False;
+      
+    addObject(obj);
+}
+
+static int
+bell()
+{
+  if (displaybell) {
+    XBell(displaybell, 0);
+  }
+  return 0;
+}
+
+static int nRubyContexts = 0;
+
+static void
+Destroy(w)
+Widget w;
+{
+    RubyObject obj = (RubyObject)w;
+    wchar buf[512];
+    int i;
+    
+    if (obj->ruby.candlist) {
+      for (i = 0 ; i < obj->ruby.candlistsize ; i++) {
+	if ((obj->ruby.candlist + i)->data) {
+	  XtFree((obj->ruby.candlist + i)->data);
+	}
+      }
+
+      XtFree((char *)obj->ruby.candlist);
+    }
+
+    /* Ruby ÍѽªÎ»½èÍý¤ò¤³¤³¤Ë½ñ¤¯ */
+
+    deleteObject(obj);
+}
+
+static Boolean
+SetValues(cur, req, wid, args, num_args)
+Widget cur;
+Widget req;
+Widget wid;
+ArgList args;
+Cardinal *num_args;
+/* ARGSUSED */
+{
+    RubyObject old = (RubyObject)cur;
+    RubyObject new = (RubyObject)wid;
+
+    return False;	     
+}
+
+static void
+fix(obj)
+RubyObject obj;
+{
+    /* ³ÎÄê¤Î½èÍý */
+    XtCallCallbackList((Widget)obj, obj->inputConv.fixcallback,
+		       (XtPointer)NULL);
+    ruby_eval("kanjiConv.fix_end");
+}
+
+static void
+convend(obj)
+RubyObject obj;
+{
+    XtCallCallbackList((Widget)obj, obj->inputConv.endcallback,
+		       (XtPointer)NULL);
+    ruby_eval("kanjiConv.reset");
+}
+
+/*
+ * keeping list of objects
+ */
+typedef struct _oblist_ {
+    RubyObject obj;
+    struct _oblist_ *next;
+} ObjRec;
+
+static ObjRec *ObjList = NULL;
+
+static void
+addObject(obj)
+RubyObject obj;
+{
+    ObjRec *objp = XtNew(ObjRec);
+
+    objp->obj = obj;
+    objp->next = ObjList;
+    ObjList = objp;
+}
+
+static void
+deleteObject(obj)
+RubyObject obj;
+{
+    ObjRec *objp, *objp0;
+
+    for (objp0 = NULL, objp = ObjList;
+	 objp != NULL;
+	 objp0 = objp, objp = objp->next) {
+	if (objp->obj == obj) {
+	    if (objp0 == NULL) {
+		ObjList = objp->next;
+	    } else {
+		objp0->next = objp->next;
+	    }
+	    XtFree((char *)objp);
+	    return;
+	}
+    }
+}
+
+/* ARGSUSED */
+static int
+GetTriggerKeys(w, keys_return)
+Widget w;
+ICTriggerKey **keys_return;
+{
+  /* ²¿¤ò¤¹¤ë´Ø¿ô¤Ê¤Î¤«ÉÔÌÀ (komatsu) */
+
+  *keys_return = NULL;
+  return 0;
+}
+
+/* ARGSUSED */
+
+
+/*
+ * int ICGetPreeditString(Widget object, int segn, int offset,
+ *                        Atom *encoding, int *format,
+ *                        int *length, XtPointer *string)
+ *      ÊÑ´¹ÅÓÃæ¤Î segn ÈÖÌܤΠ¥»¥°¥á¥ó¥È¤Î offset ʸ»ú¤«¤é¤Î¥Æ¥­¥¹¥È¤ò
+ *      string ¤ËÊÖ¤¹
+ *      encoding ¤Ë¤Ï¡¢¥Æ¥­¥¹¥È¤Î¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤ò»ØÄꤷ¤Æ¤ª¤¯
+ *      ¤¿¤À¤·¤³¤ì¤Ïñ¤Ê¤ë¥ê¥¯¥¨¥¹¥È¤Ç¤¢¤Ã¤Æ¡¢ÊÑ´¹¥ª¥Ö¥¸¥§¥¯¥È¤Ï
+ *      Ê̤Υ¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤ÇÊÖ¤·¤Æ¤â¤è¤¤
+ *      encoding ¤Ë¤Ï¼ÂºÝ¤Î¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤¬ÊÖ¤µ¤ì¤ë
+ *      ÊÑ´¹¥ª¥Ö¥¸¥§¥¯¥È¤Ï¾¯¤Ê¤¯¤È¤â COMPOUND_TEXT ¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤Ï
+ *      ¥µ¥Ý¡¼¥È¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤
+ *      format ¤Ë¤Ï 8/16/32 ¤Î¤¤¤º¤ì¤«¡¢length ¤Ï string ¤Î¥¨¥ì¥á¥ó¥È¿ô¤¬
+ *      ¤½¤ì¤¾¤ìÊÖ¤µ¤ì¤ë
+ *      ¥Æ¥­¥¹¥È¤ÎÎΰè¤Ï malloc ¤µ¤ì¤Æ¤¤¤ë¤Î¤Ç¤³¤Î´Ø¿ô¤ò¸Æ¤ó¤À¦¤Ç
+ *      free ¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤
+ *      ÊÑ´¹¥Æ¥­¥¹¥È¤¬¤Ê¤¤»þ¤ä¥¨¥é¡¼¤Î¾ì¹ç¤Ë¤Ï -1¡¢¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤¬
+ *      ´Ø¿ô¤ÎÃͤȤ·¤ÆÊÖ¤µ¤ì¤ë
+ */
+/* ¤Þ¤À, ̤¸¡Æ¤ (komatsu) */
+static int
+PreeditString(w, segn, offset, encoding, format, length, string)
+Widget w;
+int segn;
+int offset;
+Atom *encoding;
+int *format;
+int *length;
+XtPointer *string;
+{
+    RubyObject obj = (RubyObject)w;
+
+    return -1;
+}
+
+/* ARGSUSED */
+static int
+StatusString(w, encoding, format, length, string, nchars)
+Widget w;
+Atom *encoding;
+int *format;
+int *length;
+XtPointer *string;
+int *nchars;
+{
+    ICString *seg;
+    wchar *wbuf, *wp;
+    int len, wlen;
+    extern int convJWStoCT();
+
+    printf("StatusString\n");
+
+    seg = GetMode(w);
+    if (seg == NULL) {
+	*length = *nchars = 0;
+	return -1;
+    }
+
+    wlen = seg->nchars;
+    if (wlen <= 0) {
+	*length = *nchars = 0;
+	return -1;
+    }
+
+    /*
+     * data ¤ËÆþ¤Ã¤Æ¤¤¤ëÊÑ´¹¥Æ¥­¥¹¥È¤Ï null ¥¿¡¼¥ß¥Í¡¼¥È¤µ¤ì¤Æ¤¤¤Ê¤¤¤«¤â
+     * ¤·¤ì¤Ê¤¤¤Î¤Ç¡¢¤Þ¤º¥³¥Ô¡¼¤·¤Æ null ¥¿¡¼¥ß¥Í¡¼¥È¤¹¤ë
+     */
+    wbuf = (wchar *)XtMalloc((wlen + 1) * sizeof(wchar));
+    (void)bcopy(seg->data, (char *)wbuf, sizeof(wchar) * wlen);
+    wbuf[wlen] = 0;
+
+    /*
+     * Ruby ¥ª¥Ö¥¸¥§¥¯¥È¤Ï COMPOUND_TEXT ¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤·¤«¥µ¥Ý¡¼¥È¤·¤Ê¤¤
+     * COMPOUND_TEXT ¤ËÊÑ´¹¤¹¤ë
+     */
+    *encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w));
+    *format = 8;
+
+    /* COMPOUND_TEXT ¤Ï \r ¤¬Á÷¤ì¤Ê¤¤¤Î¤Ç \n ¤ËÊÑ´¹¤·¤Æ¤ª¤¯ */
+    for (wp = wbuf; *wp != 0; wp++) {
+	if (*wp == '\r') *wp = '\n';
+    }
+
+    *length = len = convJWStoCT(wbuf, (unsigned char *)NULL, 0);
+    *string = XtMalloc(len + 1);
+    (void)convJWStoCT(wbuf, (unsigned char *)*string, 0);
+    *nchars = seg->nchars;
+
+    /* wbuf ¤ò free ¤·¤Æ¤ª¤¯ */
+    XtFree((char *)wbuf);
+
+    return 0;
+}
+
+/***
+ic_str->nbytes ¤¬ 0 ¤Î¾ì¹ç ic_str->data ¤Ï¼«Æ°Åª¤Ë³ÎÊÝ (XtMalloc) ¤µ¤ì¤ë.
+ 0 °Ê³°¤Î¾ì¹ç ic_str->data ¤Ï (XtRealloc) ¤µ¤ì¤ë.
+ */
+static void
+rubyEUCtoICString(ruby_str, ic_str)
+VALUE ruby_str;
+ICString *ic_str;
+{
+  unsigned char *euc_str;
+  int euc_len;
+  wchar *wc_str;
+  
+/*   printf("String_Len: %d\n", RSTRING(ruby_str)->len); */
+
+  euc_str = STR2CSTR(ruby_str);
+  euc_len = strlen(euc_str);
+
+  if (ic_str->nbytes == 0) {
+    wc_str = (wchar *)XtMalloc((euc_len + 1) * sizeof(wchar));
+  } else {
+    wc_str = (wchar *)XtRealloc(ic_str->data, (euc_len + 1) * sizeof(wchar));
+  }
+  euc2wcs(euc_str, euc_len, wc_str);
+
+  ic_str->data   = (char *)wc_str;
+  ic_str->nchars = wstrlen(wc_str);
+  ic_str->nbytes = (euc_len + 1) * sizeof(wchar);
+  ic_str->attr   = ICAttrNotConverted;
+}
+
+static void
+rubyEUCArraytoICStringArray(ruby_str_ary, ic_str_ary)
+VALUE ruby_str_ary;
+ICStringArray *ic_str_ary;
+{
+  VALUE ruby_str;
+  int i, array_length;
+  ICString ic_str;
+
+  array_length = RARRAY(ruby_str_ary)->len;
+  if ((ic_str_ary->length) < array_length) {
+    ic_str_ary->array = (ICString *)XtRealloc((char *)ic_str_ary->array,
+					      array_length * sizeof(ICString));
+    for (i = ic_str_ary->length; i < array_length; i++) {
+/*       ic_str_ary->array[i] = (ICString *)XtMalloc(1 * sizeof(ICString)); */
+      ic_str_ary->array[i].nbytes = 0;
+    }
+  }
+  ic_str_ary->length = array_length;
+
+/*   printf("array_length: %d\n", array_length); */
+
+  for (i = 0; i < array_length; i++) {
+    rubyEUCtoICString(rb_ary_entry(ruby_str_ary, i), &(ic_str_ary->array[i]));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Ruby.rb	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,444 @@
+$LOAD_PATH.push(ENV['KINPUT2_RUBY'])
+
+$KCODE = 'e'
+require "jcode"
+require "kconv"
+require 'suikyo/suikyo'
+
+class TextEdit
+  attr_reader :cursor
+  def initialize (text = "", cursor = 0)
+    set (text, cursor)
+  end
+
+  def set (data, cursor = 0)
+    @data   = data
+    @cursor = cursor
+  end
+
+  def text
+    return @data
+  end
+
+  def reset
+    set ("", 0)
+  end
+
+  def insert (string)
+    @data    = @data[0,@cursor] + string + @data[@cursor..-1]
+    @cursor += string.length;
+  end
+
+  def delete
+    if (@cursor < @data.length) then
+      @data = @data[0,@cursor] + @data[(@cursor + 1)..-1]
+    end
+  end
+
+  def backspace
+    if (@cursor > 0) then
+      @data = @data[0,(@cursor - 1)] + @data[@cursor..-1]
+      @cursor -= 1
+    end
+  end
+
+  def cursor_left
+    if (@cursor > 0) then
+      @cursor -= 1
+    end
+  end
+
+  def cursor_right
+    if (@cursor < @data.length) then
+      @cursor += 1
+    end
+  end
+
+  def cursor_beginning
+    @cursor = 0
+  end
+
+  def cursor_end
+    @cursor = @data.length
+  end
+
+  def segments
+    # [text before the cursor, text on the cursor, text after the cursor]
+    return [@data[0,@cursor], @data[@cursor,1], @data[(@cursor + 1)..-1]]
+  end
+end
+
+class JTextEdit < TextEdit
+  def initialize (text = "", cursor = 0)
+    super
+    @suikyo = Suikyo.new
+    @suikyo.table.loadfile("romaji-kana")
+  end
+
+  def text
+    if @cursor == @data.length then
+      return @suikyo.convert (@data)
+    else
+      return super
+    end
+  end
+
+  def segments
+    if @cursor == @data.length then
+      return [@suikyo.convert (@data), '', '']
+    else
+      return super
+    end
+  end
+end
+
+class Window 
+  attr_reader :call_open, :call_close, :visible
+
+  def initialize (parent)
+    @parent = parent
+    @visible = false
+  end
+
+  def open
+    @call_open = true unless @visible
+  end
+  def open_end
+    @call_open = false
+    @visible = true
+  end
+
+  def close
+    @call_close = true if @visible
+  end
+  def close_end
+    @call_close = false
+    @visible = false
+  end
+end
+
+class Dialog < Window
+  def text
+    @parent.cand_list.join(" ")
+  end
+end
+
+class Selection < Window
+  attr_reader :call_right, :call_left, :call_line_beginning, :call_line_end,
+    :call_up, :call_down
+
+  def right
+    @call_right = true
+  end
+  def right_end
+    @call_right = false
+  end
+
+  def left
+    @call_left = true
+  end
+  def left_end
+    @call_left = false
+  end
+
+  def line_beginning
+    @call_line_beginning = true
+  end
+  def line_beginning_end
+    @call_line_beginning = false
+  end
+
+  def line_end
+    @call_line_end = true
+  end
+  def line_end_end
+    @call_line_end = false
+  end
+
+  def up
+    @call_up = true
+  end
+  def up_end
+    @call_up = false
+  end
+
+  def down
+    @call_down = true
+  end
+  def down_end
+    @call_down = false
+  end
+end
+
+class KeyMap
+  @@keysym = {
+    :enter => 65293,
+    :space => 32,
+    :tab => 65289,
+    :delete => 65535,
+    :insert => 65379,
+    :home => 65360,
+    :end => 65367,
+    :page_up => 65365,
+    :page_down => 65366,
+    :esc => 65307,
+    :f1 => 65470,
+    :f2 => 65471,
+    :f3 => 65472,
+    :f4 => 65473,
+    :f5 => 65474,
+    :f6 => 65475,
+    :f7 => 65476,
+    :f8 => 65477,
+    :f9 => 65478,
+    :f10 => 65479,
+    :f11 => 65480,
+    :f12 => 65481,
+    :backspace => 65288,
+    :muhenkan => 65314,
+    :henkan => 65315,
+    :hankaku_zenkaku => 65322,
+    :katakana_hiragana => 65319,
+    :up => 65362,
+    :down => 65364,
+    :right => 65363,
+    :left => 65361,
+    :ctrl_l => 65507,
+    :ctrl_r => 65508,
+    :alt_l => 65513,
+    :alt_r => 65514,
+    :shift_l => 65505,
+    :shift_r => 65506,
+  }
+
+#   @@enter = [13, 65293, 0]
+#   @@ctrl_a = [1,  97,  4];  @@alt_a = [97,  97,  8]
+#   @@ctrl_b = [2,  98,  4];  @@alt_b = [98,  98,  8]
+#   @@ctrl_c = [3,  99,  4];  @@alt_c = [99,  99,  8]
+#   @@ctrl_d = [4,  100, 4];  @@alt_d = [100, 100, 8]
+#   @@ctrl_e = [5,  101, 4];  @@alt_e = [101, 101, 8]
+#   @@ctrl_f = [6,  102, 4];  @@alt_f = [102, 102, 8]
+#   @@ctrl_g = [7,  103, 4];  @@alt_g = [103, 103, 8]
+#   @@ctrl_h = [8,  104, 4];  @@alt_h = [104, 104, 8]
+#   @@ctrl_i = [9,  105, 4];  @@alt_i = [105, 105, 8]
+#   @@ctrl_j = [10, 106, 4];  @@alt_j = [106, 106, 8]
+#   @@ctrl_k = [11, 107, 4];  @@alt_k = [107, 107, 8]
+#   @@ctrl_l = [12, 108, 4];  @@alt_l = [108, 108, 8]
+#   @@ctrl_m = [13, 109, 4];  @@alt_m = [109, 109, 8]
+#   @@ctrl_n = [14, 110, 4];  @@alt_n = [110, 110, 8]
+#   @@ctrl_o = [15, 111, 4];  @@alt_o = [111, 111, 8]
+#   @@ctrl_p = [16, 112, 4];  @@alt_p = [112, 112, 8]
+#   @@ctrl_q = [17, 113, 4];  @@alt_q = [113, 113, 8]
+#   @@ctrl_r = [18, 114, 4];  @@alt_r = [114, 114, 8]
+#   @@ctrl_s = [19, 115, 4];  @@alt_s = [115, 115, 8]
+#   @@ctrl_t = [20, 116, 4];  @@alt_t = [116, 116, 8]
+#   @@ctrl_u = [21, 117, 4];  @@alt_u = [117, 117, 8]
+#   @@ctrl_v = [22, 118, 4];  @@alt_v = [118, 118, 8]
+#   @@ctrl_w = [23, 119, 4];  @@alt_w = [119, 119, 8]
+#   @@ctrl_x = [24, 120, 4];  @@alt_x = [120, 120, 8]
+#   @@ctrl_y = [25, 121, 4];  @@alt_y = [121, 121, 8]
+#   @@ctrl_z = [26, 122, 4];  @@alt_z = [122, 122, 8]
+
+  @@modifier = { :shift => 1, :ctrl => 4, :alt => 8 }
+
+  def initialize
+    @keymap = Hash.new
+  end
+
+  def key (stroke)
+    modifiers = 0
+    if stroke.kind_of?(Array) then
+      main_key = stroke[0]
+      stroke[1..-1].each {|modifier|
+	modifiers |=
+	  (modifier.kind_of?(Symbol) ? @@modifier[modifier] : modifier)
+      }
+    else
+      main_key = stroke
+    end
+    if main_key.kind_of?(Symbol) then
+      main_key = @@keysym[main_key]
+    end
+    return [main_key, modifiers]
+  end
+
+  def ignore_shift (key)
+    (main_key, modifiers) = key
+    return [main_key, (modifiers & ~@@modifier[:shift])]
+  end
+
+  def add (stroke, command)
+    @keymap[key(stroke)] = command
+  end
+
+  def del (stroke)
+    @keymap.delete(key(stroke))
+  end
+
+  def command (stroke)
+    return @keymap[key(stroke)] || @keymap[ignore_shift(key(stroke))]
+  end
+end
+
+
+class ModeCore
+  attr_accessor :trap
+  attr_reader :label, :keymap
+  def initialize (parent)
+    @parent = parent
+    @label  = ""
+    @keymap = KeyMap.new
+    initialize_keys
+    @trap   = true
+  end
+
+  def on (prev_mode = nil)
+  end
+
+  def off (next_mode = nil)
+  end
+
+  def entries
+    return []
+  end
+
+  def call (char, keysym, modifiers)
+    command = @keymap.command([keysym, modifiers])
+    if command then
+      return send(command, keysym, modifiers)
+    else
+      return @trap
+    end
+  end
+end
+
+class ModeMaster
+  attr_reader :current_name
+
+  def initialize (parent, mode = :fund)
+    @parent = parent
+    @mode = Hash.new
+    @current_name = nil
+  end
+
+  def set (name, mode)
+    @mode[name] = mode
+    unless @current then
+      @current_name = name
+    end
+  end
+
+  def current
+    return @mode[@current_name]
+  end
+
+  def change (name)
+    if @mode.key?(name) then
+      @current_name = name
+      current.on
+      return true
+    else
+      return false
+    end
+  end
+
+  def label (name = @current_name)
+    if name then
+      mode = @mode[name]
+    else
+      mode = current
+    end
+
+    if mode then
+      return mode.label.toeuc
+    else
+      return "NOMODE"
+    end
+  end
+end
+
+class KanjiConvCore
+  attr_reader :cand_list, :cand_index,
+    :value_fixed, :call_fix, :mode
+
+  def initialize
+    @textEdit = TextEdit.new
+    @mode = ModeMaster.new (self)
+    clear
+  end
+
+  def reset
+    clear
+  end
+
+  def clear
+    @cand_list = []
+    @cand_index = 0
+
+    @call_fix = false
+    @value_fixed = ""
+  end
+
+  ## inputEvent (keynum, keysym = nil, state = nil)
+  ## ReturnValue 1:Pass 0:Trap
+  def inputEvent (keynum, keysym = nil, state = nil)
+    return 1
+  end
+
+  def fix (fixed_arg)
+    # fixed_arg is a string or an index number of cand_list.
+    @call_fix = true
+    if fixed_arg.kind_of?(Integer) then
+      word = @cand_list[fixed_arg]
+    else
+      word = fixed_arg
+    end
+    @value_fixed = word
+  end
+  def fix_end
+    @call_fix = false
+    @value_fixed = ""
+  end
+
+  def modeline
+    return @mode.label
+  end
+
+  def set_cand_list (list, index = nil)
+    if (list.is_a?(Array) && list.length > 0) then
+      @cand_list  = list.map {|cand| cand.toeuc}
+      @cand_index = index if index
+      return true
+    else
+      reset_cand_list
+      return false
+    end
+  end
+  def set_cand_index (index)
+    puts "<<set_cand_index>> #{index}"
+    @cand_index = index
+  end
+  def reset_cand_list
+    @cand_list  = []
+    @cand_index = 0
+  end
+
+  def segment_length
+    segments = (@mode.current.entries - [''])
+    return segments.length
+  end
+  def segment_word (n)
+    segments = (@mode.current.entries - [''])
+    return segments[n]
+  end
+  def segment_status (n)
+    segments = @mode.current.entries
+    offset = 0
+    if segments[0] == "" then
+      offset += 1
+    end
+    return ((n + offset) % 3 == 1) ? :highlight : :normal
+  end
+end
+
+require 'Prime'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Xrubylib/Imakefile	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,14 @@
+#include "../../Kinput2.conf"
+
+    SRCS = \
+           misc.c 
+
+    OBJS = $(SRCS:%.c=%.o)
+
+INCLUDES = -I../../include -I$(RUBYSRC)
+
+ DEFINES =
+
+NormalLibraryObjectRule()
+NormalLibraryTarget(Xrubylib,$(OBJS))
+DependTarget()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Xrubylib/callbacks.txt	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,134 @@
+:342:
+    /* $B%F%-%9%H$NJQ2=$r%A%'%C%/$9$k(B */
+    if (obj->ruby.textchanged) {
+	XtCallCallbackList(w, obj->inputConv.textchangecallback,
+			   (XtPointer)NULL);
+	obj->ruby.textchanged = False;
+    }
+
+:351:
+    /* $BF~NO%b!<%I$r%A%'%C%/$9$k(B */
+    if (ks->info & KanjiModeInfo) {
+      XtCallCallbackList(w, obj->inputConv.modechangecallback,
+			 (XtPointer)NULL);
+    }
+
+:357:
+    if (ks->info & KanjiGLineInfo) { /* $B0lMw9T$,$"$k>l9g(B */
+      ICAuxControlArg arg;
+
+      switch (obj->ruby.ibuf->candstat) {
+      case RUBY_GLINE_Start:
+	arg.command = ICAuxStart;
+	XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
+			   (XtPointer)&arg);
+	break;
+      case RUBY_GLINE_End:
+	arg.command = ICAuxEnd;
+	XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
+			   (XtPointer)&arg);
+	break;
+      case RUBY_GLINE_Change:
+	arg.command = ICAuxChange;
+	XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
+			   (XtPointer)&arg);
+	break;
+      }
+    }
+
+:831:
+    /* $B3NDj$N=hM}(B */
+    XtCallCallbackList((Widget)obj, obj->inputConv.fixcallback,
+		       (XtPointer)NULL);	/* $B!)!)!)(B */
+
+:837:
+static void
+convend(obj)
+RubyObject obj;
+{
+    XtCallCallbackList((Widget)obj, obj->inputConv.endcallback,
+		       (XtPointer)NULL);
+}
+
+:1442:
+static void
+moveSelection(obj, dir)
+RubyObject obj;
+int dir;
+{
+    ICSelectionControlArg arg;
+
+    arg.command = ICSelectionMove;
+    arg.u.dir = dir;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		       (XtPointer)&arg);
+}
+
+:1466:
+static void
+endSelection(obj, abort)
+RubyObject obj;
+int abort;
+{
+    ICSelectionControlArg arg;
+    int selected;
+
+    if (ignoreListfunc) return; /* SelectItem $B$G=hM}$5$l$k$N$G$3$3$OITMW(B */
+    arg.command = ICSelectionEnd;
+    arg.u.current_item = -1;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		       (XtPointer)&arg);
+
+    if (!abort && (selected = arg.u.current_item) >= 0) {
+        insertSelection(obj, selected);
+    }
+}
+
+:1486:
+static void
+querySelection(obj)
+RubyObject obj;
+{
+  ICSelectionControlArg arg;
+  int selected;
+
+  if (ignoreListfunc) return; /* SelectItem $B$G=hM}$5$l$k$N$G$3$3$OITMW(B */
+  arg.command = ICSelectionGet;
+  arg.u.current_item = -1;
+  XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		     (XtPointer)&arg);
+
+  if ((selected = arg.u.current_item) >= 0) {
+    insertSelection(obj, selected);
+  }
+}
+
+:1505:
+static void
+openSelection(obj, func, curitem)
+RubyObject obj;
+int func; /* $B0lHV>e$r8+$h(B */
+int curitem;
+{
+  ICSelectionControlArg arg;
+  static int current = 0;
+  static int doit = 0;
+
+  if (func == SELECTION_SET) {
+    current = curitem;
+    doit = 1;
+  }
+  else if (func == SELECTION_DO && doit) {
+    doit = 0;
+    arg.command = ICSelectionStart;
+    arg.u.selection_kind = ICSelectionCandidates;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		       (XtPointer)&arg);
+
+    /* set current item */
+    arg.command = ICSelectionSet;
+    arg.u.current_item = current;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		       (XtPointer)&arg);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Xrubylib/memo.txt	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,14 @@
+copyInWchar $B$N(B wssize $B$H(B wslen $B$NN>J}$,$"$k$3$H$,M}2r$7$,$?$$(B.
+  wssize $B$O(B byte $B?t$G$O$J$/$F(B, $B$?$@$N(B wslen + 1.
+
+ICString: Kinput2 $B$G$NJ8;zNs$N%U%)!<%^%C%H(B
+  VALUE(Ruby $B$NJ8;zNs(B) $B$r(B ICString $B$KJQ49$9$k4X?t$H(B
+  VALUE(Ruby $B$NJ8;zNs(B) $B$N%j%9%H$r(B ICString $B$N%j%9%H$KJQ49$9$k4X?t$,I,MW(B.
+
+  ICString.data $BMQ$N%a%b%j4IM}$,$d$C$+$$$@(B.
+    GetSegment $BMQ(B
+    candList $BMQ(B
+
+The way to negotiate about current selection between Ruby and upper widget(s).
+
+  cur_addr is used. (curcand is not used?)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Xrubylib/misc.c	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,143 @@
+/*
+ * Copyright 1999 Justsystem Corporation, Japan.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Justsystem Corporation
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.  Justsystem
+ * Corporation makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Author: Atsushi Irisawa
+ */
+
+#ifndef lint
+static  char    rcsid[] = "$Id: misc.c,v 1.2 2003/06/10 02:11:27 komatsu Exp $" ;
+#endif  /* !lint */
+#include "WStr.h"
+
+/* Page */
+/*
+ * [$B4X?tL>(B]
+ *		wcs2euc( )
+ * [$BI=Bj(B]
+ *              WCHAR $B7?$+$i(BEUC$BJ8;zNs$X$NJQ49(B
+ * [$B8F=P7A<0(B]
+ *	int	wcs2euc( wchar *wbuf, int wlen, unsigned char *euc )
+ *
+ * [$B0z?t(B]
+ *              $B7?(B           : $BL>(B  $B>N(B  : I O : $B@b(B      $BL@(B
+ *		wchar        : *wbuf   : i   : WCHAR $B7?J8;zNs(B
+ *		int          : wlen    : i   : wchar $B7?J8;zNs$ND9$5(B
+ *		unsigned char : *euc   :   o : EUC $BJ8;zNs3JG<NN0h(B
+ *
+ * [$BJV$jCM(B]
+ *		EUC $BJ8;zNs$ND9$5(B
+ *
+ * [$B;HMQ4X?t(B]
+ *		$B$J$7(B
+ * [$B5!G=(B]
+ *		wchar $B7?J8;zNs$+$i(B unsigined char  $B$N(BEUC$BJ8;zNs$KJQ49$9$k!#(B
+ *
+ */
+
+int wcs2euc(wbuf, wlen, euc)
+wchar	*wbuf;
+int	wlen;
+unsigned char *euc;
+{
+	int	i ;
+	int	n = 0 ;
+	unsigned char	c ;
+	for( i = 0 ; i < wlen ; i++ ) {
+		c =  ( *wbuf & 0xff00 ) >> 8 ;
+		if ( c ) {
+			*euc++ = c ;
+			n++ ;
+		}
+		else if (( *wbuf & 0xff ) & 0x80 ) {
+			*euc++ = 0x8e ;
+			n++ ;
+		}
+		*euc++ =  *wbuf & 0xff ;
+		wbuf++ ;
+		n++ ;
+	}
+	*euc = 0 ;
+
+	return n ;
+}
+/* Page */
+/*
+ * [$B4X?tL>(B]
+ *		euc2wcs( )
+ * [$BI=Bj(B]
+ *              EUC$BJ8;zNs$+$i(B wchar $B7?J8;zNs$X$NJQ49(B
+ * [$B8F=P7A<0(B]
+ *		int	euc2wcs( unsigned char *euc, int elen, wchar *wbuf )
+ *
+ * [$B0z?t(B]
+ *              $B7?(B            : $BL>(B  $B>N(B  : I O : $B@b(B      $BL@(B
+ *		unsigned char : *euc   : i   : EUC $BJ8;zNs(B
+ *		int           : elen   : i   : EUC $BJ8;zNs$ND9$5(B
+ *		wchar         : *wbuf  :   o : wchar $B7?J8;zNs3JG<NN0h(B
+ *
+ * [$BJV$jCM(B]
+ *		1 : $B>o$K#1(B
+ *
+ * [$B;HMQ4X?t(B]
+ *		$B$J$7(B
+ * [$B5!G=(B]
+ *		unsigined char $B7?$N(BEUC $BJ8;zNs$r(Bwchar $B7?$KJQ49$9$k!#(B
+ *		EUC $BJ8;zNs$K$O!"(B0x8f $B$NFCJL$J%3!<%I$,4^$^$l$F$$$k$N$G(B
+ *		wchar $B$KJQ49$9$k;~$K8DJL=hM}$r$9$k!#(B
+ */
+int euc2wcs(euc, elen, wbuf)
+unsigned char	*euc;
+int		elen;
+wchar		*wbuf;
+{
+	int	lb = 0, hb = 0 ;
+	int	i ;
+	int	n = 0 ;
+	int	isSkip ;
+
+	for( i = 0 ; i < elen ; i++ ) {
+		isSkip = 0 ;
+		if (  *euc == 0x8e ) {
+			euc++ ;
+			hb = *euc ;
+			lb = 0 ;
+			i++ ;
+		}
+		else if (  *euc & 0x80 ) {
+			if ( *euc == 0x8f ) {
+				isSkip=1 ;
+			}
+			else {
+				lb = *euc ;
+				euc++ ;
+				hb = *euc ;
+				i++ ;
+			}
+		}
+		else {
+			hb = *euc ;
+			lb = 0 ;
+		}
+		euc++ ;
+		if ( !isSkip ) {
+			*wbuf = (( lb << 8 ) | hb ) & 0xffff ;
+			wbuf++ ;
+			n++ ;
+		}
+	}
+
+	*wbuf = 0 ;
+	return n ;
+}
+/* End of misc.c */
--- a/lib/imlib/imxport.c	Mon Mar 08 20:38:16 2010 +0900
+++ b/lib/imlib/imxport.c	Mon Mar 08 20:38:17 2010 +0900
@@ -37,6 +37,9 @@
 #include <netinet/in.h> 
 #endif
 
+#ifdef DEBUG
+#include <errno.h>
+#endif
 extern int errno;
 
 /*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/ruby-c.c	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,65 @@
+/* $Id: ruby-c.c,v 1.2 2003/06/10 02:11:25 komatsu Exp $ */
+/*
+ * AUTHOR:  Hiroyuki Komatsu <komatsu@taiyaki.org> http://taiyaki.org/
+ * LICENSE: GPL2
+ */
+
+#include <stdarg.h>
+#include "ruby-c.h"
+#define RUBY_EVALF_BUF 1024
+
+VALUE
+ruby_eval (char *statement)
+{
+    int state;
+    VALUE result;
+
+    result = rb_eval_string_protect (statement,  &state);
+    if (state) {
+	EXTERN VALUE ruby_errinfo;
+
+	fprintf(stderr, "Eval Error in \"%s\"\n", statement);
+	fprintf(stderr, "%s\n", STR2CSTR(ruby_errinfo));
+    }
+    return result;
+}
+
+VALUE
+ruby_evalf (char *statement_format, ...)
+{
+    va_list ap;
+    char statement[RUBY_EVALF_BUF];
+    int length;
+
+    va_start (ap, statement_format);
+    length = vsnprintf (statement, RUBY_EVALF_BUF, statement_format, ap);
+    va_end (ap);
+
+    if (length == -1) { /* Before glibc 2.0.6 */
+	fprintf (stderr, "ruby_evalf: Error, Out of Buffer\n");
+	fprintf (stderr, "Buffer size is %d\n", RUBY_EVALF_BUF);
+	return Qnil;
+    } else if (length > RUBY_EVALF_BUF -1) { /* C99 */
+	VALUE result;
+	char *d_statement = malloc (sizeof (char) * length + 1);
+	va_start (ap, statement_format);
+	vsnprintf (d_statement, length + 1, statement_format, ap);
+	va_end (ap);
+	result = ruby_eval (d_statement);
+	free (d_statement);
+	return result;
+    } else {
+	return ruby_eval (statement);
+    }
+}
+
+void
+ruby_load (char *filename)
+{
+    int state;
+    rb_load_protect (rb_str_new2 (filename), 0, &state);
+    if (state) {
+	fprintf(stderr, "Load Error for \"%s\"\n", filename);
+	fprintf(stderr, "%s\n", STR2CSTR(ruby_errinfo));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/ruby-c.h	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,12 @@
+#ifndef _RUBY_C_H_
+#define _RUBY_C_H_
+
+#include <ruby.h>
+void
+ruby_load (char *filename);
+VALUE
+ruby_eval (char *statement);
+VALUE
+ruby_evalf (char *statement_format, ...);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/ruby/Imakefile	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,14 @@
+#include "../../Kinput2.conf"
+
+      RUBY_FILES = kinput2.rb kinput2_default.rb kinput2_prime.rb
+
+all::
+depend::
+clean::
+
+#ifdef UseRuby
+MakeDirectories(install,$(RUBYDIR))
+InstallMultiple($(RUBY_FILES),$(RUBYDIR))
+#else
+install::
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/ruby/kinput2.rb	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,465 @@
+$KCODE = 'e'
+require "jcode"
+require "kconv"
+require 'suikyo/suikyo'
+
+module Debug
+  attr_accessor :debug_mode
+  def debug_message (message, output = nil)
+    if Debug::debug_mode?(output) || @debug_mode then
+      puts "#{self.class}[#{self.id}]: #{message}"
+    end
+  end
+
+  def Debug::message (message, output = nil)
+    if Debug::debug_mode?(output) then
+      puts message
+    end
+  end
+
+  def Debug::debug_mode? (output = nil)
+    return (ENV['RUBY_DEBUG'] || $DEBUG || output)
+  end
+end
+
+class TextEdit
+  include Debug
+
+  attr_reader :cursor
+  def initialize (text = "", cursor = 0)
+    @debug_mode = false
+    set (text, cursor)
+  end
+
+  def set (data, cursor = 0)
+    @data   = data
+    @cursor = cursor
+  end
+
+  def text
+    return @data
+  end
+
+  def reset
+    set ("", 0)
+  end
+
+  def insert (string)
+    @data    = @data[0,@cursor] + string + @data[@cursor..-1]
+    @cursor += string.length;
+  end
+
+  def delete
+    if (@cursor < @data.length) then
+      @data = @data[0,@cursor] + @data[(@cursor + 1)..-1]
+    end
+  end
+
+  def backspace
+    if (@cursor > 0) then
+      @data = @data[0,(@cursor - 1)] + @data[@cursor..-1]
+      @cursor -= 1
+    end
+  end
+
+  def cursor_left
+    if (@cursor > 0) then
+      @cursor -= 1
+    end
+  end
+
+  def cursor_right
+    if (@cursor < @data.length) then
+      @cursor += 1
+    end
+  end
+
+  def cursor_beginning
+    @cursor = 0
+  end
+
+  def cursor_end
+    @cursor = @data.length
+  end
+
+  def segments
+    # [text before the cursor, text on the cursor, text after the cursor]
+    return [@data[0,@cursor], @data[@cursor,1], @data[(@cursor + 1)..-1]]
+  end
+end
+
+class JTextEdit < TextEdit
+  def initialize (text = "", cursor = 0)
+    super
+    @suikyo = Suikyo.new
+    @suikyo.table.loadfile("romaji-kana")
+  end
+
+  def text
+    if @cursor == @data.length then
+      return @suikyo.convert (@data)
+    else
+      return super
+    end
+  end
+
+  def segments
+    if @cursor == @data.length then
+      return [@suikyo.convert (@data), '', '']
+    else
+      return super
+    end
+  end
+end
+
+class Window 
+  attr_reader :call_open, :call_close, :visible
+
+  def initialize (parent)
+    @parent = parent
+    @visible = false
+  end
+
+  def open
+    @call_open = true unless @visible
+  end
+  def open_end
+    @call_open = false
+    @visible = true
+  end
+
+  def close
+    @call_close = true if @visible
+  end
+  def close_end
+    @call_close = false
+    @visible = false
+  end
+end
+
+class Dialog < Window
+  def text
+    @parent.cand_list.join(" ")
+  end
+end
+
+class Selection < Window
+  attr_reader :call_right, :call_left, :call_line_beginning, :call_line_end,
+    :call_up, :call_down
+
+  def right
+    @call_right = true
+  end
+  def right_end
+    @call_right = false
+  end
+
+  def left
+    @call_left = true
+  end
+  def left_end
+    @call_left = false
+  end
+
+  def line_beginning
+    @call_line_beginning = true
+  end
+  def line_beginning_end
+    @call_line_beginning = false
+  end
+
+  def line_end
+    @call_line_end = true
+  end
+  def line_end_end
+    @call_line_end = false
+  end
+
+  def up
+    @call_up = true
+  end
+  def up_end
+    @call_up = false
+  end
+
+  def down
+    @call_down = true
+  end
+  def down_end
+    @call_down = false
+  end
+end
+
+class KeyMap
+  @@keysym = {
+    :enter => 65293,
+    :space => 32,
+    :tab => 65289,
+    :delete => 65535,
+    :insert => 65379,
+    :home => 65360,
+    :end => 65367,
+    :page_up => 65365,
+    :page_down => 65366,
+    :esc => 65307,
+    :f1 => 65470,
+    :f2 => 65471,
+    :f3 => 65472,
+    :f4 => 65473,
+    :f5 => 65474,
+    :f6 => 65475,
+    :f7 => 65476,
+    :f8 => 65477,
+    :f9 => 65478,
+    :f10 => 65479,
+    :f11 => 65480,
+    :f12 => 65481,
+    :backspace => 65288,
+    :muhenkan => 65314,
+    :henkan => 65315,
+    :hankaku_zenkaku => 65322,
+    :katakana_hiragana => 65319,
+    :up => 65362,
+    :down => 65364,
+    :right => 65363,
+    :left => 65361,
+    :ctrl_l => 65507,
+    :ctrl_r => 65508,
+    :alt_l => 65513,
+    :alt_r => 65514,
+    :shift_l => 65505,
+    :shift_r => 65506,
+  }
+
+#   @@enter = [13, 65293, 0]
+#   @@ctrl_a = [1,  97,  4];  @@alt_a = [97,  97,  8]
+#   @@ctrl_b = [2,  98,  4];  @@alt_b = [98,  98,  8]
+#   @@ctrl_c = [3,  99,  4];  @@alt_c = [99,  99,  8]
+#   @@ctrl_d = [4,  100, 4];  @@alt_d = [100, 100, 8]
+#   @@ctrl_e = [5,  101, 4];  @@alt_e = [101, 101, 8]
+#   @@ctrl_f = [6,  102, 4];  @@alt_f = [102, 102, 8]
+#   @@ctrl_g = [7,  103, 4];  @@alt_g = [103, 103, 8]
+#   @@ctrl_h = [8,  104, 4];  @@alt_h = [104, 104, 8]
+#   @@ctrl_i = [9,  105, 4];  @@alt_i = [105, 105, 8]
+#   @@ctrl_j = [10, 106, 4];  @@alt_j = [106, 106, 8]
+#   @@ctrl_k = [11, 107, 4];  @@alt_k = [107, 107, 8]
+#   @@ctrl_l = [12, 108, 4];  @@alt_l = [108, 108, 8]
+#   @@ctrl_m = [13, 109, 4];  @@alt_m = [109, 109, 8]
+#   @@ctrl_n = [14, 110, 4];  @@alt_n = [110, 110, 8]
+#   @@ctrl_o = [15, 111, 4];  @@alt_o = [111, 111, 8]
+#   @@ctrl_p = [16, 112, 4];  @@alt_p = [112, 112, 8]
+#   @@ctrl_q = [17, 113, 4];  @@alt_q = [113, 113, 8]
+#   @@ctrl_r = [18, 114, 4];  @@alt_r = [114, 114, 8]
+#   @@ctrl_s = [19, 115, 4];  @@alt_s = [115, 115, 8]
+#   @@ctrl_t = [20, 116, 4];  @@alt_t = [116, 116, 8]
+#   @@ctrl_u = [21, 117, 4];  @@alt_u = [117, 117, 8]
+#   @@ctrl_v = [22, 118, 4];  @@alt_v = [118, 118, 8]
+#   @@ctrl_w = [23, 119, 4];  @@alt_w = [119, 119, 8]
+#   @@ctrl_x = [24, 120, 4];  @@alt_x = [120, 120, 8]
+#   @@ctrl_y = [25, 121, 4];  @@alt_y = [121, 121, 8]
+#   @@ctrl_z = [26, 122, 4];  @@alt_z = [122, 122, 8]
+
+  @@modifier = { :shift => 1, :ctrl => 4, :alt => 8 }
+
+  def initialize
+    @keymap = Hash.new
+  end
+
+  def key (stroke)
+    modifiers = 0
+    if stroke.kind_of?(Array) then
+      main_key = stroke[0]
+      stroke[1..-1].each {|modifier|
+	modifiers |=
+	  (modifier.kind_of?(Symbol) ? @@modifier[modifier] : modifier)
+      }
+    else
+      main_key = stroke
+    end
+    if main_key.kind_of?(Symbol) then
+      main_key = @@keysym[main_key]
+    end
+    return [main_key, modifiers]
+  end
+
+  def ignore_shift (key)
+    (main_key, modifiers) = key
+    return [main_key, (modifiers & ~@@modifier[:shift])]
+  end
+
+  def add (stroke, command)
+    @keymap[key(stroke)] = command
+  end
+
+  def del (stroke)
+    @keymap.delete(key(stroke))
+  end
+
+  def command (stroke)
+    return @keymap[key(stroke)] || @keymap[ignore_shift(key(stroke))]
+  end
+end
+
+
+class ModeCore
+  attr_accessor :trap
+  attr_reader :label, :keymap
+  def initialize (parent)
+    @parent = parent
+    @label  = ""
+    @keymap = KeyMap.new
+    initialize_keys
+    @trap   = true
+  end
+
+  def on (prev_mode = nil)
+  end
+
+  def off (next_mode = nil)
+  end
+
+  def entries
+    return []
+  end
+
+  def call (char, keysym, modifiers)
+    command = @keymap.command([keysym, modifiers])
+    if command then
+      return send(command, keysym, modifiers)
+    else
+      return @trap
+    end
+  end
+end
+
+class ModeMaster
+  attr_reader :current_name
+
+  def initialize (parent, mode = :fund)
+    @parent = parent
+    @mode = Hash.new
+    @current_name = nil
+  end
+
+  def set (name, mode)
+    @mode[name] = mode
+    unless @current then
+      @current_name = name
+    end
+  end
+
+  def current
+    return @mode[@current_name]
+  end
+
+  def change (name)
+    if @mode.key?(name) then
+      @current_name = name
+      current.on
+      return true
+    else
+      return false
+    end
+  end
+
+  def label (name = @current_name)
+    if name then
+      mode = @mode[name]
+    else
+      mode = current
+    end
+
+    if mode then
+      return mode.label.toeuc
+    else
+      return "NOMODE"
+    end
+  end
+end
+
+class KanjiConvCore
+  include Debug
+  attr_reader :cand_list, :cand_index,
+    :value_fixed, :call_fix, :mode
+
+  def initialize
+    @debug_mode = false
+
+    @textEdit = TextEdit.new
+    @mode = ModeMaster.new (self)
+    clear
+  end
+
+  def reset
+    clear
+  end
+
+  def clear
+    @cand_list = []
+    @cand_index = 0
+
+    @call_fix = false
+    @value_fixed = ""
+  end
+
+  ## inputEvent (keynum, keysym = nil, state = nil)
+  ## ReturnValue 1:Pass 0:Trap
+  def inputEvent (keynum, keysym = nil, state = nil)
+    return 1
+  end
+
+  def fix (fixed_arg)
+    # fixed_arg is a string or an index number of cand_list.
+    @call_fix = true
+    if fixed_arg.kind_of?(Integer) then
+      word = @cand_list[fixed_arg]
+    else
+      word = fixed_arg
+    end
+    @value_fixed = word
+  end
+  def fix_end
+    @call_fix = false
+    @value_fixed = ""
+  end
+
+  def modeline
+    return @mode.label
+  end
+
+  def set_cand_list (list, index = nil)
+    if (list.is_a?(Array) && list.length > 0) then
+      @cand_list  = list.map {|cand| cand.toeuc}
+      @cand_index = index if index
+      return true
+    else
+      reset_cand_list
+      return false
+    end
+  end
+  def set_cand_index (index)
+    debug_message("<<set_cand_index>> #{index}")
+    @cand_index = index
+  end
+  def reset_cand_list
+    @cand_list  = []
+    @cand_index = 0
+  end
+
+  def segment_length
+    segments = (@mode.current.entries - [''])
+    return segments.length
+  end
+  def segment_word (n)
+    segments = (@mode.current.entries - [''])
+    return segments[n]
+  end
+  def segment_status (n)
+    segments = @mode.current.entries
+    offset = 0
+    if segments[0] == "" then
+      offset += 1
+    end
+    return ((n + offset) % 3 == 1) ? :highlight : :normal
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/ruby/kinput2_default.rb	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,287 @@
+require 'kinput2'
+
+class KanjiConv < KanjiConvCore
+  attr_reader :input, :selection, :dialog
+
+  def initialize
+    super
+    @input  = JTextEdit.new
+
+    @selection = Selection.new (self)
+    @dialog = Dialog.new (self)
+    @mode = ModeMaster.new (self)
+
+    @fundMode  = FundMode.new(self)
+    @inputMode = InputMode.new(self)
+    @convMode  = ConvMode.new(self)
+    @mode.set(:fund,  @fundMode)
+    @mode.set(:input, @inputMode)
+    @mode.set(:conv,  @convMode)
+    @mode.change(:fund)
+
+    debug_message("Initialize Done.")
+  end
+
+  def reset
+    super
+    @mode.change(:fund)
+    @input.reset
+    reset_cand_list
+  end
+
+  def convert (word)
+    cand_list = [word, word.upcase]
+    return cand_list
+  end
+
+  ## inputEvent (keynum, keysym = nil, state = nil)
+  ## ReturnValue 1:Pass 0:Trap
+  def inputEvent (keynum, keysym = nil, state = nil)
+    debug_message("KeyNum: #{keynum}, KeySym: #{keysym}, Status: #{state}")
+
+    if keynum == 0 then
+      return 1
+    end
+    key = [keynum]
+
+    if @mode.current then
+      trap = @mode.current.call (keynum, keysym, state)
+      return ((trap == true) ? 0 : 1)
+    end
+    return 1;
+  end
+
+  def selection_fix (index)
+    fix (index)
+    @mode.change(:fund)
+  end
+
+  def fix (fixed_arg)
+    ### Must NOT chage @mode here, because exceptional case can exist.
+    super (fixed_arg)
+    @input.reset
+    reset_cand_list
+  end
+
+  def insert (keysym, modifiers)
+    debug_message("insert '#{keysym.chr}'")
+    @input.insert(keysym.chr)
+    set_cand_list (convert(@input.text), 0)
+  end
+end
+
+class PrimeModeCore < ModeCore
+  def initialize (parent)
+    super
+  end
+
+  private
+  def insert (keysym, modifiers)
+    @parent.insert(keysym, modifiers)
+    @parent.mode.change(:input)
+    return true
+  end
+
+  def fix (keysym, modifiers)
+    fix_internal(keysym, modifiers)
+    @parent.mode.change(:fund)
+    return true
+  end
+
+  def fix_and_insert (keysym, modifiers)
+    fix_internal (keysym, modifiers)
+    insert (keysym, modifiers)
+    return true
+  end
+
+  def cursor_right (keysym, modifiers)
+    @parent.input.cursor_right
+    return true
+  end
+  def cursor_left (keysym, modifiers)
+    @parent.input.cursor_left
+    return true
+  end
+  def cursor_beginning (keysym, modifiers)
+    @parent.input.cursor_beginning
+    return true
+  end
+  def cursor_end (keysym, modifiers)
+    @parent.input.cursor_end
+    return true
+  end
+
+  def selection_right (keysym, modifiers)
+    @parent.selection.right
+    return true
+  end
+  def selection_left (keysym, modifiers)
+    @parent.selection.left
+    return true
+  end
+  def selection_beginning (keysym, modifiers)
+    @parent.selection.line_beginning
+    return true
+  end
+  def selection_end (keysym, modifiers)
+    @parent.selection.line_end
+    return true
+  end
+  def selection_up (keysym, modifiers)
+    @parent.selection.up
+    return true
+  end
+  def selection_down (keysym, modifiers)
+    @parent.selection.down
+    return true
+  end
+end
+
+class FundMode < PrimeModeCore
+  def initialize (parent)
+    super
+    @label = '[ $B$"(B ]'
+    @trap  = false
+  end
+
+  def initialize_keys
+    (33..126).each {|char|
+      @keymap.add(char, :insert)
+    }
+  end
+
+  def on (prev_mode = nil)
+    @parent.selection.close
+  end
+end
+
+class InputMode < PrimeModeCore
+  def initialize (parent)
+    super
+    @label   = "[$BF~NO(B]"
+  end
+
+  def initialize_keys
+    (33..126).each {|char|
+      @keymap.add(char, :insert)
+    }
+    (?A..?Z).each {|char|
+      @keymap.add(char, :fix_and_insert)
+    }
+    @keymap.add(:enter, :fix)
+    @keymap.add([?m, :ctrl], :fix)
+    @keymap.add(:space, :convert)
+    @keymap.add(:backspace, :backspace)
+    @keymap.add([?h, :ctrl], :backspace)
+    @keymap.add(:delete, :delete)
+    @keymap.add([?d, :ctrl], :delete)
+    @keymap.add(:left, :cursor_left)
+    @keymap.add([?b, :ctrl], :cursor_left)
+    @keymap.add(:right, :cursor_right)
+    @keymap.add([?f, :ctrl], :cursor_right)
+    @keymap.add([?a, :ctrl], :cursor_beginning)
+    @keymap.add([?e, :ctrl], :cursor_end)
+    @keymap.add([?g, :ctrl], :cancel)
+    @keymap.add(:esc, :cancel)
+  end
+
+  def on (prev_mode = nil)
+    @parent.selection.close
+  end
+
+  def entries
+    return @parent.input.segments
+  end
+
+  private
+  def fix_internal (keysym, modifiers)
+    @parent.fix(@parent.input.text)
+  end
+
+  def backspace (keysym, modifiers)
+    @parent.input.backspace
+    if @parent.input.text.length == 0 then
+      @parent.mode.change(:fund)
+    end
+    return true
+  end
+
+  def delete (keysym, modifiers)
+    @parent.input.delete
+    if @parent.input.text.length == 0 then
+      @parent.mode.change(:fund)
+    end
+    return true
+  end
+
+  def cancel (keysym, modifiers)
+    @parent.input.reset
+    @parent.mode.change(:fund)
+    return true
+  end
+
+  def convert (keysym, modifiers)
+    if @parent.set_cand_list (@parent.convert(@parent.input.text)) then
+      @parent.set_cand_index(0)
+      @parent.mode.change(:conv)
+    end
+    return true
+  end
+end
+
+class ConvMode < PrimeModeCore
+  def initialize (parent)
+    super
+    @label  = "[$BJQ49(B]"
+  end
+
+  def initialize_keys
+    (33..126).each {|char|
+      @keymap.add(char, :fix_and_insert)
+    }
+    @keymap.add(:enter, :fix)
+    @keymap.add([?m, :ctrl], :fix)
+    @keymap.add(:space, :convert)
+#     @keymap.add(:backspace, :backspace)
+#     @keymap.add([?h, :ctrl], :backspace)
+#     @keymap.add(:delete, :delete)
+#     @keymap.add([?d, :ctrl], :delete)
+    @keymap.add(:left, :selection_left)
+    @keymap.add([?b, :ctrl], :selection_left)
+    @keymap.add(:right, :selection_right)
+    @keymap.add([?f, :ctrl], :selection_right)
+    @keymap.add(:down, :selection_down)
+    @keymap.add([?n, :ctrl], :selection_down)
+    @keymap.add(:up, :selection_up)
+    @keymap.add([?p, :ctrl], :selection_up)
+    @keymap.add([?a, :ctrl], :selection_beginning)
+    @keymap.add([?e, :ctrl], :selection_end)
+    @keymap.add([?g, :ctrl], :cancel)
+    @keymap.add(:esc, :cancel)
+  end
+
+  def on (prev_mode = nil)
+    @parent.selection.open
+  end
+
+  def entries
+    return ['', @parent.cand_list[@parent.cand_index]]
+  end
+
+  private
+  def fix_internal (keysym, modifiers)
+    @parent.fix(@parent.cand_list[@parent.cand_index])
+  end
+  
+  def cancel (keysym, modifiers)
+    @parent.mode.change(:input)
+    return true
+  end
+
+  def convert (keysym, modifiers)
+    return selection_right(keysym, modifiers)
+  end
+end
+
+$kanjiConv = KanjiConv.new
+#p local_variables
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/ruby/kinput2_prime.rb	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,307 @@
+# $LOAD_PATH.push ('/home/komatsu/src/prime/prime-xim/lib/ruby/')
+
+# PRIME_USER_DIR = ENV['HOME'] + '/.prime'
+# PRIME_PATH = '/home/komatsu/src/prime'
+# $LOAD_PATH.push (PRIME_PATH)
+
+require 'kinput2'
+require 'prime/prime'
+
+class KanjiConv < KanjiConvCore
+  attr_reader :input, :selection, :dialog
+
+  def initialize
+    super
+#    @useprime = false
+    @useprime = true
+    
+    if @useprime then
+      @prime = Prime.new
+    end
+    @input  = JTextEdit.new
+
+    @selection = Selection.new (self)
+    @dialog = Dialog.new (self)
+    @mode = ModeMaster.new (self)
+
+    @fundMode  = FundMode.new(self)
+    @inputMode = InputMode.new(self)
+    @convMode  = ConvMode.new(self)
+    @mode.set(:fund,  @fundMode)
+    @mode.set(:input, @inputMode)
+    @mode.set(:conv,  @convMode)
+    @mode.change(:fund)
+
+    debug_message("Initialize Done.")
+  end
+
+  def reset
+    super
+    @mode.change(:fund)
+    @input.reset
+    reset_cand_list
+  end
+
+  def convert (word)
+    if @useprime then
+      cand_list = @prime.lookup_hybrid(word).values
+    else
+      cand_list = [word, "Taiyaki", "Hiroyuki", "Komatsu", "$B4A;z(B"]
+    end
+    return cand_list[0,5]
+  end
+
+  ## inputEvent (keynum, keysym = nil, state = nil)
+  ## ReturnValue 1:Pass 0:Trap
+  def inputEvent (keynum, keysym = nil, state = nil)
+    debug_message("KeyNum: #{keynum}, KeySym: #{keysym}, Status: #{state}")
+
+    if keynum == 0 then
+      return 1
+    end
+    key = [keynum]
+
+    if @mode.current then
+      trap = @mode.current.call (keynum, keysym, state)
+      return ((trap == true) ? 0 : 1)
+    end
+    return 1;
+  end
+
+  def selection_fix (index)
+    fix (index)
+    @mode.change(:fund)
+  end
+
+  def fix (fixed_arg)
+    ### Must NOT chage @mode here, because exceptional case can exist.
+    super (fixed_arg)
+    @input.reset
+    reset_cand_list
+  end
+
+  def insert (keysym, modifiers)
+    debug_message("insert '#{keysym.chr}'")
+    @input.insert(keysym.chr)
+    set_cand_list (convert(@input.text), 0)
+  end
+end
+
+class PrimeModeCore < ModeCore
+  def initialize (parent)
+    super
+  end
+
+  private
+  def insert (keysym, modifiers)
+    @parent.insert(keysym, modifiers)
+    @parent.mode.change(:input)
+    return true
+  end
+
+  def fix (keysym, modifiers)
+    fix_internal(keysym, modifiers)
+    @parent.mode.change(:fund)
+    return true
+  end
+
+  def fix_and_insert (keysym, modifiers)
+    fix_internal (keysym, modifiers)
+    insert (keysym, modifiers)
+    return true
+  end
+
+  def cursor_right (keysym, modifiers)
+    @parent.input.cursor_right
+    return true
+  end
+  def cursor_left (keysym, modifiers)
+    @parent.input.cursor_left
+    return true
+  end
+  def cursor_beginning (keysym, modifiers)
+    @parent.input.cursor_beginning
+    return true
+  end
+  def cursor_end (keysym, modifiers)
+    @parent.input.cursor_end
+    return true
+  end
+
+  def selection_right (keysym, modifiers)
+    @parent.selection.right
+    return true
+  end
+  def selection_left (keysym, modifiers)
+    @parent.selection.left
+    return true
+  end
+  def selection_beginning (keysym, modifiers)
+    @parent.selection.line_beginning
+    return true
+  end
+  def selection_end (keysym, modifiers)
+    @parent.selection.line_end
+    return true
+  end
+  def selection_up (keysym, modifiers)
+    @parent.selection.up
+    return true
+  end
+  def selection_down (keysym, modifiers)
+    @parent.selection.down
+    return true
+  end
+end
+
+class FundMode < PrimeModeCore
+  def initialize (parent)
+    super
+    @label = '[ $B$"(B ]'
+    @trap  = false
+  end
+
+  def initialize_keys
+    (33..126).each {|char|
+      @keymap.add(char, :insert)
+    }
+  end
+
+  def on (prev_mode = nil)
+    @parent.selection.close
+    @parent.dialog.close
+  end
+end
+
+class InputMode < PrimeModeCore
+  def initialize (parent)
+    super
+    @label   = "[$BF~NO(B]"
+  end
+
+  def initialize_keys
+    (33..126).each {|char|
+      @keymap.add(char, :insert)
+    }
+    (?A..?Z).each {|char|
+      @keymap.add(char, :fix_and_insert)
+    }
+    @keymap.add(:enter, :fix)
+    @keymap.add([?m, :ctrl], :fix)
+    @keymap.add(:space, :convert)
+    @keymap.add(:backspace, :backspace)
+    @keymap.add([?h, :ctrl], :backspace)
+    @keymap.add(:delete, :delete)
+    @keymap.add([?d, :ctrl], :delete)
+    @keymap.add(:left, :cursor_left)
+    @keymap.add([?b, :ctrl], :cursor_left)
+    @keymap.add(:right, :cursor_right)
+    @keymap.add([?f, :ctrl], :cursor_right)
+    @keymap.add([?a, :ctrl], :cursor_beginning)
+    @keymap.add([?e, :ctrl], :cursor_end)
+    @keymap.add([?g, :ctrl], :cancel)
+    @keymap.add(:esc, :cancel)
+  end
+
+  def on (prev_mode = nil)
+    @parent.selection.close
+    @parent.dialog.open
+  end
+
+  def entries
+    return @parent.input.segments
+  end
+
+  private
+  def fix_internal (keysym, modifiers)
+    @parent.fix(@parent.input.text)
+  end
+
+  def backspace (keysym, modifiers)
+    @parent.input.backspace
+    if @parent.input.text.length == 0 then
+      @parent.mode.change(:fund)
+    end
+    return true
+  end
+
+  def delete (keysym, modifiers)
+    @parent.input.delete
+    if @parent.input.text.length == 0 then
+      @parent.mode.change(:fund)
+    end
+    return true
+  end
+
+  def cancel (keysym, modifiers)
+    @parent.input.reset
+    @parent.mode.change(:fund)
+    return true
+  end
+
+  def convert (keysym, modifiers)
+    if @parent.set_cand_list (@parent.convert(@parent.input.text)) then
+      @parent.set_cand_index(0)
+      @parent.mode.change(:conv)
+    end
+    return true
+  end
+end
+
+class ConvMode < PrimeModeCore
+  def initialize (parent)
+    super
+    @label  = "[$BJQ49(B]"
+  end
+
+  def initialize_keys
+    (33..126).each {|char|
+      @keymap.add(char, :fix_and_insert)
+    }
+    @keymap.add(:enter, :fix)
+    @keymap.add([?m, :ctrl], :fix)
+    @keymap.add(:space, :convert)
+#     @keymap.add(:backspace, :backspace)
+#     @keymap.add([?h, :ctrl], :backspace)
+#     @keymap.add(:delete, :delete)
+#     @keymap.add([?d, :ctrl], :delete)
+    @keymap.add(:left, :selection_left)
+    @keymap.add([?b, :ctrl], :selection_left)
+    @keymap.add(:right, :selection_right)
+    @keymap.add([?f, :ctrl], :selection_right)
+    @keymap.add(:down, :selection_down)
+    @keymap.add([?n, :ctrl], :selection_down)
+    @keymap.add(:up, :selection_up)
+    @keymap.add([?p, :ctrl], :selection_up)
+    @keymap.add([?a, :ctrl], :selection_beginning)
+    @keymap.add([?e, :ctrl], :selection_end)
+    @keymap.add([?g, :ctrl], :cancel)
+    @keymap.add(:esc, :cancel)
+  end
+
+  def on (prev_mode = nil)
+    @parent.selection.open
+    @parent.dialog.close
+  end
+
+  def entries
+    return ['', @parent.cand_list[@parent.cand_index]]
+  end
+
+  private
+  def fix_internal (keysym, modifiers)
+    @parent.fix(@parent.cand_list[@parent.cand_index])
+  end
+  
+  def cancel (keysym, modifiers)
+    @parent.mode.change(:input)
+    return true
+  end
+
+  def convert (keysym, modifiers)
+    return selection_right(keysym, modifiers)
+  end
+end
+
+$kanjiConv = KanjiConv.new
+#p local_variables
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/ruby/test/testPrime.rb	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,13 @@
+require '/home/komatsu/src/prime/prime-xim/lib/Ruby.rb'
+
+kanjiConv = KanjiConv.new
+p kanjiConv.mode.current_name
+puts kanjiConv.modeline
+kanjiConv.inputEvent (97, 97, 0)
+p kanjiConv.mode.current_name
+puts kanjiConv.modeline
+kanjiConv.inputEvent (97, 97, 0)
+p kanjiConv.mode.current_name
+puts kanjiConv.modeline
+p kanjiConv.segment_length
+p kanjiConv.segment_status(0)