*** empty log message ***
[m17n/m17n-lib-cs.git] / MInputMethod.cs
index 6091f14..be452c1 100644 (file)
@@ -19,16 +19,14 @@ namespace M17N.Input
     public delegate bool Callback (Context ic, MPlist args);
 
     // Class members
-    public static Callback PreeditStart, PreeditDone, PreeditDraw;
-    public static Callback StatusStart, StatusDone, StatusDraw;
-    public static Callback CandidateStart, CandidateDone, CandidateDraw;
-    public static Callback SetSpot;
-    public static Callback Toggle;
-    public static Callback Reset;
+    public static event Callback PreeditChanged;
+    public static event Callback StatusChanged;
+    public static event Callback CandidateChanged;
     public static Callback GetSurroundingText;
     public static Callback DeleteSurroundingText;
 
-    internal static Xex.Domain im_domain = new Xex.Domain (null);
+    internal static Xex.Domain im_domain
+      = new Xex.Domain ("input-method", null);
     private static MSymbol Minput_method = "input-method";
     private static MSymbol Mdescription = "description";
     private static MSymbol Mvariable = "variable";
@@ -41,27 +39,6 @@ namespace M17N.Input
     private static MSymbol Mmap_list = "map-list";
     private static MSymbol Mstate = "state";
     internal static MSymbol Mcandidates = "candidates";
-    private static MSymbol Minsert = "insert";
-    internal static MSymbol Mselect = "select";
-    private static MSymbol Mdelete = "delete";
-    private static MSymbol Mmove = "move";
-    private static MSymbol Mmark = "mark";
-    private static MSymbol Mmarker = "marker";
-    private static MSymbol Mset = "set";
-    private static MSymbol Madd = "add";
-    private static MSymbol Msub = "sub";
-    private static MSymbol Mmul = "mul";
-    private static MSymbol Mdiv = "div";
-    private static MSymbol Mif = "if";
-    private static MSymbol Mcond = "cond";
-    private static MSymbol Mchar_at = "char-at";
-    private static MSymbol Msurrounding_flag = "surrounding-text-flag";
-    private static MSymbol Mpushback = "pushback"; 
-    private static MSymbol Mkeyseq = "keyseq"; 
-
-    private static MSymbol Mget_surrounding_text = "get-surrounding-text";
-    private static MSymbol Mdel_surrounding_text = "del-surrounding-text";
-
     private static MSymbol Mat_minus_zero = "@-0";
 
     private static Xex.Symbol Qmap = "map";
@@ -72,6 +49,17 @@ namespace M17N.Input
     private static Xex.Symbol Qinsert = "insert";
     private static Xex.Symbol Qinsert_candidates = "insert-candidates";
     private static Xex.Symbol Qchar_at = "char-at";
+    private static Xex.Symbol Qselect = "select";
+    private static Xex.Symbol Qdelete = "delete";
+    private static Xex.Symbol Qshift = "shift";
+    private static Xex.Symbol Qmove = "move";
+    private static Xex.Symbol Qmark = "mark";
+    private static Xex.Symbol Qset = "set";
+    private static Xex.Symbol Qadd = "add";
+    private static Xex.Symbol Qsub = "sub";
+    private static Xex.Symbol Qmul = "mul";
+    private static Xex.Symbol Qdiv = "div";
+    private static Xex.Symbol Qcond = "cond";
     private static Xex.Symbol Qsname = "sname";
     private static Xex.Symbol Qmname = "mname";
     private static Xex.Symbol Qstate_hook = "state-hook";
@@ -79,7 +67,9 @@ namespace M17N.Input
     private static Xex.Symbol Qbranch = "branch";
     private static Xex.Symbol Qstate = "state";
     private static Xex.Symbol Qtitle = "title";
-
+    private static Xex.Symbol Qeq = "=";
+    private static Xex.Symbol Qeqeq = "==";
+    private static Xex.Symbol Qcandidates_group_size = "candidates-group-size";
 
     private static Xex.Term Tnil = new Xex.Term ((Xex.Symbol) "nil");
     private static Xex.Term Tcatch_tag = new Xex.Term ((Xex.Symbol) "@mimtag");
@@ -90,7 +80,7 @@ namespace M17N.Input
     internal static MInputMethod im_global = null;
 
     [FlagsAttribute]
