*** empty log message ***
[m17n/m17n-lib-js.git] / mim.js
diff --git a/mim.js b/mim.js
index d206d76..be5bf7b 100644 (file)
--- a/mim.js
+++ b/mim.js
@@ -1,22 +1,26 @@
 // -* coding: utf-8; -*
 
-/* URL to scan JavaScript files defining MIM (M17N Input Method).  */
-var MIM_url = "http://www.m17n.org/common/mim-js";
-
-/* Boolean flag to tell if MIM is active or not.  */
-var MIM_enabled = true;
-
-var MIM_current_im;
-
-var MIM_list = new Array ();
-
-function M17N_im (url, lang, name)
+var MIM = {};
+
+// URL of the input method server.
+MIM.server = "http://www.m17n.org/common/mim-js",
+// Boolean flag to tell if MIM is active or not.
+MIM.enabled = true;
+// Boolean flag to tell if MIM is running in debug mode or not.
+MIM.debug = false;
+// List of registered input methods.
+MIM.list = new Array ();
+// Currently selected input method.
+MIM.current_im = false;
+
+MIM.im = function (lang, name, filename)
 {
   this.status = 0; /* 0: not-yet-loaded, 1:loading, 2:loaded, -1:error */
-  this.url = url;
+  this.url = MIM.server + "/" + filename;
   this.lang = lang;
   this.name = name;
   this.keymap = false;
+  this.body = null;
 
   function add_keystring (map, keystring, str)
   {
@@ -25,30 +29,30 @@ function M17N_im (url, lang, name)
     var intermediate_string = "";
 
     for (i = 0; i < keystring.length; i++)
-      {
-       c = keystring.charAt (i);
-       if (c in map)
-         {
-           map = map[c];
-           if ('_target_text' in map)
-             intermediate_string = map['_target_text'];
-           else
-             intermediate_string += c;
-         }
-       else
-         {
-           newmap = new Array ();
-           map[c] = newmap;
-           map['_has_child'] = true;
-           map = newmap;
+    {
+      c = keystring.charAt (i);
+      if (c in map)
+        {
+         map = map[c];
+         if ('_target_text' in map)
+           intermediate_string = map['_target_text'];
+         else
            intermediate_string += c;
-           map['_target_text'] = intermediate_string;
-         }
-      }
+       }
+      else
+        {
+         newmap = new Array ();
+         map[c] = newmap;
+         map['_has_child'] = true;
+         map = newmap;
+         intermediate_string += c;
+         map['_target_text'] = intermediate_string;
+       }
+    }
     map['_target_text'] = str;
   }
 
-  function lookup_keyseq (keyseq, limit)
+  this.lookup = function (keyseq, limit)
   {
     var map = this.keymap;
 
@@ -64,56 +68,141 @@ function M17N_im (url, lang, name)
     return map;
   }
 
-  function load_map (mapdef)
+  this.load_map = function (mapdef)
   {
     this.keymap = new Array ();
     for (var keystring in mapdef)
       add_keystring (this.keymap, keystring, mapdef[keystring]);
   }
 
-  this.load_mapdef = load_map;
-  this.lookup = lookup_keyseq;
+  this.load_map_node = function ()
+  {
+    this.keymap = new Array ();
+    var maps = this.body.getElementsByTagName ('map');
+    var map = maps[0];
+    var rules = map.getElementsByTagName ('rule');
+    for (var i = 0; i < rules.length; i++)
+      {
+       var rule = rules[i];
+       var keyseq_elm = MIM.first_element (rule);
+       var keystring = keyseq_elm.attributes[0].nodeValue;
+       var insert_elm = MIM.next_element (rule);
+       var str = insert_elm.attributes[0].nodeValue;
+       add_keystring (this.keymap, keystring, str);
+      }
+  }
+};
+
+MIM.error_return = function (msg, ret)
+{
+  alert (msg);
+  return ret;
 }
 
-function MIM_register (url, lang, name)
+MIM.first_element = function (node)
 {
-  var im = new M17N_im (url, lang, name);
-  if (! (lang in MIM_list))
-    MIM_list[lang] = new Array ();
-  MIM_list[lang][name] = im;
-  return im;
+  node.mim_index = 0;
+  return MIM.next_element (node);
 }
 
-function MIM_find (lang, name)
+MIM.next_element = function (node)
 {
-  if (! (lang in MIM_list))
-    return false;
-  if (! (name in MIM_list[lang]))
-    return false;
-  return MIM_list[lang][name];
+  var element = node.childNodes[node.mim_index++];
+  while (element && element.nodeType != 1)
+    element = node.childNodes[node.mim_index++];
+  return element;
 }
 
