*** empty log message ***
[m17n/m17n-lib-js.git] / xex.js
diff --git a/xex.js b/xex.js
index 6e4a6f5..542e94d 100644 (file)
--- a/xex.js
+++ b/xex.js
@@ -2,15 +2,19 @@
 
 var Xex = {
   LogNode: null,
-  Log: function (arg, indent)
+  LogSuspended: '',
+  Log: function (arg, indent, suspend)
   {
     if (! Xex.LogNode)
       return;
     if (! arg)
       Xex.LogNode.value = '';
+    else if (suspend)
+      Xex.LogSuspended += arg;
     else
       {
-       var str = '';
+       var str = Xex.LogSuspended;
+       Xex.LogSuspended = '';
        if (indent != undefined)
          for (var i = 0; i <= indent; i++)
            str += '  ';
@@ -249,7 +253,11 @@ Xex.Domain = function (name, parent, context)
       for (elt in parent.functions)
        this.functions[elt] = parent.functions[elt];
       for (elt in parent.variables)
-       this.variables[elt] = parent.variables[elt];
+       {
+         var vari = parent.variables[elt];
+         this.variables[elt] = new Xex.Variable (this, vari.name, vari.desc,
+                                                 vari.val, vari.range);
+       }
     }
 
   this.call_stack = new Array ();
@@ -624,10 +632,9 @@ Xex.Varref = function (vname)
   proto.Clone = function () { return new Xex.Varref (this.val); }
   proto.Eval = function (domain)
   {
-    if (! this.vari || this.vari.domain != domain)
-      this.vari = domain.GetVarCreate (this.val);
-    Xex.Log (this.ToString () + '=>' + this.vari.val, domain.depth);
-    return this.vari.val;
+    var vari = domain.GetVarCreate (this.val);
+    Xex.Log (this.ToString () + '=>' + vari.val, domain.depth);
+    return vari.val;
   }
 
   proto.Parser = function (domain, node)
@@ -645,10 +652,10 @@ Xex.Varref = function (vname)
 
 var null_args = new Array ();
   
-Xex.Funcall = function (func, vari, args)
+Xex.Funcall = function (func, vname, args)
 {
   this.func = func;
-  this.vari = vari;
+  this.vname = vname;
   this.args = args || null_args;
 };
 
@@ -663,18 +670,17 @@ Xex.Funcall = function (func, vari, args)
     if (fname == 'funcall')
       fname = node.attributes['fname'].nodeValue;
     var func = domain.GetFunc (fname);
-    var vari;
+    var vname;
     attr = node.attributes['vname'];
-    vari = attr != undefined ? domain.GetVarCreate (attr.nodeValue) : false;
+    vname = attr != undefined ? attr.nodeValue : null;
     var args = Xex.Term.Parse (domain, node.firstElement (), null);
-    return new Xex.Funcall (func, vari, args);
+    return new Xex.Funcall (func, vname, args);
   }
 
   proto.New = function (domain, fname, vname, args)
   {
     var func = domain.GetFunc (fname);
-    var vari = vname ? domain.GetVarCreate (vname) : null;
-    var funcall = new Xex.Funcall (func, vari, args);
+    var funcall = new Xex.Funcall (func, vname, args);
     if (func instanceof Xex.Macro)
       funcall = funcall.Eval (domain);
     return funcall;
@@ -684,10 +690,13 @@ Xex.Funcall = function (func, vari, args)
   {
     if (! (this.func instanceof Xex.Subrountine))
       Xex.Log (this, domain.depth);
+    var vari;
+    if (this.vname)
+      vari = domain.GetVarCreate (this.vname);
     domain.depth++;
     var result;
     try {
-      result = this.func.Call (domain, this.vari, this.args);
+      result = this.func.Call (domain, vari, this.args);
     } finally {
       Xex.Log (this + ' => ' + result, --domain.depth);
     }
@@ -803,7 +812,7 @@ Xex.StrTerm = function (str) { this.val = str; };
   proto.Clone = function () { return new Xex.StrTerm (this.val); }
   proto.Parser = function (domain, node)
   {
-    return new Xex.StrTerm (node.firstChild.nodeValue);
+    return new Xex.StrTerm (node.firstChild ? node.firstChild.nodeValue : '');
   }
   Xex.StrTerm.prototype = proto;
 }) ();
@@ -871,6 +880,11 @@ Xex.LstTerm = function (list) { this.val = list; };
     return args[0];
   }
 