-    private enum LoadStatus
+    protected enum LoadStatus
     {
       None =   0x00,
       Header = 0x01,
@@ -104,11 +94,13 @@ namespace M17N.Input
     {
       None =           0x00,
       StateTitle =     0x01,
-      Preedit   =      0x02,
+      PreeditText =    0x02,
       CursorPos =      0x04,
       CandidateList =  0x08,
       CandidateIndex = 0x10,
       CandidateShow =  0x20,
+      Preedit =                PreeditText | CursorPos,
+      Candidate =      CandidateList | CandidateIndex | CandidateShow,
     }
 
     private static ChangedStatus CandidateAll = (ChangedStatus.CandidateList
@@ -323,7 +315,18 @@ namespace M17N.Input
 
       public override string ToString ()
       {
-       MText mt = new MText (ToChar ());
+       int c = ToChar ();
+       MText mt = null;
+       if (c < 0x20)
+         foreach (KeyValuePair<string, uint> kv in keysyms)
+           if ((uint) c == kv.Value)
+             {
+               mt = kv.Key;
+               break;
+             }
+       if (mt == null)
+         mt = new MText (c);
+
        KeyModifier m = ((KeyModifier) key) & KeyModifier.All;
 
        if (m != KeyModifier.None)
@@ -407,7 +410,7 @@ namespace M17N.Input
       {
        MText mt;
        foreach (Key key in keyseq)
-         if (key.HasModifier)
+         if (key.HasModifier || key.ToChar () < 0x20)
            {
              mt = "(";
              foreach (Key k in keyseq)
@@ -421,10 +424,12 @@ namespace M17N.Input
        mt = "\"";
        foreach (Key k in keyseq)               
          {
-           if (mt.Length > 1)
-             mt.Cat (' ');
-           mt.Cat (k.ToString ());
-         }
+           int c = k.ToChar ();
+
+           if (c == '\\' || c == '"')
+             mt.Cat ('\\');
+           mt.Cat (c);
+         }         
        return (string) mt.Cat ("\"");
       }
     }
@@ -545,6 +550,7 @@ namespace M17N.Input
        }
 
       public abstract int Position (Context ic);
+
       public virtual void Mark (Context ic)
        {
          throw new Exception ("Can't set predefined marker: " + name);
@@ -553,7 +559,11 @@ namespace M17N.Input
        {
          return ic.preedit[Position (ic)];
        }
-      public override Xex.TermValue Clone () { return this; }
+
+      public override string ToString ()
+      {
+       return "<marker>" + name.Name + "</marker>";
+      }
 
       public static Xex.TermValue parser (Xex.Domain domain, XmlNode node)
       {
@@ -566,24 +576,28 @@ namespace M17N.Input
 
        public override int Position (Context ic)
        {
-         MPlist p = ic.markers.Find (name);
-         return (p != null ? p.Integer : 0);
-
+         MPlist p =  ic.marker_positions.Find (name);
+         return (p == null ? 0 : p.Integer);
        }
 
        public override void Mark (Context ic)
        {
-         ic.markers.Put (name, ic.cursor_pos);
+         ic.marker_positions.Put (name, ic.cursor_pos);
        }
       }
      
       public class Predefined : Marker
       {
-       public Predefined (MSymbol name) : base (name) { }
+       char tag;
+
+       public Predefined (MSymbol name) : base (name)
+         {
+           tag = ((string) name)[1];
+         }
        
        public override int Position (Context ic)
        {
-         switch (name.Name[1]) {
+         switch (tag) {
          case '<': return 0;
          case '>': return ic.preedit.Length;
          case '-': return ic.cursor_pos - 1;
@@ -607,7 +621,7 @@ namespace M17N.Input
              }
            return ic.preedit.Length;
          default:
-           return name.Name[1] - '0';
+           return tag - '0';
          }
        }
       }
@@ -618,7 +632,7 @@ namespace M17N.Input
 
        public PredefinedAbsolute (MSymbol name) : base (name)
          {
-           if (! int.TryParse (name.Name.Substring (1), out pos))
+           if (! int.TryParse (((string) name).Substring (1), out pos))
              throw new Exception ("Invalid marker name: " + name);
          }
 
@@ -634,7 +648,7 @@ namespace M17N.Input
 
        public PredefinedSurround (MSymbol name) : base (name)
          {
-           if (! int.TryParse (name.Name.Substring (2), out distance))
+           if (! int.TryParse (((string) name).Substring (2), out distance))
              throw new Exception ("Invalid marker name: " + name);
            if (distance > 0)
              distance--;
@@ -660,7 +674,7 @@ namespace M17N.Input
 
       static Marker ()
       {
-       predefined_markers = new Dictionary<MSymbol,Predefined> ();
+       predefined_markers = new Dictionary<MSymbol, Predefined> ();
        MSymbol[] symlist = new MSymbol[] {"@<", "@>", "@-", "@+", "@[", "@]" };
        foreach (MSymbol s in symlist)
          predefined_markers[s] = new Predefined (s);
@@ -668,17 +682,18 @@ namespace M17N.Input
 
       public static Marker Get (MSymbol name)
       {
-       if (name.Name[0] == '@')
+       string str = name.Name;
+       if (str[0] == '@')
          {
            Predefined pred;
            if (predefined_markers.TryGetValue (name, out pred))
              return pred;
-           if (name.Name.Length == 1)
+           if (str.Length == 1)
              throw new Exception ("Invalid marker name: " + name);
-           if (Char.IsDigit (name.Name[1]))
+           if (Char.IsDigit (str[1]))
              return new PredefinedAbsolute (name);
-           if (name.Name.Length == 2 || name == Mat_minus_zero
-               || ! (name.Name[1] == '-' || name.Name[1] == '+'))
+           if (str.Length == 2 || name == Mat_minus_zero
+               || ! (str[1] == '-' || str[1] == '+'))
              throw new Exception ("Invalid marker name: " + name);
            return new PredefinedSurround (name);
          }
@@ -788,13 +803,13 @@ namespace M17N.Input
          group = new object[column];
       }
 
-      public Candidates (List<Xex.Term> list, int column)
+      public Candidates (Xex.Term[] candidates, int column)
       {
-       int nblocks = list.Count;
+       int nblocks = candidates.Length;
 
        blocks = new Block[nblocks];
        for (int i = 0, start = 0; i < nblocks; i++)
-         start += (blocks[i] = new Block (index, list[i])).Count;
+         start += (blocks[i] = new Block (index, candidates[i])).Count;
        if (column > 0)
          group = new object[column];
       }
@@ -979,8 +994,6 @@ namespace M17N.Input
        return selector;
       }
 
-      public override Xex.TermValue Clone () { return this; }
-
       public void Select (Candidates candidates)
       {
        switch (tag)
@@ -999,7 +1012,7 @@ namespace M17N.Input
     internal class Map
     {
       public MSymbol name;
-      public List<Entry> entries;
+      public List<Entry> entries = new List<Entry> ();
 
       public Map (MSymbol name) { this.name = name; }
 
@@ -1015,7 +1028,13 @@ namespace M17N.Input
        }
       }
 
-      public override string ToString () { return (string) name; }
+      public override string ToString ()
+      {
+       string str = "(" + name;
+       foreach (Entry e in entries)
+         str += " " + e.keyseq.ToString ();
+       return str + ")";
+      }
     }
 
     internal class Keymap
@@ -1081,7 +1100,7 @@ namespace M17N.Input
            if (branch_actions != null)
              foreach (Xex.Term term in branch_actions)
                mt.Cat (' ').Cat (term.ToString ());
-           mt.Cat (')');           
+           mt.Cat (')');
          }
        if (submaps != null)
          foreach (KeyValuePair<Key, Keymap> kv in submaps)
@@ -1098,7 +1117,6 @@ namespace M17N.Input
        KeySeq keyseq = new KeySeq ();
 
        describe (mt, keyseq);
-       mt.Cat (')');
        return (string) mt;
       }
     }
@@ -1108,7 +1126,7 @@ namespace M17N.Input
       public Xex.Symbol name;
       public MText title;
       public Xex.Term[] enter_actions, fallback_actions;