+MIM.check_map = function (im, map)
+{
+  var rules = map.getElementsByTagName ('rule');
+  var len = rules.length;
+  
+  for (var i = 0; i < len; i++)
+    {
+      var rule = rules[i];
+      var elm = MIM.first_element (rule);
+
+      if (!elm || elm.nodeName != 'keyseq')
+       return false;
+      while ((elm = MIM.next_element (rule)))
+       if (elm.nodeName != 'insert')
+         return false;
+    }
+  return true;
+}
 
-function MIM_load_async (im)
+MIM.check_state = function (im, state)
+{
+  var branches = state.getElementsByTagName ('branch');
+  var len = branches.length;
+
+  for (var i = 0; i < len; i++)
+    {
+      var branch = branches[i];
+      var elm = MIM.first_element (branch);
+
+      if (elm)
+       return false;
+    }
+  return true;
+}
+
+MIM.parse = function (im)
+{
+  var maps = im.body.getElementsByTagName ('map');
+  var states = im.body.getElementsByTagName ('state');
+  var str = "";
+  var i;
+
+  if (! maps || maps.length == 0)
+    MIM.error_return ('No map', false);
+  if (! states)
+    MIM.error_return ('No state', false);
+  for (i = 0; i < maps.length; i++)
+    if (! MIM.check_map (im, maps[i]))
+      MIM.error_return ('Unsupported directive in map', false);
+  for (var i = 0; i < states.length; i++)
+    if (! MIM.check_state (im, states[i]))
+      MIM.error_return ('Unsupported directive in state', false);
+  im.load_map_node ();
+  return true;
+}
+
+MIM.register = function (lang, name, url)
+{
+  var im = new MIM.im (lang, name, url);
+  if (! (lang in MIM.list))
+    MIM.list[lang] = new Array ();
+  MIM.list[lang][name] = im;
+  return im;
+};
+
+MIM.find = function (lang, name)
+{
+  if (! (lang in MIM.list))
+    return false;
+  if (! (name in MIM.list[lang]))
+    return false;
+  return MIM.list[lang][name];
+};
+
+MIM.load_async = function (im)
 {
-  var filename = MIM_url + "/" + im.url;
   var obj = (window.XMLHttpRequest ? new XMLHttpRequest ()
             : window.ActiveXObject ? new ActiveXObject ("Msxml2.XMLHTTP")
             : null);
 
   if (! obj)
     alert ("XMLHttpRequest not supported");
-  alert ("loading " + filename);
-  obj.open ('GET', filename, true);
+  obj.open ('GET', im.url, true);
   im.status = 1; /* loading */
   obj.onreadystatechange = function () { 
-    alert (obj.readyState + ":" + obj.statusText);
     if (obj.readyState == 4)
       {
        try {
          eval (obj.responseText);
          im.status = 2; /* loaded */
-         alert ("loaded:"+obj.responseXML);
        } catch (e) {
          alert ("load error:" + e.message + " at " + e.lineNumber
                 + " " + obj.responseText);
@@ -123,56 +212,95 @@ function MIM_load_async (im)
   };
   obj.send (null);
   return im;
-}
+};
 
-function MIM_load (im)
+MIM.load_sync = function (im)
+{
+  var obj = (window.XMLHttpRequest ? new XMLHttpRequest ()
+            : window.ActiveXObject ? new ActiveXObject ("Msxml2.XMLHTTP")
+            : null);
+
+  if (! obj)
+    alert ("XMLHttpRequest not supported");
+  if (true)
+    {
+      obj.open ('GET', im.url, false);
+      obj.send ("");  
+      eval (obj.responseText);
+      if (! im.keymap)
+       alert ("obj.responseText");
+      return im;
+    }
+  else
+    {
+      obj.open ('GET', 'latn-post.mimx', false);
+      obj.overrideMimeType ('text/xml');
+      obj.send ("");
+      im.body = obj.responseXML;
+      document.AnXml = im.body;
+      if (MIM.parse (im))
+       return im;
+      alert (im.parse_error);
+    }
+  return false;
+};
+
+MIM.load = function (im)
 {
-  var filename = MIM_url + "/" + im.url;
   var s = document.createElement ('script');
 
   s.charset = 'UTF-8';
-  s.src = filename;
+  s.src = im.url;
   document.body.appendChild (s);
-  alert (s.innerText);
-  //document.body.removeChild (s);
+  document.body.removeChild (s);
+  if (! im.keymap)
+    alert ("load fail");
   im.status = 2;
   return im;
-}
-
-function MIM_add_event_listener (target, type, listener)
-{
-  if (target.addEventListener)
-    target.addEventListener (type, listener, false);
-  else if (target.attachEvent)
-    target.attachEvent ('on' + type,
-                       function() { listener.call (target, window.event); });
-  else
-    target['on' + type]
-      = function(e) { listener.call (target, e || window.event); };
-}
-
-var MIM_key = new Array ();
-MIM_key[0x09] = 'tab';
-MIM_key[0x08] = 'backspace';
-MIM_key[0x0D] = 'return';
-MIM_key[0x1B] = 'escape';
-MIM_key[0x20] = 'space';
-MIM_key[0x21] = 'pageup';
-MIM_key[0x22] = 'pagedown';
-MIM_key[0x23] = 'end';
-MIM_key[0x24] = 'home';
-MIM_key[0x25] = 'left';
-MIM_key[0x26] = 'up';
-MIM_key[0x27] = 'right';
-MIM_key[0x28] = 'down';
-MIM_key[0x2D] = 'insert';
-MIM_key[0x2E] = 'delete';
-for (var i = 1; i <= 12; i++)
-  MIM_key[111 + i] = "f" + i;
-MIM_key[0x90] = "numlock";
-MIM_key[0xF0] = "capslock";
-
-function MIM_decode_key (event)
+};
+
+MIM.add_event_listener
+  = (window.addEventListener
+     ? function (target, type, listener) {
+       target.addEventListener (type, listener, false);
+     }
+     : window.attachEvent
+     ? function (target, type, listener) {
+       target.attachEvent ('on' + type,
+                          function() {
+                            listener.call (target, window.event);
+                          });
+     }
+     : function (target, type, listener) {
+       target['on' + type]
+        = function (e) { listener.call (target, e || window.event); };
+     });
+
+(function () {
+  var keys = new Array ();
+  keys[0x09] = 'tab';
+  keys[0x08] = 'backspace';
+  keys[0x0D] = 'return';
+  keys[0x1B] = 'escape';
+  keys[0x20] = 'space';
+  keys[0x21] = 'pageup';
+  keys[0x22] = 'pagedown';
+  keys[0x23] = 'end';
+  keys[0x24] = 'home';
+  keys[0x25] = 'left';
+  keys[0x26] = 'up';
+  keys[0x27] = 'right';
+  keys[0x28] = 'down';
+  keys[0x2D] = 'insert';
+  keys[0x2E] = 'delete';
+  for (var i = 1; i <= 12; i++)
+    keys[111 + i] = "f" + i;
+  keys[0x90] = "numlock";
+  keys[0xF0] = "capslock";
+  MIM.special_key = keys;
+}) ();
+
+MIM.decode_key = function (event)
 {
   var key = ((event.type == 'keydown' || event.keyCode) ? event.keyCode
             : event.charCode ? event.charCode
@@ -181,7 +309,7 @@ function MIM_decode_key (event)
     return false;
   if (event.type == 'keydown')
     {
-      key = MIM_key[key];
+      key = MIM.special_key[key];
       if (! key)
        return false;
       if (event.shiftKey) key = "S-" + key ;
@@ -191,129 +319,113 @@ function MIM_decode_key (event)
   if (event.altKey) key = "A-" + key ;
   if (event.ctrlKey) key = "C-" + key ;
   return key;
-}
+};
 
-function debug_print (event, ic)
+MIM.debug_print = function (event, ic)
 {
+  if (! MIM.debug)
+    return;
+  if (! MIM.debug_nodes)
+    {
+      MIM.debug_nodes = new Array ();
+      MIM.debug_nodes['keydown'] = document.getElementById ('keydown');
+      MIM.debug_nodes['keypress'] = document.getElementById ('keypress');
+      MIM.debug_nodes['status0'] = document.getElementById ('status0');
+      MIM.debug_nodes['status1'] = document.getElementById ('status1');
+      MIM.debug_nodes['keyseq0'] = document.getElementById ('keyseq0');
+      MIM.debug_nodes['keyseq1'] = document.getElementById ('keyseq1');
+      MIM.debug_nodes['range0'] = document.getElementById ('range0');
+      MIM.debug_nodes['range1'] = document.getElementById ('range1');
+    }
   var target = event.target;
   var code = event.keyCode;
-  var char = event.type == 'keydown' ? "?" : event.charCode;
-  var key = MIM_decode_key (event);
-
-  document.getElementById (event.type).innerHTML = "" + code + "/" + char + " : " + key;
-  document.getElementById ('status').innerHTML = ic.im.status;
+  var ch = event.type == 'keydown' ? 0 : event.charCode;
+  var key = MIM.decode_key (event);
   var keyseq = "";
+  var index;
+
+  MIM.debug_nodes[event.type].innerHTML = "" + code + "/" + ch + " : " + key;
+  index = (event.type == 'keydown' ? '0' : '1');
+  MIM.debug_nodes['status' + index].innerHTML = ic.im.status;
   for (var i = 0; i < ic.keyseq.length; i++)
     keyseq += ic.keyseq[i];
-  document.getElementById ('keyseq').innerHTML = keyseq + ":" + ic.keyseq.length;
-  document.getElementById ('range').innerHTML = "" + ic.range[0] + "," + ic.range[1];;
-}
+  MIM.debug_nodes['keyseq' + index].innerHTML
+    = keyseq + ":" + ic.keyseq.length;
+  MIM.debug_nodes['range' + index].innerHTML
+    = "" + ic.range[0] + ":" + ic.range[1];
+};
 