+  function Fnot (domain, vari, args)
+  {
+    return (args[0].IsTrue () ? Xex.Zero : Xex.One);
+  }
+
   function maybe_set_intvar (vari, n)
   {
     var term = new Xex.IntTerm (n);
@@ -948,6 +962,39 @@ Xex.LstTerm = function (list) { this.val = list; };
     return maybe_set_intvar (vari, n);
   }
 
+  function Flogand (domain, vari, args)
+  {
+    var n, i;
+    if (vari == null)
+      {
+       Xex.Log ("logand arg args[0]" + args[0]);
+       n = args[0].Intval ()
+       i = 1;
+      }
+    else
+      {
+       Xex.Log ("logand arg var " + vari);
+       n = vari.val.Intval ();
+       i = 0;
+      }
+    while (n > 0 && i < args.length)
+      {
+       Xex.Log ("logand arg " + args[i]);
+       n &= args[i++].val;
+      }
+    return maybe_set_intvar (vari, n);
+  }
+
+  function Flsh (domain, vari, args)
+  {
+    return maybe_set_intvar (vari, args[0].Intval () << args[1].Intval ());
+  }
+
+  function Frsh (domain, vari, args)
+  {
+    return maybe_set_intvar (vari, args[0].Intval () >> args[1].Intval ());
+  }
+
   function Fand (domain, vari, args)
   {
     var len = args.length;
@@ -984,13 +1031,18 @@ Xex.LstTerm = function (list) { this.val = list; };
     return Xex.One;
   }
 