-      public Keymap keymap;
+      public Keymap keymap = new Keymap ();
 
       public State (Xex.Symbol name, MText title)
       {
@@ -1122,6 +1140,8 @@ namespace M17N.Input
        XmlAttribute attr = node.Attributes[Qtitle];
        if (attr != null)
          title = (MText) attr.Value;
+       else
+         title = im.title;
        keymap = new Keymap ();
        for (node = node.FirstChild; node != null; node = node.NextSibling)
          {
@@ -1150,9 +1170,11 @@ namespace M17N.Input
        plist = plist.next;
        if (plist.IsMText)
          {
-           this.title = plist.Text;
+           title = plist.Text;
            plist = plist.next;
          }
+       else
+         title = im.title;
        keymap = new Keymap (); 
        for (; ! plist.IsEmpty; plist = plist.next)
          {
@@ -1163,14 +1185,14 @@ namespace M17N.Input
              throw new Exception ("Invalid branch: " + p);
            MSymbol mapname = p.Symbol;
            if (mapname == MSymbol.t)
-             enter_actions = im.parse_actions (p.next);
+             enter_actions = im.parse_actions (p.next, false);
            else if (mapname == MSymbol.nil)
-             fallback_actions = im.parse_actions (p.next);
+             fallback_actions = im.parse_actions (p.next, false);
            else
              {
                Map map;
                if (im.maps.TryGetValue (mapname, out map))
-                 keymap.AddMap (map, im.parse_actions (p.next));
+                 keymap.AddMap (map, im.parse_actions (p.next, false));
                else
                  throw new Exception ("Unknown map: " + mapname);
              }
@@ -1183,16 +1205,16 @@ namespace M17N.Input
 
        if (title != null)
          mt.Cat (" \"" + title + "\"");
-       mt += keymap.ToString ();
+       mt.Cat (keymap.ToString ());
        return (string) mt + ")";
       }
     }
 
     // Instance members
-    internal Xex.Domain domain = new Xex.Domain (im_domain, null);
+    internal Xex.Domain domain;
 
-    private LoadStatus load_status = LoadStatus.None;
-    private MDatabase.Tag tag;
+    protected LoadStatus load_status = LoadStatus.None;
+    protected MDatabase.Tag tag;
     private MDatabase mdb;
 
     private MText description;
@@ -1211,7 +1233,7 @@ namespace M17N.Input
       im_domain.DefTerm ("selector", Selector.parser);
 
       im_domain.DefSubr (Finsert, "insert", false, 1, 1);
-      im_domain.DefSubr (Finsert_candidates, "candidates", false, 1, -1);
+      im_domain.DefSubr (Finsert_candidates, "insert-candidates", false, 1, -1);
       im_domain.DefSubr (Fdelete, "delete", false, 1, 1);
       im_domain.DefSubr (Fselect, "select", false, 1, 1);
       im_domain.DefSubr (Fshow, "show", false, 0, 0);
@@ -1241,6 +1263,7 @@ namespace M17N.Input
     private MInputMethod (MDatabase.Tag tag)
     {
       this.tag = tag;
+      domain = new Xex.Domain (tag[1].Name, im_domain, null);
     }
 
     // Instance Properties
@@ -1292,7 +1315,7 @@ namespace M17N.Input
       return (im_table.TryGetValue (tag, out im) ? im : null);
     }
 
-    public bool Open ()
+    private bool Open ()
     {
       return ((load_status == LoadStatus.Full) || load_body ());
     }
@@ -1356,7 +1379,7 @@ namespace M17N.Input
     private void add_default_state ()
     {
       Xex.Symbol Qinit = "init";
-      State state = new State (Qinit, null);
+      State state = new State (Qinit, title);
       foreach (KeyValuePair<MSymbol, Map>kv in maps)
        state.keymap.AddMap (kv.Value, null);
       states[Qinit] = initial_state = state;
@@ -1464,126 +1487,6 @@ namespace M17N.Input
        add_default_state ();
     }
 
-    private static void transform (MPlist plist)
-    {
-      for (; ! plist.IsEmpty; plist = plist.next)
-       {
-         if (plist.IsMText)
-           {
-             MPlist p = new MPlist ();
-             p.Add (MSymbol.symbol, Minsert);
-             p.Add (MSymbol.mtext, plist.Text);
-             plist.Set (MSymbol.plist, p);
-           }
-         else if (plist.IsInteger)
-           {
-             MPlist p = new MPlist ();
-             p.Add (MSymbol.symbol, Minsert);
-             p.Add (MSymbol.integer, plist.Integer);
-             plist.Set (MSymbol.plist, p);
-           }
-         else if (plist.IsPlist)
-           {
-             MPlist pl = plist.Plist;
-
-             if (pl.IsSymbol)
-               {
-                 if (pl.Symbol == Madd)
-                   pl.Set (MSymbol.symbol, (MSymbol) "+=");
-                 else if (pl.Symbol == Msub)
-                   pl.Set (MSymbol.symbol, (MSymbol) "-=");
-                 else if (pl.Symbol == Mmul)
-                   pl.Set (MSymbol.symbol, (MSymbol) "*=");
-                 else if (pl.Symbol == Mdiv)
-                   pl.Set (MSymbol.symbol, (MSymbol) "/=");
-                 else if (pl.Symbol == Minsert)
-                   {
-                     // (insert (CANDIDATES ...))
-                     //   => (candidates CANDIDATES ...)
-                     if (pl.next.IsPlist)
-                       {
-                         pl.Set (MSymbol.symbol, Mcandidates);
-                         pl = pl.next;
-                         MPlist p = pl.Plist;
-                         pl.Set (p.key, p.val);
-                         for (p = p.next; ! p.IsEmpty; p = p.next);
-                         pl.Add (p.key, p.val);
-                       }
-                   }
-                 else if (pl.Symbol == Mif)
-                   {
-                     pl = pl.next;
-                     if (! pl.IsEmpty)
-                       transform (pl.next);
-                   }
-                 else if (pl.Symbol == Mcond)
-                   {
-                     for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
-                       if (pl.IsPlist)
-                         {
-                           MPlist p = pl.Plist;
-
-                           if (p.IsPlist)
-                             transform (p);
-                           else
-                             transform (p.next);
-                         }
-                   }
-                 else if (pl.Symbol == Mdelete
-                          || pl.Symbol == Mmove
-                          || pl.Symbol == Mmark)
-                   {
-                     pl = pl.next;
-                     if (pl.IsSymbol)
-                       {
-                         MSymbol sym = pl.Symbol;
-                         MPlist p = new MPlist ();
-                         p.Add (MSymbol.symbol, Mmarker);
-                         p.Add (MSymbol.symbol, sym);
-                         pl.Set (MSymbol.plist, p);
-                       }
-                   }
-                 else if (pl.Symbol == Mpushback)
-                   {
-                     pl = pl.next;
-                     if (pl.IsPlist)
-                       pl.Plist.Push (MSymbol.symbol, Mkeyseq);
-                   }
-               }
-             else if (pl.IsMText)
-               {
-                 // (CANDIDATES ...) => (candidates CANDIDATES ...)
-                 pl.Push (MSymbol.symbol, Mcandidates);
-               }
-           }
-         else if (plist.IsSymbol)
-           {
-             MSymbol sym = plist.Symbol;
-
-             if (sym.Name.Length >= 3
-                 && sym.Name[0] == '@'
-                 && (sym.Name[1] == '-' || sym.Name[1] == '+'))
-               {
-                 int pos = int.Parse (sym.Name.Substring (1));
-                 MPlist p = new MPlist ();
-
-                 if (pos == 0)
-                   {
-                     p.Add (MSymbol.symbol, Msurrounding_flag);
-                   }
-                 else
-                   {
-                     if (sym.Name[1] == '+')
-                       pos--;
-                     p.Add (MSymbol.symbol, Mchar_at);
-                     p.Add (MSymbol.integer, pos);
-                   }
-                 plist.Set (MSymbol.plist, p);
-               }
-           }
-       }
-    }
-
     private static MText parse_description (MPlist plist)
     {
       if (plist.IsMText)
@@ -1639,7 +1542,7 @@ namespace M17N.Input
            }
        }
       if (vari == null)