-function MIM_get_range (target, range)
+MIM.get_range = function (target, range)
 {
-  if (target.selectionStart != null)
+  if (target.selectionStart != null) // for Mozilla
     {
-      // for Mozilla
       range[0] = target.selectionStart;
       range[1] = target.selectionEnd;
-      return true;
     }
-  if (document.selection != null)
+  else                         // for IE
     {
-      target.focus();
-
-      var range = document.selection.createRange ();
-      var bookmark = range.getBookmark ();
-      var value = target.value;
-      var saved_value = value;
-      var marker = "_#_MARKER_#_";
-      while (value.indexOf (marker) != -1)
-        marker += "#_";
-      var parent = range.parentElement ();
-      if (parent == null || parent.type != "textarea")
-       {
-         range[0] = range[1] = 0;
-       }
-      else
-       {
-         range.text = marker + range.text + marker;
-         contents = this.element.value;
-         range[0] = contents.indexOf (marker);
-         contents = contents.replace(marker, "");
-         range[1] = contents.indexOf(marker);
-         target.value = originalContents;
-         range.moveToBookmark (bookmark);
-         range.select ();
-       }
-      return true;
+      var r = document.selection.createRange ();
+      var rr = r.duplicate ();
+
+      rr.moveToElementText (target);
+      rr.setEndPoint ('EndToEnd', range);
+      range[0] = rr.text.length - r.text.length;
+      range[1] = rr.text.length;
     }
-  return false;
 }
 