+  function Fnoteq (domain, vari, args)
+  {
+    return (Feq (domain, vari, args) == Xex.One ? Xex.Zero : Xex.One);
+  }
+
   function Flt (domain, vari, args)
   {
-    var n = args[0].Intval;
+    var n = args[0].Intval ();
 
     for (var i = 1; i < args.length; i++)
       {
-       var n1 = args[i].Intval;
+       var n1 = args[i].Intval ();
        if (n >= n1)
          return Xex.Zero;
        n = n1;
@@ -1000,10 +1052,10 @@ Xex.LstTerm = function (list) { this.val = list; };
 
   function Fle (domain, vari, args)
   {
-    var n = args[0].Intval;
+    var n = args[0].Intval ();
     for (var i = 1; i < args.length; i++)
       {
-       var n1 = args[i].Intval;
+       var n1 = args[i].Intval ();
        if (n > n1)
          return Xex.Zero;
        n = n1;
@@ -1013,10 +1065,10 @@ Xex.LstTerm = function (list) { this.val = list; };
 
   function Fgt (domain, vari, args)
   {
-    var n = args[0].Intval;
+    var n = args[0].Intval ();
     for (var i = 1; i < args.length; i++)
       {
-       var n1 = args[i].Intval;
+       var n1 = args[i].Intval ();
        if (n <= n1)
          return Xex.Zero;
        n = n1;
@@ -1026,10 +1078,10 @@ Xex.LstTerm = function (list) { this.val = list; };
 
   function Fge (domain, vari, args)
   {
-    var n = args[0].Intval;
+    var n = args[0].Intval ();
     for (var i = 1; i < args.Length; i++)
       {
-       var n1 = args[i].Intval;
+       var n1 = args[i].Intval ();
        if (n < n1)
          return Xex.Zero;
        n = n1;
@@ -1158,8 +1210,8 @@ Xex.LstTerm = function (list) { this.val = list; };
 
   basic.DefSubr (Fset, "set", true, 1, 1);
   basic.DefAlias ("=", "set");
-  //basic.DefSubr (Fnot, "not", false, 1, 1);
-  //basic.DefAlias ("!", "not");
+  basic.DefSubr (Fnot, "not", false, 1, 1);
+  basic.DefAlias ("!", "not");
   basic.DefSubr (Fadd, "add", true, 1, -1);
   basic.DefSubr (Fmul, "mul", true, 1, -1);
   basic.DefAlias ("*", "mul");
@@ -1171,16 +1223,16 @@ Xex.LstTerm = function (list) { this.val = list; };
   basic.DefAlias ("%", "mod");
   basic.DefSubr (Flogior, "logior", true, 1, -1);
   basic.DefAlias ('|', "logior");
-  //basic.DefSubr (Flogand, "logand", true, 1, -1);
-  //basic.DefAlias ("&", "logand");
-  //basic.DefSubr (Flsh, "lsh", true, 1, 2);
-  //basic.DefAlias ("<<", "lsh");
-  //basic.DefSubr (Frsh, "rsh", true, 1, 2);
-  //basic.DefAlias (">>", "rsh");
+  basic.DefSubr (Flogand, "logand", true, 1, -1);
+  basic.DefAlias ("&", "logand");
+  basic.DefSubr (Flsh, "lsh", true, 1, 2);
+  basic.DefAlias ("<<", "lsh");
+  basic.DefSubr (Frsh, "rsh", true, 1, 2);
+  basic.DefAlias (">>", "rsh");
   basic.DefSubr (Feq, "eq", false, 2, -1);
   basic.DefAlias ("==", "eq");
-  //basic.DefSubr (Fnoteq, "noteq", false, 2, 2);
-  //basic.DefAlias ("!=", "noteq");
+  basic.DefSubr (Fnoteq, "noteq", false, 2, 2);
+  basic.DefAlias ("!=", "noteq");
   basic.DefSubr (Flt, "lt", false, 2, -1);
   basic.DefAlias ("<", "lt");
   basic.DefSubr (Fle, "le", false, 2, -1);
@@ -1344,7 +1396,9 @@ var MIM = {
   {
     this.key;
     this.has_modifier = false;
-    if (typeof val == 'string' || val instanceof String)
+    if (val instanceof Xex.Term)
+      this.key = val.val;
+    else if (typeof val == 'string' || val instanceof String)
       {
        this.key = decode_keysym (val);
        if (! this.key)
@@ -1362,6 +1416,10 @@ var MIM = {
   }
 
   MIM.Key.prototype.toString = function () { return this.key; };
+
+  MIM.Key.FocusIn = new MIM.Key (new Xex.StrTerm ('input-focus-in'));
+  MIM.Key.FocusOut = new MIM.Key (new Xex.StrTerm ('input-focus-out'));
+  MIM.Key.FocusMove = new MIM.Key (new Xex.StrTerm ('input-focus-move'));
 }) ();
 
 (function () {
@@ -1377,12 +1435,14 @@ var MIM = {
            var len = seq.val.length;
            for (var i = 0; i < len; i++)
              {
-               var v = seq.val[i];
-               if (v.type != 'string' && v.type != 'integer'
-                   && v.type != 'symbol')
+               var v = seq.val[i], key;
+               if (v.type == 'symbol' || v.type == 'string')
+                 key = new MIM.Key (v);
+               else if (v.type == 'integer')
+                 key = new MIM.Key (v.val);
+               else
                  throw new Xex.ErrTerm (MIM.Error.ParseError,
                                         "Invalid key: " + v);
-               var key = new MIM.Key (v.val);
                this.val.push (key);
                if (key.has_modifier)
                  this.has_modifier = true;
@@ -1528,7 +1588,7 @@ var MIM = {
        var n = predefined[name];
        if (n)
          return n;
-       if (name.charAt (1) == '-')
+       if (name.charAt (1) == '-' || name.charAt (1) == '+')
          return new MIM.SurroundMarker (name);
        throw new Xex.ErrTerm (MIM.Error.ParseError,
                               "Invalid marker: " + name);
@@ -1989,7 +2049,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
   {
     var ic = domain.context;
     var gsize = domain.variables['candidates_group_size'];
-    var candidates = new MIM.Candidates (args, gsize ? gsize.Intval : 0);
+    var candidates = new MIM.Candidates (args, gsize ? gsize.Intval () : 0);
     ic.ins (candidates.Current (), candidates);
     return args[0];
   }
@@ -1997,7 +2057,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
   function Fdelete (domain, vari, args)
   {
     var ic = domain.context;
-    var pos = args[0].IsInt ? args[0].Intval : args[0].Position (ic);
+    var pos = args[0].IsInt ? args[0].Intval () : args[0].Position (ic);
     return new Xex.IntTerm (ic.del (pos));
   }
 
@@ -2017,6 +2077,20 @@ MIM.im_domain.DefType (MIM.State.prototype);
     return args[0];
   }
 
+  function Fshow (domain, vari, args)
+  {
+    domain.context.candidate_show = true;
+    domain.context.changed |= MIM.ChangedStatus.CandidateShow;
+    return Xex.nil;
+  }
+
+  function Fhide (domain, vari, args)
+  {
+    domain.context.candidate_show = false;
+    domain.context.changed |= MIM.ChangedStatus.CandidateShow;
+    return Xex.nil;
+  }
+
   function Fchar_at (domain, vari, args)
   {
     return new Xex.IntTerm (args[0].CharAt (domain.context));
@@ -2045,14 +2119,23 @@ MIM.im_domain.DefType (MIM.State.prototype);
     return args[0];
   }
 
+  function Fpop (domain, vari, args)
+  {
+    var ic = domain.context;
+    if (ic.key_head < ic.keys.val.length)
+      ic.keys.val.splice (ic.keys_head, 1);
+    return Xex.nil;
+  }
+
   function Fundo  (domain, vari, args)
   {
     var ic = domain.context;
     var n = args.length == 0 ? -2 : args[0].val;
+    Xex.Log ('undo with arg ' + args[0]);
     if (n < 0)
-      ic.keys.val.splice (ic.keys.length + n, -n);
+      ic.keys.val.splice (ic.keys.val.length + n, -n);
     else
-      ic.keys.val.splice (n, ic.keys.length);
+      ic.keys.val.splice (n, ic.keys.val.length);
     ic.reset ();
     return Xex.nil;
   }
@@ -2064,10 +2147,10 @@ MIM.im_domain.DefType (MIM.State.prototype);
   }
 
   function Funhandle (domain, vari, args)
-    {
-      domain.context.commit ();
-      return Xex.Fthrow (domain, vari, Xex.CatchTag._mimtag);
-    }
+  {
+    domain.context.commit ();
+    return Xex.Fthrow (domain, vari, Xex.CatchTag._mimtag);
+  }
 
   function Fshift (domain, vari, args)
   {
@@ -2080,6 +2163,17 @@ MIM.im_domain.DefType (MIM.State.prototype);
     return args[0];
   }
 
+  function Fshiftback (domain, vari, args)
+  {
+    domain.context.shift (null);
+    return Xex.nil;
+  }
+
+  function Fkey_count (domain, vari, args)
+  {
+    return new Xex.IntTerm (domain.context.key_head);
+  }
+
   function Fsurrounding_flag (domain, vari, args)
   {
     return new Xex.IntTerm (-1);
@@ -2089,19 +2183,19 @@ MIM.im_domain.DefType (MIM.State.prototype);
   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-candidates", false, 0, 0);
-  //im_domain.DefSubr (Fhide, "hide-candidates", false, 0, 0);
+  im_domain.DefSubr (Fshow, "show-candidates", false, 0, 0);
+  im_domain.DefSubr (Fhide, "hide-candidates", false, 0, 0);
   im_domain.DefSubr (Fmove, "move", false, 1, 1);
   im_domain.DefSubr (Fmark, "mark", false, 1, 1);
   im_domain.DefSubr (Fpushback, "pushback", false, 1, 1);
-  //im_domain.DefSubr (Fpop, "pop", false, 0, 0);
+  im_domain.DefSubr (Fpop, "pop", false, 0, 0);
   im_domain.DefSubr (Fundo, "undo", false, 0, 1);
   im_domain.DefSubr (Fcommit, "commit", false, 0, 0);
   im_domain.DefSubr (Funhandle, "unhandle", false, 0, 0);
   im_domain.DefSubr (Fshift, "shift", false, 1, 1);
-  //im_domain.DefSubr (Fshiftback, "shiftback", false, 0, 0);
+  im_domain.DefSubr (Fshiftback, "shiftback", false, 0, 0);
   im_domain.DefSubr (Fchar_at, "char-at", false, 1, 1);
-  //im_domain.DefSubr (Fkey_count, "key-count", false, 0, 0);
+  im_domain.DefSubr (Fkey_count, "key-count", false, 0, 0);
   im_domain.DefSubr (Fsurrounding_flag, "surrounding-text-flag", false, 0, 0);
 }) ();
 
@@ -2207,8 +2301,8 @@ MIM.im_domain.DefType (MIM.State.prototype);
                alert ('inclusion fail');
                continue;
              }
-           for (var mapname in im.map_list)
-             this.map_list[mapname] = im.map_list[mapname];
+           for (var mname in im.map_list)
+             this.map_list[mname] = im.map_list[mname];
          }
        else
          {
@@ -2222,7 +2316,20 @@ MIM.im_domain.DefType (MIM.State.prototype);
     this.domain.map_list = this.map_list;
     for (node = node.firstElement (); node; node = node.nextElement ())
       {
-       if (node.nodeName == 'state')
+       if (node.nodeName == 'xi:include')
+         {
+           var im = include (node);
+           if (! im)
+             alert ('inclusion fail');
+           for (var sname in im.state_list)
+             {
+               state = im.state_list[sname];
+               if (! this.initial_state)
+                 this.initial_state = state;
+               this.state_list[sname] = state;
+             }
+         }
+       else if (node.nodeName == 'state')
          {
            var state = Xex.Term.Parse (this.domain, node);
            if (! state.title)
@@ -2351,9 +2458,9 @@ MIM.im_domain.DefType (MIM.State.prototype);
     ic.candidate_table.clear ();
     ic.candidates = null;
     ic.changed |= (MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos
-                  | ChangedStatus.CandidateList
-                  | ChangedStatus.CandidateIndex
-                  | ChangedStatus.CandidateShow);
+                  | MIM.ChangedStatus.CandidateList
+                  | MIM.ChangedStatus.CandidateIndex
+                  | MIM.ChangedStatus.CandidateShow);
   }
 
   function set_cursor (prefix, pos)
@@ -2383,14 +2490,13 @@ MIM.im_domain.DefType (MIM.State.prototype);
     var sub = out.map;
 
     Xex.Log ('handling ' + this.keys.val[this.key_head]
-            + ' in ' + this.state.name + ':' + this.keymap.name);
+            + ' in ' + this.state.name + ':' + this.keymap.name, 0, true);
     this.key_head = out.index;
     if (sub != this.keymap)
       {
-
+       Xex.Log (' with submap');
        restore_state.call (this);
        this.keymap = sub;
-       Xex.Log ('submap found');
        if (this.keymap.map_actions)
          {
            Xex.Log ('taking map actions:');
@@ -2421,7 +2527,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
       }
     else
       {
-       Xex.Log ('no submap');
+       Xex.Log (' without submap');
        var current_state = this.state;
        var map = this.keymap;
 
@@ -2462,7 +2568,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
       this.state_var_values = {};
       this.state_pos = 0;
       this.key_head = 0;
-      this.keys.val.length = 0;
+      this.commit_key_head = 0;
       this.key_unhandled = false;
       this.unhandled_key = null;
       this.changed = MIM.ChangedStatus.None;
@@ -2679,6 +2785,9 @@ MIM.im_domain.DefType (MIM.State.prototype);
        this.candidate_table.clear ();
        this.produced += this.preedit;
        this.preedit_replace.call (this, 0, this.preedit.length, '', null);
+       this.preedit_saved = '';
+       this.state_pos = 0;
+       this.commit_key_head = this.key_head;
       }
     },
 
@@ -2740,6 +2849,10 @@ MIM.im_domain.DefType (MIM.State.prototype);
                  this.unhandled_key = this.keys.val[this.key_head];
                  this.keys.val.splice (this.key_head, this.key_head + 1);
                }
+             if (this.state_key_head > 0)
+               this.state_key_head--;
+             if (this.commit_key_head > 0)
+               this.commit_key_head--;
              this.key_unhandled = true;
              break;
            }
@@ -2750,14 +2863,23 @@ MIM.im_domain.DefType (MIM.State.prototype);
              break;
            }
        }
+      if (this.keymap == this.initial_state.keymap)
+       this.commit ();
+
+      if (this.commit_key_head > 0)
+       {
+         this.keys.val.splice (0, this.commit_key_head);
+         this.key_head -= this.commit_key_head;
+         this.state_key_head -= this.commit_key_head;
+         this.commit_key_head = 0;
+       }
       if (this.key_unhandled)
        {
          this.keys.val.length = 0;
          this.key_head = this.state_key_head = this.commit_key_head = 0;
        }
       return (! this.key_unhandled
-             && this.produced.length == 0
-             && this.preedit.length == 0);
+             && this.produced.length == 0);
     }
   }
 
@@ -2848,20 +2970,23 @@ MIM.im_domain.DefType (MIM.State.prototype);
       {
        if (modifiers[key])
          return false;
+       var mod = '';
+       if (event.ctrlKey) mod += 'C-';
+       if (event.metaKey) mod += 'M-';
+       if (event.altKey) mod += 'A-';
        var keysym = keyids[key];
        if (keysym)
          key = keysym;
        else if (key.match(/^U\+([0-9A-Z]+)$/))
-         key = String.fromCharCode (parseInt (RegExp.$1, 16));
+         {
+           if (mod.length == 0)
+             return false;
+           key = String.fromCharCode (parseInt (RegExp.$1, 16));
+         }
        else
          key = key.toLowerCase ();
-       if (event.shiftKey) key = "S-" + key ;
-       if (event.altKey) key = "A-" + key ;
-       if (event.metaKey) key = "M-" + key ;
-       if (event.ctrlKey) key = "C-" + key ;
-       if (key.length == 1)
-         return false;
-       return new MIM.Key (key);
+       if (event.shiftKey) mod += 'S-';
+       return new MIM.Key (mod + key);
       }
     else
       {
@@ -2985,6 +3110,8 @@ MIM.set_caret = function (target, ic)
     }
 };
 
+MIM.ignore_focus = false;
+
 MIM.update = function (target, ic)
 {
   var text = target.value;
@@ -2997,15 +3124,68 @@ MIM.update = function (target, ic)
   MIM.set_caret (target, ic);
 };
 
-MIM.reset_ic = function (event)
+MIM.focus_in = function (event)
 {
-  if (event.target.mim_ic)
+  var target = event.target;
+  var ic = target.mim_ic;
+  if (ic)
     {
-      var target = event.target;
-      var ic = target.mim_ic;
-      if (ic.preedit.length > 0)
-       event.target.setSelectionRange (ic.range[1], ic.range[1]);
-      ic.reset ();
+      if (target.mim_ignore_focus_in)
+       {
+         Xex.Log ('ignore focus_in in ' + target.tagName);
+         // Ignore this event which is caused by setSelectionRange ().
+         target.mim_ignore_focus_in = false;
+         event.preventDefault ();
+       }
+      else
+       {
+         Xex.Log ('focus_in in ' + target.tagName);
+         try {
+           ic.Filter (MIM.Key.FocusIn);
+           MIM.update (target, ic);
+           // Ignore further focus-in caused by setSelectionRange ().
+           // target.mim_ignore_focus_in = true;
+         }
+         catch (e) { Xex.Log ('Error:' + e); throw (e); }
+       }
+    }
+}
+
+MIM.cancel_ignore_focus = function ()
+{
+  if (MIM.focus_ignore_target)
+    {
+      MIM.focus_ignore_target.mim_ignore_focus_in = false;
+      MIM.focus_ignore_target.mim_ignore_focus_out = false;
+    }
+}
+
+MIM.focus_out = function (event)
+{
+  var target = event.target;
+  var ic = target.mim_ic;
+  if (ic)
+    {
+      if (target.mim_ignore_focus_out)
+       {
+         Xex.Log ('ignore focus_out in ' + target.tagName);
+         // Ignore this event which is caused by setSelectionRange ().
+         target.mim_ignore_focus_out = false;
+         event.preventDefault ();
+       }
+      else
+       {
+         Xex.Log ('focus_out in ' + target.tagName);
+         if (! MIM.get_range (target, ic))
+           ic.reset ();
+         ic.Filter (MIM.Key.FocusOut);
+         // Ignore further focus-out caused by setSelectionRange ().
+         target.mim_ignore_focus_in = true;
+         target.mim_ignore_focus_out = true;
+         MIM.focus_ignore_target = target;
+         MIM.update (target, ic);
+         setTimeout (MIM.cancel_ignore_focus, 100);
+       }
     }
 };
 
@@ -3016,6 +3196,7 @@ MIM.keydown = function (event)
     return;
   if (! (target.type == "text" || target.type == "textarea"))
     return;
+  document.akey = event;
 
   var ic = target.mim_ic;
   if (! ic || ic.im != MIM.current)
@@ -3026,7 +3207,8 @@ MIM.keydown = function (event)
       if (ic.im.load_status != MIM.LoadStatus.Loaded)
        return;
       target.mim_ic = ic;
-      MIM.add_event_listener (target, 'blur', MIM.reset_ic);
+      MIM.add_event_listener (target, 'focus', MIM.focus_in);
+      MIM.add_event_listener (target, 'blur', MIM.focus_out);
       MIM.get_range (target, ic)
     }
   else