-       domain.Defvar (new Xex.Variable.Int (name, desc, val, range));
+       domain.Defvar (new Xex.Variable.Int (domain, name, desc, val, range));
       else
        {
          Xex.Term term = new Xex.Term (val);
@@ -1668,7 +1571,7 @@ namespace M17N.Input
            }
        }
       if (vari == null)
-       domain.Defvar (new Xex.Variable.Str (name, desc, (string) val, range));
+       domain.Defvar (new Xex.Variable.Str (domain, name, desc, (string) val, range));
       else
        {
          Xex.Term term = new Xex.Term ((string) val);
@@ -1698,7 +1601,7 @@ namespace M17N.Input
            }
        }
       if (vari == null)
-       domain.Defvar (new Xex.Variable.Sym (name, desc, sym, range));
+       domain.Defvar (new Xex.Variable.Sym (domain, name, desc, sym, range));
       else
        {
          Xex.Term term = new Xex.Term (sym);
@@ -1863,6 +1766,8 @@ namespace M17N.Input
          {
            State state = new State (this, plist.Plist);
            states[state.name] = state;     
+           if (initial_state == null)
+             initial_state = state;
          }
     }
 
@@ -1873,6 +1778,8 @@ namespace M17N.Input
          {
            State state = new State (this, node);
            states[state.name] = state;
+           if (initial_state == null)
+             initial_state = state;
          }
     }
 
@@ -1956,10 +1863,13 @@ namespace M17N.Input
          if (! plist.IsPlist)
            throw new Exception ("Invalid cond args: " + plist);
          MPlist p = plist.Plist;
-         List<Xex.Term> arg = new List<Xex.Term> (parse_actions (p));
+         List<Xex.Term> arg = new List<Xex.Term> ();
+         arg.Add (parse_action (p, true));
+         for (p = p.next; ! p.IsEmpty; p = p.next)
+           arg.Add (parse_action (p, false));
          args[i] = new Xex.Term (arg);
        }
-      return new Xex.Term (domain, (Xex.Symbol) Mcond.Name, args);
+      return new Xex.Term (domain, Qcond, args);
     }
 
     private Xex.Term parse_insert (MPlist plist)
@@ -1975,6 +1885,7 @@ namespace M17N.Input
       else if (plist.IsPlist)
        {
          MPlist pl = plist.Plist;
+
          args = new Xex.Term[pl.Count];
          int i;
          for (i = 0; ! pl.IsEmpty; i++, pl = pl.next)
@@ -2015,19 +1926,19 @@ namespace M17N.Input
        args[0] = new Xex.Term (Selector.Get (plist.Symbol));
       else
        args[0] = new Xex.Term (domain, (Xex.Symbol) plist.Symbol.Name);
-      return new Xex.Term (domain, (Xex.Symbol) Mselect.Name, args);
+      return new Xex.Term (domain, Qselect, args);
     }
 
-    private Xex.Term parse_funcall_with_marker (MPlist plist, MSymbol func)
+    private Xex.Term parse_funcall_with_marker (MPlist plist, Xex.Symbol func)
     {
       Xex.Term[] args = new Xex.Term[1];
-      if (plist.IsInteger && func != Mmark)
+      if (plist.IsInteger && func != Qmark)
        args[0] = new Xex.Term (plist.Integer);
       else if (plist.IsSymbol)
        args[0] = new Xex.Term (Marker.Get (plist.Symbol));
       else
        throw new Exception ("Invalid arg to " + func + ": " + plist);
-      return new Xex.Term (domain, (Xex.Symbol) func.Name, args);
+      return new Xex.Term (domain, func, args);
     }
 
     private Xex.Term parse_char_at (MSymbol name)
@@ -2037,53 +1948,82 @@ namespace M17N.Input
       return new Xex.Term (domain, Qchar_at, args);
     }
 