-function MIM_set_caret (target, pos)
+MIM.set_caret = function (target, pos)
 {
-  if (target.selectionStart != null)
+  if (target.selectionStart != null) // Mozilla
     {
-      // Mozilla
       target.focus ();
       target.setSelectionRange (pos, pos);
-      return true;
     }
-  if (target.createTextRange != null)
+  else                         // IE
     {
-      // IE
       var range = target.createTextRange ();
       range.move ('character', pos);
-      ranges.elect ();
-      return true;
+      range.select ();
     }
-  // Unknown
-  target.focus ();
-  return false;
-}
+};
 
-function MIM_ic (im, target)
+MIM.ic = function (im, target)
 {
   this.im = im;
   this.target = target;
   this.key = false;
   this.keyseq = new Array ();
-  this.range = new Array (-1, -1);
+  this.range = new Array (0, 0);
   return this;
-}
+};
 
-MIM_ic.prototype.reset = function ()
+MIM.ic.prototype.reset = function ()
 {
   this.key = false;
   while (this.keyseq.length > 0)
     this.keyseq.pop ();
-  this.range[0] = this.range[1] = -1;
-}
+};
 
-MIM_ic.prototype.check_caret = function ()
+MIM.ic.prototype.check_range = function ()
 {
-  var from = this.range[0];
-  var to = this.range[1];
+  var from = this.range[0], to = this.range[1];
 
-  MIM_get_range (this.target, this.range);
-  if (from >= 0)
-    {
-      if (this.range[0] != this.range[1] || to != this.range[0])
-       this.reset ();
-      else
-       this.range[0] = from;
-    }
-}
+  MIM.get_range (this.target, this.range);
+  if (this.range[0] != this.range[1] || to != this.range[1])
+    this.reset ();
+  else
+    this.range[0] = from;
+};
 