@@ -3039,7 +3221,12 @@ MIM.keydown = function (event)
   if (ic.key)
     {
       Xex.Log ("filtering " + ic.key);
-      var result = ic.Filter (ic.key);
+      try {
+       var result = ic.Filter (ic.key);
+      } catch (e) {
+       Xex.Log ('Error' + e);
+       throw (e);
+      }
       MIM.update (target, ic);
       if (! ic.key_unhandled)
        event.preventDefault ();
@@ -3069,7 +3256,12 @@ MIM.keypress = function (event)
       }
     
     Xex.Log ("filtering " + ic.key);
-    var result = ic.Filter (ic.key);
+    try {
+      var result = ic.Filter (ic.key);
+    } catch (e) {
+      Xex.Log ('Error;' + e);
+      throw (e);
+    }
     MIM.update (target, ic);
     if (! ic.key_unhandled)
       event.preventDefault ();
@@ -3335,7 +3527,7 @@ MIM.keypress = function (event)
     MIM.add_event_listener (window, 'mousedown', create_menu);
     if (window.location == 'http://localhost/mim/index.html')
       MIM.server = 'http://localhost/mim';
-    MIM.current = MIM.imlist['vi']['telex'];
+    MIM.current = MIM.imlist['zh']['tonepy'];
   };
 }) ();