-    private Xex.Term parse_action (MPlist plist)
+    private Xex.Term parse_shift (MPlist plist)
+    {
+      Xex.Term[] args = new Xex.Term[1];
+      if (! plist.IsSymbol)
+       throw new Exception ("Invalid arg to shift: " + plist);
+      args[0] = new Xex.Term ((Xex.Symbol) plist.Symbol.Name);
+      return new Xex.Term (domain, Qshift, args);
+    }
+
+    private Xex.Term parse_action (MPlist plist, bool as_funarg)
     {
       if (plist.IsPlist)
        {
          MPlist p = plist.Plist;
              
          if (p.IsMText || p.IsPlist)
-           return parse_insert (p);
+           return parse_insert (plist);
          if (! p.IsSymbol)
            throw new Exception ("Invalid action: " + p);
-         MSymbol name = p.Symbol;
+         MSymbol sym = p.Symbol;
+         Xex.Symbol name = sym.Name;
          p = p.next;
-         if (name == Mcond)
+         if (name == Qcond)
            return parse_cond (p);
-         if (name == Minsert)
+         if (name == Qinsert)
            return parse_insert (p);
-         if (name == Mselect)
+         if (name == Qselect)
            return parse_select (p);
-         if (name == Mdelete || name == Mmove || name == Mmark)
+         if (name == Qdelete || name == Qmove || name == Qmark)
            return parse_funcall_with_marker (p, name);
-         if (name.Name[0] == '@')
-           return parse_char_at (name);
-         if (name == Mset || name == Madd || name == Msub
-                  || name == Mmul || name == Mdiv)
+         if (name == Qshift)
+           return parse_shift (p);
+         if (((string) name)[0] == '@')
+           return parse_char_at (sym);
+         if (name == Qset || name == Qadd || name == Qsub
+                  || name == Qmul || name == Qdiv)
            {
              if (! p.IsSymbol)
                throw new Exception ("Invalid action: " + p);
              Xex.Symbol varname = p.Symbol.Name;
-             return new Xex.Term (domain, (Xex.Symbol) name.Name,
-                                  varname, parse_actions (p.next));
+             Xex.Term[] args = new Xex.Term[1];
+             args[0] = parse_action (p.next, true);
+             return new Xex.Term (domain, name, varname, args);
            }
          else
-           return new Xex.Term (domain, (Xex.Symbol) name.Name,
-                                parse_actions (p));
+           {
+             if (name == Qeq)
+               name = Qeqeq;
+             if (p.IsEmpty)
+               return new Xex.Term (domain, name, null);
+             else
+               return new Xex.Term (domain, name, parse_actions (p, true));
+           }
        }
-      else if (plist.IsMText || plist.IsInteger || plist.IsSymbol)
-       return parse_insert (plist);
+      else if (plist.IsSymbol)
+       {
+         if (plist.Symbol.Name[0] == '@')
+           return parse_char_at (plist.Symbol);
+         return new Xex.Term (domain, (Xex.Symbol) plist.Symbol.Name);
+       }
+      else if (plist.IsMText)
+       return (as_funarg ? new Xex.Term ((string) plist.Text)
+               : parse_insert (plist));
+      else if (plist.IsInteger)
+       return (as_funarg ? new Xex.Term (plist.Integer)
+               : parse_insert (plist));
       else
        throw new Exception ("Invalid action: " + plist);
     }
 
-    private Xex.Term[] parse_actions (MPlist plist)
+    private Xex.Term[] parse_actions (MPlist plist, bool as_funarg)
     {
       Xex.Term[] terms = new Xex.Term[plist.Count];
 
       for (int i = 0; ! plist.IsEmpty; i++, plist = plist.next)
-       terms[i] = parse_action (plist);
+       terms[i] = parse_action (plist, as_funarg);
       return terms;
     }
 
@@ -2105,9 +2045,8 @@ namespace M17N.Input
 
            if (! p.IsSymbol)
              continue;
-           transform (p.next);
            domain.Defun ((Xex.Symbol) p.Symbol.Name, false, null,
-                         parse_actions (p.next), false);
+                         parse_actions (p.next, false), false);
          }
     }
 
@@ -2135,9 +2074,8 @@ namespace M17N.Input
                else
                  continue;
                p = p.next;
-               if (p.IsEmpty)
-                 continue;
-               Xex.Term[] actions = parse_actions (p);
+               Xex.Term[] actions
+                 = p.IsEmpty ? null : parse_actions (p, false);
                map.entries.Add (new Map.Entry (domain, keys, actions));
              }
          }
@@ -2146,7 +2084,10 @@ namespace M17N.Input
     private static Xex.Term Finsert (Xex.Domain domain, Xex.Variable vari,
                                     Xex.Term[] args)
     {
-      ((Context) domain.context).insert (args[0]);
+      if (args[0].IsInt)
+       ((Context) domain.context).insert (args[0].Intval);
+      else
+       ((Context) domain.context).insert (args[0].Strval);
       return args[0];
     }
 
@@ -2154,7 +2095,11 @@ namespace M17N.Input
                                                Xex.Variable vari,
                                                Xex.Term[] args)
     {
-      ((Context) domain.context).insert_candidates (args[0]);
+      Context ic = (Context) domain.context;
+      Xex.Variable v = ic.domain.GetVar (Qcandidates_group_size, false);
+      int column = (v == null ? 0 : v.Value.Intval);
+
+      ic.insert_candidates (new Candidates (args, column));
       return args[0];
     }
 
@@ -2164,14 +2109,23 @@ namespace M17N.Input
       Context ic = (Context) domain.context;
       Marker m = (Marker) args[0].Objval;
 
-      return new Xex.Term (ic.char_at (m.Position (ic)));
+      return new Xex.Term (m.CharAt (ic));
     }
 
     private static Xex.Term Fdelete (Xex.Domain domain, Xex.Variable vari,
-                                  Xex.Term[] args)
+                                    Xex.Term[] args)
     {
-      ((Context) domain.context).delete ((int) args[0].Intval);
-      return args[0];
+      Context ic = (Context) domain.context;
+      int pos;
+
+      if (args[0].IsInt)
+       pos = args[0].Intval;
+      else
+       {
+         Marker m = (Marker) args[0].Objval;
+         pos = m.Position (ic);
+       }
+      return new Xex.Term (ic.delete (pos));
     }
 
     private static Xex.Term Fselect (Xex.Domain domain, Xex.Variable vari,
@@ -2180,35 +2134,36 @@ namespace M17N.Input
       Candidates can = ((Context) domain.context).candidates;
 
       if (can != null)
-       ((Selector) args[0].Objval).Select (can);
+       {
+         if (args[0].IsInt)
+           can.Select (args[0].Intval);
+         else
+           ((Selector) args[0].Objval).Select (can);
+       }
       return args[0];
     }
 
     private static Xex.Term Fshow (Xex.Domain domain, Xex.Variable vari,
-                                Xex.Term[] args)
+                                  Xex.Term[] args)
     {
       ((Context) domain.context).show ();
       return Tnil;
     }
 
     private static Xex.Term Fhide (Xex.Domain domain, Xex.Variable vari,
-                                Xex.Term[] args)
+                                  Xex.Term[] args)
     {
       ((Context) domain.context).hide ();
       return Tnil;
     }
 
     private static Xex.Term Fmove (Xex.Domain domain, Xex.Variable vari,
-                                Xex.Term[] args)
+                                  Xex.Term[] args)
     {
-      if (args[0].IsInt)
-       ((Context) domain.context).move (args[0].Intval);
-      else
-       {
-         Marker m = (Marker) args[0].Objval;
-         Context ic = (Context) domain.context;
-         ((Context) domain.context).move (m.Position (ic));
-       }
+      Context ic = (Context) domain.context;
+      int pos = (args[0].IsInt ? args[0].Intval
+                : ((Marker) args[0].Objval).Position (ic));
+      ic.move (pos);
       return args[0];
     }
 