-function MIM_insert (ic, insert)
+MIM.insert = function (ic, insert)
 {
   var text = ic.target.value;
   ic.target.value = (text.substring (0, ic.range[0])
                     + insert
                     + text.substring (ic.range[1]));
   ic.range[1] = ic.range[0] + insert.length;
-  MIM_set_caret (ic.target, ic.range[1]);
-}
+  MIM.set_caret (ic.target, ic.range[1]);
+};
 
 function keyseq_string (keyseq)
 {
@@ -323,21 +435,24 @@ function keyseq_string (keyseq)
   return str;
 }
 
-function MIM_handle_keyseq (event, ic)
+MIM.handle_keyseq = function (event, ic)
 {
   var map = ic.im.lookup (ic.keyseq, 1000);
   if (map instanceof Array)
     {
-      MIM_insert (ic, map['_target_text']);
+      MIM.insert (ic, map['_target_text']);
       if (! ('_has_child' in map))
-       ic.reset ();
+       {
+         ic.reset ();
+         ic.range[0] = ic.range[1];
+       }
       event.preventDefault ();
       //document.getElementById ('text').value
-       //= keyseq_string (ic.keyseq) + " handled";
+      //= keyseq_string (ic.keyseq) + " handled";
     }
   else if (map > 0)
     {
-      MIM_insert (ic, ic.im.lookup (ic.keyseq, map)['_target_text']);
+      MIM.insert (ic, ic.im.lookup (ic.keyseq, map)['_target_text']);
       while (map > 0)
        {
          ic.keyseq.shift ();
@@ -345,43 +460,44 @@ function MIM_handle_keyseq (event, ic)
        }
       ic.range[0] = ic.range[1];
       if (ic.keyseq.length > 0)
-       MIM_handle_keyseq (event, ic);
+       MIM.handle_keyseq (event, ic);
     }
   else
     {
       ic.reset ();
-      document.getElementById ('text').value
-       = keyseq_string (ic.keyseq) + " unhandled";
+      //document.getElementById ('text').value
+      //= keyseq_string (ic.keyseq) + " unhandled";
     }
-}
+};
 
-function MIM_reset_ic (event)
+MIM.reset_ic = function (event)
 {
   var ic = event.target.mim_ic;
   if (ic)
     ic.reset ();
-}
+};
 
-function MIM_keydown (event)
+MIM.keydown = function (event)
 {
-  if (! (event.target.type == "text" || event.target.type == "textarea"))
+  var target = event.target;
+  if (! (target.type == "text" || target.type == "textarea"))
     return;
 
-  var ic = event.target.mim_ic;
-  if (! ic || ic.im != MIM_current_im)
+  var ic = target.mim_ic;
+  if (! ic || ic.im != MIM.current_im)
     {
-      ic = new MIM_ic (MIM_current_im, event.target);
-      event.target.mim_ic = ic;
+      ic = new MIM.ic (MIM.current_im, target);
+      target.mim_ic = ic;
+      MIM.add_event_listener (target, 'blur', MIM.reset_ic);
     }
-  MIM_add_event_listener (event.target, 'blur', MIM_reset_ic);
-  debug_print (event, ic);
   if (ic.im.status < 0)
     return;
-  ic.check_caret ();
-  ic.key = MIM_decode_key (event);
-}
+  ic.check_range ();
+  MIM.debug_print (event, ic);
+  ic.key = MIM.decode_key (event);
+};
 
-function MIM_keypress (event)
+MIM.keypress = function (event)
 {
   if (! (event.target.type == "text" || event.target.type == "textarea"))
     return;
@@ -389,50 +505,53 @@ function MIM_keypress (event)
   var ic = event.target.mim_ic;
   var i;
 
-  debug_print (event, ic);
-  if (ic.im.status < 0)
-    return;
-  if (! ic.key)
-    ic.key = MIM_decode_key (event);
-  if (! ic.key)
-    {
-      ic.reset ();
+  try {
+    if (ic.im.status < 0)
       return;
-    }
-  ic.keyseq.push (ic.key);
-  if (ic.im.status == 1) // Still loading.
-    return;
-  MIM_handle_keyseq (event, ic);
+    if (! ic.key)
+      ic.key = MIM.decode_key (event);
+    if (! ic.key)
+      {
+       ic.reset ();
+       return;
+      }
+    ic.keyseq.push (ic.key);
+    if (ic.im.status == 1) // Still loading.
+      return;
+    MIM.handle_keyseq (event, ic);
+  } finally {
+    MIM.debug_print (event, ic);
+  }
   return;
-}
+};
 