@@ -2294,11 +2249,12 @@ namespace M17N.Input
                                               Xex.Variable vari,
                                               Xex.Term[] args)
     {
-      return new Xex.Term (((Context) domain.context).SurroundingFlag);
+      return new Xex.Term (GetSurroundingText == null ? 0 : 1);
     }
 
     public override string ToString ()
     {
+      this.Open ();
       string str = (String.Format ("({0} (title \"{1}\")", tag, title));
       if (commands != null)
        {
@@ -2325,44 +2281,42 @@ namespace M17N.Input
       foreach (KeyValuePair<MSymbol, Map> kv in maps)
        str += " " + kv.Value;
       str += ") (states";
-      foreach (Xex.Symbol name in states.Keys)
-       str += " " + name;
+      foreach (KeyValuePair<Xex.Symbol, State> kv in states)
+       {
+         str += " (" + kv.Key + " " + kv.Value.keymap + ")";
+       }
       return str + "))";
     }
 
     public class Context
     {
-      internal static Xex.Symbol Qcandidates_group_size
-        = "candidates-group-size";
       internal MInputMethod im;
-      private Dictionary<MSymbol, Callback> callbacks
-       = new Dictionary<MSymbol, Callback> ();
-
-      private MText produced;
+      internal Xex.Domain domain;
       private bool active;
+
       private MText status;
-      internal MText preedit;
+      private MText produced = new MText ();
+      internal MText preedit = new MText ();
       internal int cursor_pos;
-      internal MPlist markers;
+      internal MPlist marker_positions = new MPlist ();
+
       internal Candidates candidates;
       private int candidate_from, candidate_to;
       private bool candidate_show;
+      public bool CandidateShow { get { return candidate_show; } }
 
-      private List<State> state_list = new List<State> ();
-      private Keymap keymap;
+      private State state, prev_state;
+      private MText state_preedit = new MText ();
+      private int state_key_head;
+      private object state_var_values, state_initial_var_values;
+      private int state_pos;
 
+      private Keymap keymap;
       // Sequence of input keys.
       internal KeySeq keys = new KeySeq ();
-
       // Index into KEYS specifying the next key to handle.
       internal int key_head;
 
-
-      private int state_key_head;
-      private object state_var_values;
-      private int commit_key_head;
-      private MText state_preedit;
-      private int state_pos;
       internal MText preceding_text = new MText ();
       internal MText following_text = new MText ();
 
@@ -2374,15 +2328,39 @@ namespace M17N.Input
       // 'key_unhandled' is true.
       private Key unhandled_key;
 
-      internal Xex.Domain domain;
-
       internal ChangedStatus changed;
 
-      static MPlist callback_arg = new MPlist ();
+      private void set_cursor (string prefix, int pos)
+      {
+       cursor_pos = pos;
+      }
+
+      internal void reset ()
+      {
+       status = im.initial_state.title;
+       produced.Del ();
+       preedit.Del ();
+
+       set_cursor ("reset", 0);
+       marker_positions.Clear ();
+       candidates = null;
+       candidate_show = false;
+
+       state = prev_state = null;
+       state_preedit.Del ();
+       state_var_values = state_initial_var_values;
+       state_pos = 0;
+       shift (im.initial_state);
+
+       preceding_text.Del ();
+       following_text.Del ();
+
+       changed = ChangedStatus.None;
+      }
 
       static Xex.Term[] catch_args = new Xex.Term[2];
 
-      private bool take_action (Xex.Term[] actions)
+      private bool take_actions (Xex.Term[] actions)
       {
        catch_args[0] = Tcatch_tag;
        catch_args[1]= new Xex.Term (domain, Qprogn, actions);
@@ -2391,22 +2369,17 @@ namespace M17N.Input
        return (! term.IsSymbol || term.Symval != Tcatch_tag.Symval);
       }
 
-
-      private bool call_callback (MSymbol name, MPlist arg)
-      {
-       Callback callback;
-       if (! callbacks.TryGetValue (name, out callback))
-         return false;
-       return callback (this, arg);
-      }
+      static MPlist callback_arg = new MPlist ();
 
       private bool get_surrounding_text (int len)
       {
        if (len < 0 ? -len <= preceding_text.Length
            : len <= following_text.Length)
          return true;
+       if (GetSurroundingText == null)
+         return false;
        callback_arg.Set (MSymbol.integer, len);
-       if (! call_callback (Mget_surrounding_text, callback_arg)
+       if (! GetSurroundingText (this, callback_arg)
            || ! callback_arg.IsMText)
          return false;
        if (len < 0)
@@ -2418,11 +2391,6 @@ namespace M17N.Input
        return (len <= following_text.Length);
       }
 
-      internal int SurroundingFlag
-      {
-       get { return (callbacks.ContainsKey (Mget_surrounding_text) ? 1 : 0); }
-      }
-
       internal int GetSurroundingChar (int pos)
       {
        if (! get_surrounding_text (pos < 0 ? pos : pos + 1))
@@ -2439,21 +2407,16 @@ namespace M17N.Input
                   : ((MText) inserted).Length);
        int diff = ins - (to - from);
 
-       for (MPlist plist = markers; ! plist.IsEmpty; plist = plist.next)
+       for (MPlist p = marker_positions; ! p.IsEmpty; p = p.next)
          {
-           int pos = plist.Integer;
+           int pos = p.Integer;
            if (pos > from)
-             {
-               if (pos >= to)
-                 plist.val = pos + diff;
-               else
-                 plist.val = from;
-             }
+             p.Set (p.Key, pos >= to ? pos + diff : from);
          }
        if (cursor_pos >= to)
-         cursor_pos += diff;
+         set_cursor ("adjust", cursor_pos + diff);
        else if (cursor_pos > from)
-         cursor_pos = from;
+         set_cursor ("adjust", from);
       }
 
       private void preedit_replace (int from, int to, int c)
@@ -2469,12 +2432,15 @@ namespace M17N.Input
        adjust_markers (from, to, mt);
       }
 
-      internal void insert (Xex.Term arg)
+      internal void insert (int c)
       {
-       if (arg.IsInt)
-         preedit_replace (cursor_pos, cursor_pos, arg.Intval);
-       else
-         preedit_replace (cursor_pos, cursor_pos, new MText (arg.Strval));
+       preedit_replace (cursor_pos, cursor_pos, c);
+       changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos;
+      }
+
+      internal void insert (string str)
+      {
+       preedit_replace (cursor_pos, cursor_pos, (MText) str);
        changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos;
       }
 
@@ -2494,19 +2460,14 @@ namespace M17N.Input
          }
        preedit.PushProp (candidate_from, candidate_to,
                          Mcandidates, this);
-       cursor_pos = candidate_from;
+       set_cursor ("update-candidate", candidate_to);
        changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos
                    | CandidateAll);
       }
 
-      internal void insert_candidates (Xex.Term arg)
+      internal void insert_candidates (Candidates candidates)
       {
-       int column = 0;
-       Xex.Variable v = domain.GetVar (Qcandidates_group_size, false);
-
-       if (v != null)
-         column = v.Value.Intval;
-       candidates = new Candidates (arg.Listval, column);
+       this.candidates = candidates;
        candidate_from = candidate_to = cursor_pos;
        update_candidate ();
       }
@@ -2520,105 +2481,55 @@ namespace M17N.Input
          }
       }
 
-      internal int marker (MSymbol sym)
+      internal int delete (int pos)
       {
-       int pos = cursor_pos;
+       int deleted = pos - cursor_pos;
 
-       if (sym.Name.Length == 2 && sym.Name[0] == '@')
+       if (pos < cursor_pos)
          {
-           switch (sym.Name[0])
+           if (pos < 0)
              {
-             case '<': pos = 0; break;
-             case '>': pos = preedit.Length; break;
-             case '-': pos = cursor_pos - 1; break;
-             case '+': pos = cursor_pos + 1; break;
-             case '[':
-               if (pos > 0)
+               if (DeleteSurroundingText != null)
                  {
-                   int to;
-                   preedit.FindProp (Mcandidates, pos - 1,
-                                     out pos, out to);
+                   callback_arg.Set (MSymbol.integer, pos);
+                   if (DeleteSurroundingText (this, callback_arg))
+                     {
+                       if (callback_arg.IsInteger)
+                         deleted = callback_arg.Integer - cursor_pos;
+                       preceding_text.Del ();
+                     }
+                   else
+                     deleted = - cursor_pos;
                  }
-               else
-                 pos = 0;
-               break;
-             case ']':
-               if (cursor_pos < preedit.Length - 1)
-                 {
-                   int from;
-                   preedit.FindProp (Mcandidates, pos,
-                                     out from, out pos);
-                 }
-               else
-                 pos = preedit.Length;
-               break;
-             default:
-               if (sym.Name[0] >= '0' && sym.Name[0] <= '9')
-                 pos = sym.Name[0];
-               break;
+               pos = 0;
              }
-         }
-       else if (sym.Name.Length >= 3 && sym.Name[0] == '@')
-         {
-           pos = int.Parse (sym.Name.Substring (2));
+           if (pos < cursor_pos)
+             preedit_replace (pos, cursor_pos, null);
          }
        else
          {
-           object val = markers.Get (sym);
-
-           if (val is int)
-             pos = (int) val;
-         }
-       return pos;
-      }
-
-      internal int char_at (int pos)
-      {
-       int c;
-
-       pos += cursor_pos;
-       if (pos < 0)
-         {
-           if (preceding_text.Length < -pos)
+           if (pos > preedit.Length)
              {
-               MPlist plist = new MPlist ();
-               plist.Push (MSymbol.integer, pos);
-               if (GetSurroundingText != null
-                   && GetSurroundingText (this, plist)
-                   && plist.IsMText
-                   && preceding_text.Length < plist.Text.Length)
-                 preceding_text = plist.Text;
-             }
-           c = (-pos < preceding_text.Length
-                ? preceding_text[preceding_text.Length + pos] : -1);
-         }
-       else if (pos >= 0 && pos < preedit.Length)
-         c = preedit[pos];
-       else
-         {
-           pos -= preedit.Length;
-           if (pos >= following_text.Length)
-             {
-               MPlist plist = new MPlist ();
-               plist.Push (MSymbol.integer, pos + 1);
-               if (GetSurroundingText != null
-                   && GetSurroundingText (this, plist)
-                   && plist.IsMText
-                   && following_text.Length < plist.Text.Length)
-                 following_text = plist.Text;
+               if (DeleteSurroundingText != null)
+                 {
+                   callback_arg.Set (MSymbol.integer, pos - preedit.Length);
+                   if (DeleteSurroundingText (this, callback_arg))
+                     {
+                       if (callback_arg.IsInteger)
+                         deleted = callback_arg.Integer - cursor_pos;
+                       preceding_text.Del ();
+                     }
+                   else
+                     deleted = preedit.Length - cursor_pos;
+                 }
+               pos = preedit.Length;
              }
-           c = (pos < following_text.Length ? following_text[pos] : -1);
+           if (pos > cursor_pos)
+             preedit_replace (cursor_pos, pos, null);
          }
-       return c;
-      }
-
-      internal void delete (int pos)
-      {
-       if (pos < cursor_pos)
-         preedit_replace (pos, cursor_pos, null);
-       else
-         preedit_replace (cursor_pos, pos, null);
-       changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos;
+       if (deleted != 0)
+         changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos;
+       return deleted;
       }
 
       internal void show ()
@@ -2641,7 +2552,7 @@ namespace M17N.Input
          pos = preedit.Length;
        if (pos != cursor_pos)
          {
-           cursor_pos = pos;
+           set_cursor ("move", pos);
            changed |= ChangedStatus.Preedit;
          }
       }