-function MIM_select_im (event)
+MIM.select_im = function (event)
 {
   var target = event.target.parentNode;
   while (target.tagName != "SELECT")
     target = target.parentNode;
   var idx = 0;
   var im = false;
-  for (var lang in MIM_list)
-    for (var name in MIM_list[lang])
+  for (var lang in MIM.list)
+    for (var name in MIM.list[lang])
       if (idx++ == target.selectedIndex)
        {
-         im = MIM_list[lang][name];
+         im = MIM.list[lang][name];
          break;
        }
   document.getElementsByTagName ('body')[0].removeChild (target);
   target.target.focus ();
-  if (im && im != MIM_current_im)
-    MIM_current_im = MIM_load (im);
-}
+  if (im && im != MIM.current_im)
+    MIM.current_im = MIM.load_sync (im);
+};
 
-function MIM_destroy_menu (event)
+MIM.destroy_menu = function (event)
 {
   if (event.target.tagName == "SELECT")
     document.getElementsByTagName ('body')[0].removeChild (event.target);
-}
+};
 
-function MIM_select_menu (event)
+MIM.select_menu = function (event)
 {
   var target = event.target;
 
@@ -441,36 +560,68 @@ function MIM_select_menu (event)
     return;
 
   var sel = document.createElement ('select');
-  sel.onclick = MIM_select_im;
-  sel.onmouseout = MIM_destroy_menu;
+  sel.onclick = MIM.select_im;
+  sel.onmouseout = MIM.destroy_menu;
   sel.style.position='absolute';
   sel.style.left = (event.clientX - 10) + "px";
   sel.style.top = (event.clientY - 10) + "px";
   sel.target = target;
   var idx = 0;
-  for (var lang in MIM_list)
-    for (var name in MIM_list[lang])
+  for (var lang in MIM.list)
+    for (var name in MIM.list[lang])
       {
        var option = document.createElement ('option');
        var imname = lang + "-" + name;
        option.appendChild (document.createTextNode (imname));
        option.value = imname;
        sel.appendChild (option);
-       if (MIM_list[lang][name] == MIM_current_im)
+       if (MIM.list[lang][name] == MIM.current_im)
          sel.selectedIndex = idx;
        idx++;
       }
   sel.size = idx;
   document.getElementsByTagName ('body')[0].appendChild (sel);
-}
-
-MIM_current_im = MIM_register ('latn-post.js', 'latin', 'post');
-MIM_register ('th-kesmanee.js', 'th', 'kesmanee');
+};
 
-function MIM_init ()
+MIM.textinput = function (event)
 {
-  MIM_add_event_listener (window, 'keydown', MIM_keydown);
-  MIM_add_event_listener (window, 'keypress', MIM_keypress);
-  MIM_add_event_listener (window, 'mousedown', MIM_select_menu);
-  MIM_load (MIM_current_im);
+  var str = ''
+  var changed = false;
+  for (var i = 0; i < event.data.length; i++)
+    {
+      if (event.data.charAt (i) == 'あ')
+       {
+         str += 'ア'; changed = true;
+       }
+      else
+       str += event.data.charAt (i);
+    }
+  alert (str);
+  if (changed)
+    {
+      var e = document.createEvent ('TextEvent');
+      e.initTextEvent ('textInput', event.canBuggle, event.cancelable, event.view,
+                      str, event.inputMode);
+      document.getElementById ('text').value = str;
+      event.target.dispatchEvent (e);
+    }
 }
+
+MIM.init = function ()
+{
+  MIM.add_event_listener (window, 'keydown', MIM.keydown);
+  MIM.add_event_listener (window, 'keypress', MIM.keypress);
+  MIM.add_event_listener (window, 'mousedown', MIM.select_menu);
+  MIM.add_event_listener (window, 'textInput', MIM.textinput);
+  if (window.location == 'http://localhost/mim/index.html')
+    MIM.server = 'http://localhost/mim';
+  MIM.current_im = MIM.register ('latin', 'post', 'latn-post.js');
+  MIM.register ('th', 'kesmanee', 'th-kesmanee.js');
+  MIM.load_sync (MIM.current_im);
+};
+
+MIM.init_debug = function ()
+{
+  MIM.debug = true;
+  MIM.init ();
+};