@@ -2692,80 +2603,69 @@ namespace M17N.Input
       internal void commit ()
       {
        produced.Cat (preedit);
-       preedit.Del ();
+       preedit_replace (0, preedit.Length, null);
        changed |= ChangedStatus.Preedit;
       }
 
       internal void shift (State state)
       {
-       bool changed;
-
        if (state == null)
          {
-           if (state_list.Count > 1)
-             state_list.RemoveAt (state_list.Count - 1);
-           state = state_list[state_list.Count - 1];
-           changed = true;
+           if (prev_state == null)
+             return;
+           state = prev_state;
          }
-       else
-         {
-           changed = state != state_list[state_list.Count - 1];
-           if (changed)
-             state_list.Add (state);
-         }
-       if (state_list.Count == 1)
+
+       if (state == im.initial_state)
          {
            commit ();
-           reset ();
-         }
-       else
-         {
-           state_key_head = key_head;
-           state_pos = cursor_pos;
-           state_preedit = preedit.Dup ();
-           state_var_values = domain.SaveValues ();
-           if (changed)
+           keys.keyseq.RemoveRange (0, key_head);
+           key_head = 0;
+           if (state != this.state)
              {
-               status = state.title;
-               if (status == null)
-                 status = im.title;
-               this.changed |= ChangedStatus.StateTitle;
+               domain.RestoreValues (state_initial_var_values);
                if (state.enter_actions != null)
-                 take_action (state.enter_actions);
+                 take_actions (state.enter_actions);
              }
+           prev_state = null;
          }
-      }
-
-      internal void reset ()
-      {
-       preedit.Del ();
-       state_preedit.Del ();
-       produced.Del ();
-       markers.Clear ();
-       cursor_pos = 0;
-       keys.keyseq.Clear ();
-       key_head = commit_key_head = 0;
-       state_list.Clear ();
-       state_list.Add (im.initial_state);
-       keymap = im.initial_state.keymap;
-       key_head = state_key_head = 0;
-       state_pos = 0;
+       else
+         {
+           if (state != this.state && state.enter_actions != null)
+             take_actions (state.enter_actions);
+           prev_state = this.state;
+         }
+       save_state ();
+       if (this.state == null || this.state.title != state.title)
+         this.changed |= ChangedStatus.StateTitle;
+       this.state = state;
+       keymap = state.keymap;
       }
 
       public Context (MInputMethod im)
       {
+       if (im.load_status != LoadStatus.Full
+           && ! im.Open ())
+         throw new Exception ("Openging " + im.tag + " failed");
        this.im = im;
-       domain = new Xex.Domain (im.domain, this);
+       domain = new Xex.Domain ("context", im.domain, this);
+       state_initial_var_values = domain.SaveValues ();
        reset ();
+       active = true;
+       if (PreeditChanged != null)
+         {
+           callback_arg.Set (MSymbol.mtext, preedit);
+           PreeditChanged (this, callback_arg);
+         }
+       if (StatusChanged != null)
+         {
+           callback_arg.Set (MSymbol.mtext, status);
+           StatusChanged (this, callback_arg);
+         }
       }
 
       public ChangedStatus Changed { get { return changed; } }
 
-      public void AddCallback (MSymbol name, Callback callback)
-      {
-       callbacks[name] = callback;
-      }
-
       internal object GetCandidates (out int column)
       {
        column = 0;
@@ -2779,22 +2679,37 @@ namespace M17N.Input
        return candidates.Current;
       }
 
+      private void save_state ()
+      {
+       state_var_values = domain.SaveValues ();
+       state_preedit.Del ();
+       state_preedit.Ins (0, preedit);
+       state_key_head = key_head;
+       state_pos = cursor_pos;
+      }
+
       private void restore_state ()
       {
+       domain.RestoreValues (state_var_values);
+       preedit.Del ();
+       preedit.Ins (0, state_preedit);
+       set_cursor ("restore", state_pos);
       }
 
       private bool handle_key ()
       {
-       State state = state_list[state_list.Count - 1];
+       Console.Write ("\nHandle ({0}[{1}]) in {2}",
+                      keys, key_head, state.name);
+
        Keymap sub = keymap.Lookup (keys, ref key_head);
 
        if (sub != keymap)
          {
+           restore_state ();
            keymap = sub;
            if (keymap.map_actions != null)
              {
-               restore_state ();
-               if (! take_action (keymap.map_actions))
+               if (! take_actions (keymap.map_actions))
                  return false;
              }
            else if (keymap.submaps != null)
@@ -2807,7 +2722,7 @@ namespace M17N.Input
              {
                if (keymap.branch_actions != null)
                  {
-                   if (! take_action (keymap.branch_actions))
+                   if (! take_actions (keymap.branch_actions))
                      return false;
                  }
                if (keymap != state.keymap)
@@ -2816,12 +2731,14 @@ namespace M17N.Input
          }
        else
          {
+           State current_state = state;
+
            if (keymap.branch_actions != null)
              {
-               if (! take_action (keymap.branch_actions))
+               if (! take_actions (keymap.branch_actions))
                  return false;
              }
-           if (state == state_list[state_list.Count - 1])
+           if (state == current_state)
              {
                if (state == im.initial_state
                    && key_head < keys.keyseq.Count)
@@ -2847,19 +2764,23 @@ namespace M17N.Input
        return key_unhandled;
       }
 
-      public bool Produced (out MText mt)
-      {
-       mt = produced;
-       return (produced.Length > 0);
-      }
+      public MText Preedit { get { return preedit; } }
+      public MText Produced { get { return produced; } }
 
       // Return value:
       //   true: All keys are handled and there's no text to commit.
-      //   false: Some key is unhandled or there's a text to commit.
-      //      The caller should use methods UnhandledKey and Produced.
+      //   false: Some key is left unhandled or there's a text to
+      //      commit.  The caller should refer to UnhandledKey and
+      //      Produced.
 
       public bool Filter (Key key)
       {
+       if (! active)
+         {
+           key_unhandled = true;
+           unhandled_key = key;
+           return false;
+         }
        if (key == Key.Reload)
          return true;
        changed = ChangedStatus.None;
@@ -2878,10 +2799,33 @@ namespace M17N.Input
                key_unhandled = true;
                break;
              }
-           if (++count == 100)
+           if (++count == 10)
              break;
          }
        keys.keyseq.RemoveRange (0, key_head);
+       key_head = 0;
+
+       if ((changed & ChangedStatus.Preedit) != ChangedStatus.None
+           && PreeditChanged != null)
+         {
+           callback_arg.Set (MSymbol.mtext, preedit);
+           PreeditChanged (this, callback_arg);
+         }
+       if ((changed & ChangedStatus.StateTitle) != ChangedStatus.None
+           && StatusChanged != null)
+         {
+           callback_arg.Set (MSymbol.mtext, status);
+           StatusChanged (this, callback_arg);
+         }
+       if ((changed & ChangedStatus.Candidate) != ChangedStatus.None
+           && CandidateChanged != null)
+         {
+           CandidateChanged (this, callback_arg);
+         }
+
+       Console.Write ("\nPreedit(\"{0}\"/{1}), Produced({2})",
+                      preedit, cursor_pos, produced);
+
        return (! key_unhandled && produced.Length == 0);
       }
     }