var kbArray = new Array();

var agent = navigator.userAgent.toLowerCase();
var msie = (agent.indexOf("msie") != -1) && !window.opera;

function setup_event(elem, eventType, handler)
{
  if(elem.attachEvent)
  {
    elem.attachEvent("on" + eventType, handler);
  }
  else if(elem.addEventListener)
  {
    elem.addEventListener(eventType, handler, false);
  }
}

function detach_event(elem, eventType, handler)
{
  if(elem.detachEvent)
  {
    elem.detachEvent("on" + eventType, handler);
  }
  else if(elem.removeEventListener)
  {
    elem.removeEventListener(eventType, handler, false);
  }
}

function get_event_source(e)
{
  var event = e ? e : window.event;
  return event.srcElement ? event.srcElement : event.target;
}

function findPosX(obj)
{
  var curleft = 140;
  if(obj.offsetParent)
  {
    while(obj.offsetParent)
    {
      curleft += obj.offsetLeft;
      obj = obj.offsetParent;
    }
  }
  else if(obj.x)
    curleft += obj.x;

  return curleft;
}

function findPosY(obj)
{
  var curtop = 0;
  if(obj.offsetParent)
  {
    while(obj.offsetParent)
    {
      curtop += obj.offsetTop;
      obj = obj.offsetParent;
    }
  }
  else if(obj.y)
    curtop += obj.y;

  return curtop;
}

function findOffX(obj)
{ return (obj && obj.main) ? parseFloat(obj.main.offsetLeft) : 0; }

function findOffY(obj)
{ return (obj && obj.main) ? parseFloat(obj.main.offsetTop) : 0; }

function findOffW(obj)
{ return (obj && obj.main) ? parseFloat(obj.main.offsetWidth) : 0; }

function findOffH(obj)
{ return (obj && obj.main) ? parseFloat(obj.main.offsetHeight) : 0; }

function setup_style(obj, top, left, width, height, position, border_color, text_align, line_height, font_size, font_weight, padding_left, padding_right, font_color, back_color)
{
  if(top) obj.style.top = top;
  if(left) obj.style.left = left;
  if(width) obj.style.width = width;
  if(height) obj.style.height = height;
  if(position) obj.style.position = position;
  if(border_color) obj.style.border = "1px solid " + border_color;
  if(back_color) obj.style.backgroundColor = back_color;

  if(line_height) obj.style.lineHeight = line_height;
  if(text_align) obj.style.textAlign = text_align;
  if(padding_left) obj.style.paddingLeft = padding_left;
  if(padding_right) obj.style.paddingRight = padding_right;

  obj.style.fontWeight = (font_weight ? font_weight : "bold");
  if(font_size) obj.style.fontSize = font_size;
  //if(msie) obj.UNSELECTABLE = "off";
}

function setup_key(top, left, width, height, border_color, text_align, line_height, font_size, font_weight, padding_left, padding_right, font_color, back_color)
{
  var key = document.createElement("DIV");
  setup_style(key, top, left, width, height, "absolute");

  var key_sub = document.createElement("DIV");
  key.appendChild(key_sub);

  setup_style(key_sub,"","","",line_height,"relative",border_color,text_align,line_height,font_size,font_weight,padding_left,padding_right,font_color,back_color);

  var retObj = new Object();
  retObj.main = key;
  retObj.sub = key_sub;

  return retObj;
}

function ShowVKeyboard(container_id, callback_proc, shownhide_on_change, font_size, font_color, dead_color, back_color, border_color, inactive_border_color, lang_sel_brd_color, lang_sel_item_color)
{
  var ct = document.getElementById(container_id);
  var vkboard = kbArray[container_id];

  if(vkboard)
  {
    var changed = false;

    if((vkboard.Callback != callback_proc) && (String(callback_proc).length > 0))
    {
      vkboard.Callback = callback_proc;
      changed = true;
    }

    if(!changed || (changed && shownhide_on_change))
    {
      ct.style.display = (ct.style.display == "none" ? "block" : "none");

      var menu = document.getElementById(container_id + "___lang_menu");
      if(menu)
        ct.removeChild(menu);
    }
  }
  else
  {
    var fs = font_size ? font_size : "14px";
    var fc = font_color ? font_color : "#000";
    var bkc = back_color ? back_color : "#FFF";
    var bc = border_color ? border_color : "#777";
    var ibc = inactive_border_color ? inactive_border_color : "#CCC";
    var lsc = lang_sel_brd_color ? lang_sel_brd_color : "#F77";
    var lic = lang_sel_item_color ? lang_sel_item_color : "#DDD";

    // vkboard creation:
    vkboard = new Object;

    vkboard.Callback = callback_proc;
    vkboard.Caps = false;
    vkboard.Shift = false;
    vkboard.AltGr = false;
    vkboard.DeadAction = null;
    vkboard.CurrentLayout = "Az";

    vkboard.fontsize = fs;
    vkboard.fontcolor = fc;
    vkboard.backcolor = bkc;
    vkboard.bordercolor = bc;
    vkboard.inactivebc = ibc;
    vkboard.lsc = lsc;
    vkboard.lic = lic;

    vkboard.keys = new Array(), vkboard.ctrl = new Array();

    kbArray[container_id] = vkboard;

    var mag = parseFloat(fs) / 14.0, cell = 25.0 * mag, dcell = 2 * cell;
    var cp = String(cell) + "px", lh = String(Math.floor(cell - 2.0)) + "px";

    var initY = findPosY(ct), initX = findPosX(ct);

    var kb = document.createElement("DIV");
    ct.appendChild(kb);

    ct.style.display = "block";
    ct.style.position = "absolute";
    ct.style.top = initY + "px", ct.style.left = initX +"px";

    kb.style.position = "relative";
    kb.style.top = "0px", kb.style.left = "0px";
    kb.style.border = "1px solid " + bc;

    var kb_main = document.createElement("DIV");
    kb.appendChild(kb_main);

    kb_main.style.position = "relative";
    kb_main.style.width = "1px";
    kb_main.style.cursor = "pointer";
    kb_main.style.backgroundColor = bkc;

    var prevX = 0, prevY = 1, prevW = 0, prevH = 0;

    // Convinience var-strings:
    var c = "center", n = "normal", r = "right", l = "left", e = "&nbsp;";

    // Number row:

    var key;
    for(var i = 0; i < 13; i++)
    {
      key = setup_key("1px", (prevX + prevW + 1) + "px", cp, cp, bc, c, lh, fs);
      key.sub.id = container_id + "___key" + String(i);
      kb_main.appendChild(key.main);

      prevX = findOffX(key), prevW = findOffW(key), vkboard.keys[i] = key.sub;
    }

    prevY = findOffY(key), prevH = findOffH(key);

    var kb_kbp = setup_key("1px", (prevX + prevW + 1) + "px", (2.96 * cell) + "px", cp, bc, r, lh, fs, n, "", "4px");
    kb_kbp.sub.innerHTML = "BackSpace";
    kb_kbp.sub.id = container_id + "___kbp";
    kb_main.appendChild(kb_kbp.main);
    vkboard.ctrl["backsp"] = kb_kbp.sub;

    // Top row:

    var kb_tab = setup_key((prevY + prevH + 1) + "px", "1px", (1.48 * cell + 1) + "px", cp, bc, l, lh, fs, n, "4px");
    kb_tab.sub.innerHTML = "Tab";
    kb_tab.sub.id = container_id + "___tab";
    kb_main.appendChild(kb_tab.main);
    vkboard.ctrl["tab"] = kb_tab.sub;

    prevX = findOffX(kb_tab), prevW = findOffW(kb_tab), prevY = findOffY(kb_tab);

    for(; i < 26; i++)
    {
      key = setup_key(prevY + "px", (prevX + prevW + 1) + "px", cp, cell + "px", bc, c, lh, fs);
      key.sub.id = container_id + "___key" + String(i);
      kb_main.appendChild(key.main);

      prevX = findOffX(key), prevW = findOffW(key), vkboard.keys[i] = key.sub;
    }

    prevH = findOffH(key);
    var kbpH = findOffX(kb_kbp) + findOffW(kb_kbp);

    var kb_enter_top = setup_key(prevY + "px", (prevX + prevW + 1) + "px", String(kbpH - prevX - prevW - 1) + "px", (1.08 * cell) + "px", bc, c, cp, fs);
    kb_enter_top.sub.style.borderBottomColor = bkc;
    kb_enter_top.sub.innerHTML = e;
    kb_enter_top.sub.subst = "Enter";      // Special expando
    kb_enter_top.sub.id = container_id + "___enter_top";
    kb_main.appendChild(kb_enter_top.main);
    vkboard.ctrl["et"] = kb_enter_top.sub;

    // Home row:

    var kb_caps = setup_key((prevY + prevH + 1) + "px", "1px", dcell + "px", cp, bc, l, lh, fs, n, "4px");
    kb_caps.sub.innerHTML = "Caps";
    kb_caps.sub.id = container_id + "___caps";
    kb_main.appendChild(kb_caps.main);
    vkboard.ctrl["caps"] = kb_caps.sub;

    prevX = findOffX(kb_caps), prevW = findOffW(kb_caps), prevY = findOffY(kb_caps);

    for(; i < 38; i++)
    {
      key = setup_key(prevY + "px", (prevX + prevW + 1) + "px", cp, cp, bc, c, lh, fs);
      key.sub.id = container_id + "___key" + String(i);
      kb_main.appendChild(key.main);

      prevX = findOffX(key), prevW = findOffW(key), vkboard.keys[i] = key.sub;
    }

    prevY = findOffY(key), prevH = findOffH(key);

    var kb_enter_l = setup_key(prevY + "px", (prevX + prevW + 1) + "px", (0.54 * cell) + "px", cp, bc, r, lh, fs, n, "", "4px");
    kb_enter_l.sub.style.borderRightColor = bkc;
    kb_enter_l.sub.innerHTML = e;
    kb_enter_l.sub.subst = "Enter";
    kb_enter_l.sub.id = container_id + "___enter_l";
    kb_main.appendChild(kb_enter_l.main);
    vkboard.ctrl["el"] = kb_enter_l.sub;

    prevX = findOffX(kb_enter_l), prevW = findOffW(kb_enter_l);

    var kb_enter = setup_key(prevY + "px", (prevX + prevW) + "px", String(findOffX(kb_enter_top) + findOffW(kb_enter_top) - prevX - prevW) + "px", cp, bc, r, lh, fs, n, "", "4px");
    kb_enter.sub.style.borderTopColor = bkc;
    kb_enter.sub.style.borderLeftColor = bkc;
    kb_enter.sub.innerHTML = "Enter";
    kb_enter.sub.id = container_id + "___enter";
    kb_main.appendChild(kb_enter.main);
    vkboard.ctrl["e"] = kb_enter.sub;

    // Bottom row:

    var kb_shift = setup_key((prevY + prevH + 1) + "px", "1px", (2.52 * cell) + "px", cp, bc, l, lh, fs, n, "4px");
    kb_shift.sub.innerHTML = "Shift";
    kb_shift.sub.id = container_id + "___shift";
    kb_main.appendChild(kb_shift.main);
    vkboard.ctrl["sh"] = kb_shift.sub;

    prevX = findOffX(kb_shift), prevW = findOffW(kb_shift), prevY = findOffY(kb_shift);

    for(; i < 48; i++)
    {
      key = setup_key(prevY + "px", (prevX + prevW + 1) + "px", cp, cp, bc, c, lh, fs);
      key.sub.id = container_id + "___key" + String(i);
      kb_main.appendChild(key.main);

      prevX = findOffX(key), prevW = findOffW(key), vkboard.keys[i] = key.sub;
    }

    prevY = findOffY(key), prevH = findOffH(key);

    var kb_shift_r = setup_key(prevY + "px", (prevX + prevW + 1) + "px", String(findOffX(kb_kbp) + findOffW(kb_kbp) - prevX - prevW - 1) + "px", cp, bc, r, lh, fs, n, "", "4px");
    kb_shift_r.sub.innerHTML = "Shift";
    kb_shift_r.sub.id = container_id + "___shift_r";
    kb_main.appendChild(kb_shift_r.main);
    vkboard.ctrl["sr"] = kb_shift_r.sub;

    // Language selector:
    var vcell = String(1.32 * cell) + "px";

    var kb_lang = setup_key((prevY + prevH + 1) + "px", "1px", vcell, cp, lsc, l, lh, fs, n, "4px");
    kb_lang.sub.id = container_id + "___lang";
    vkboard.ctrl["lang"] = kb_lang.sub;
    kb_main.appendChild(kb_lang.main);

    prevY = findOffY(kb_lang);

    var kb_res_2 = setup_key(prevY + "px", (findOffX(kb_lang) + findOffW(kb_lang) + 1) + "px", vcell, cp, ibc, c, lh, fs);
    kb_res_2.sub.innerHTML = e;
    kb_main.appendChild(kb_res_2.main);

    var kb_res_3 = setup_key(prevY + "px", (findOffX(kb_res_2) + findOffW(kb_res_2) + 1) + "px", vcell, cp, ibc, c, lh, fs);
    kb_res_3.sub.innerHTML = e;
    kb_main.appendChild(kb_res_3.main);

    var kb_space = setup_key(prevY + "px", (findOffX(kb_res_3) + findOffW(kb_res_3) + 1) + "px", (6.28 * cell) + "px", cp, bc, c, lh, fs);
    kb_space.sub.id = container_id + "___space";
    setup_event(kb_space.sub, 'mousedown', generic_callback_proc);
    vkboard.ctrl["space"] = kb_space.sub;
    kb_main.appendChild(kb_space.main);

    var kb_alt_gr = setup_key(prevY + "px", (findOffX(kb_space) + findOffW(kb_space) + 1) + "px", vcell, cp, bc, c, lh, parseFloat(fs) * 0.786, n);
    kb_alt_gr.sub.innerHTML = "AltGr";
    kb_alt_gr.sub.id = container_id + "___alt_gr";
    vkboard.ctrl["altgr"] = kb_alt_gr.sub;
    kb_main.appendChild(kb_alt_gr.main);

    var kb_res_5 = setup_key(prevY + "px", (findOffX(kb_alt_gr) + findOffW(kb_alt_gr) + 1) + "px", vcell, cp, ibc, c, lh, fs);
    kb_res_5.sub.innerHTML = e;
    kb_main.appendChild(kb_res_5.main);

    var kb_res_6 = setup_key(prevY + "px", (findOffX(kb_res_5) + findOffW(kb_res_5) + 1) + "px", vcell, cp, ibc, c, lh, fs);
    kb_res_6.sub.innerHTML = e;
    kb_main.appendChild(kb_res_6.main);

    kb_main.style.height = (prevY + prevH + 1) + "px";

    // Numeric keypad:

    var edge = (kbpH + cell + 1) + "px";

    var kb_pad_eur = setup_key("1px", edge, cp, cp, bc, c, lh, fs);
    kb_pad_eur.sub.innerHTML = "&#x20AC;";
    kb_pad_eur.sub.id = container_id + "___pad_eur";
    vkboard.ctrl["padeur"] = kb_pad_eur.sub;
    kb_main.appendChild(kb_pad_eur.main);

    var edge_1 = (findOffX(kb_pad_eur) + findOffW(kb_pad_eur) + 1) + "px";

    var kb_pad_slash = setup_key("1px", edge_1, cp, cp, bc, c, lh, fs);
    kb_pad_slash.sub.innerHTML = "/";
    kb_pad_slash.sub.id = container_id + "___pad_slash";
    vkboard.ctrl["padsl"] = kb_pad_slash.sub;
    kb_main.appendChild(kb_pad_slash.main);

    var edge_2 = (findOffX(kb_pad_slash) + findOffW(kb_pad_slash) + 1) + "px";

    var kb_pad_star = setup_key("1px", edge_2, cp, cp, bc, c, lh, fs);
    kb_pad_star.sub.innerHTML = "*";
    kb_pad_star.sub.id = container_id + "___pad_star";
    vkboard.ctrl["padst"] = kb_pad_star.sub;
    kb_main.appendChild(kb_pad_star.main);

    var edge_3 = (findOffX(kb_pad_star) + findOffW(kb_pad_star) + 1) + "px";

    var kb_pad_minus = setup_key("1px", edge_3, cp, cp, bc, c, lh, fs);
    kb_pad_minus.sub.innerHTML = "-";
    kb_pad_minus.sub.id = container_id + "___pad_minus";
    vkboard.ctrl["padmin"] = kb_pad_minus.sub;
    kb_main.appendChild(kb_pad_minus.main);

    kb.style.width = kb_main.style.width = String(findOffX(kb_pad_minus) + findOffW(kb_pad_minus) + 1) + "px";

    var edge_Y = (findOffY(kb_pad_eur) + findOffH(kb_pad_eur) + 1) + "px";

    var kb_pad_7 = setup_key(edge_Y, edge, cp, cp, bc, c, lh, fs);
    kb_pad_7.sub.innerHTML = "7";
    kb_pad_7.sub.id = container_id + "___pad_7";
    vkboard.ctrl["pad7"] = kb_pad_7.sub;
    kb_main.appendChild(kb_pad_7.main);

    var kb_pad_8 = setup_key(edge_Y, edge_1, cp, cp, bc, c, lh, fs);
    kb_pad_8.sub.innerHTML = "8";
    kb_pad_8.sub.id = container_id + "___pad_8";
    vkboard.ctrl["pad8"] = kb_pad_8.sub;
    kb_main.appendChild(kb_pad_8.main);

    var kb_pad_9 = setup_key(edge_Y, edge_2, cp, cp, bc, c, lh, fs);
    kb_pad_9.sub.innerHTML = "9";
    kb_pad_9.sub.id = container_id + "___pad_9";
    vkboard.ctrl["pad9"] = kb_pad_9.sub;
    kb_main.appendChild(kb_pad_9.main);

    var kb_pad_plus = setup_key(edge_Y, edge_3, cp, (dcell + 1) + "px", bc, c, (dcell - 1) + "px", fs);
    kb_pad_plus.sub.innerHTML = "+";
    kb_pad_plus.sub.id = container_id + "___pad_plus";
    vkboard.ctrl["padpl"] = kb_pad_plus.sub;
    kb_main.appendChild(kb_pad_plus.main);

    edge_Y = (findOffY(kb_pad_7) + findOffH(kb_pad_7) + 1) + "px";

    var kb_pad_4 = setup_key(edge_Y, edge, cp, cp, bc, c, lh, fs);
    kb_pad_4.sub.innerHTML = "4";
    kb_pad_4.sub.id = container_id + "___pad_4";
    vkboard.ctrl["pad4"] = kb_pad_4.sub;
    kb_main.appendChild(kb_pad_4.main);

    var kb_pad_5 = setup_key(edge_Y, edge_1, cp, cp, bc, c, lh, fs);
    kb_pad_5.sub.innerHTML = "5";
    kb_pad_5.sub.id = container_id + "___pad_5";
    vkboard.ctrl["pad5"] = kb_pad_5.sub;
    kb_main.appendChild(kb_pad_5.main);

    var kb_pad_6 = setup_key(edge_Y, edge_2, cp, cp, bc, c, lh, fs);
    kb_pad_6.sub.innerHTML = "6";
    kb_pad_6.sub.id = container_id + "___pad_6";
    vkboard.ctrl["pad6"] = kb_pad_6.sub;
    kb_main.appendChild(kb_pad_6.main);

    edge_Y = (findOffY(kb_pad_4) + findOffH(kb_pad_4) + 1) + "px";

    var kb_pad_1 = setup_key(edge_Y, edge, cp, cp, bc, c, lh, fs);
    kb_pad_1.sub.innerHTML = "1";
    kb_pad_1.sub.id = container_id + "___pad_1";
    vkboard.ctrl["pad1"] = kb_pad_1.sub;
    kb_main.appendChild(kb_pad_1.main);

    var kb_pad_2 = setup_key(edge_Y, edge_1, cp, cp, bc, c, lh, fs);
    kb_pad_2.sub.innerHTML = "2";
    kb_pad_2.sub.id = container_id + "___pad_2";
    vkboard.ctrl["pad2"] = kb_pad_2.sub;
    kb_main.appendChild(kb_pad_2.main);

    var kb_pad_3 = setup_key(edge_Y, edge_2, cp, cp, bc, c, lh, fs);
    kb_pad_3.sub.innerHTML = "3";
    kb_pad_3.sub.id = container_id + "___pad_3";
    vkboard.ctrl["pad3"] = kb_pad_3.sub;
    kb_main.appendChild(kb_pad_3.main);

    var kb_pad_enter = setup_key(edge_Y, edge_3, cp, (dcell + 1) + "px", bc, c, (dcell - 1) + "px", parseFloat(fs) * 0.643, n);
    kb_pad_enter.sub.innerHTML = "Enter";
    kb_pad_enter.sub.id = container_id + "___pad_enter";
    vkboard.ctrl["pade"] = kb_pad_enter.sub;
    kb_main.appendChild(kb_pad_enter.main);

    edge_Y = (findOffY(kb_pad_1) + findOffH(kb_pad_1) + 1) + "px";

    var kb_pad_0 = setup_key(edge_Y, edge, (dcell + 1) + "px", cp, bc, l, lh, fs, "bold", "7px");
    kb_pad_0.sub.innerHTML = "0";
    kb_pad_0.sub.id = container_id + "___pad_0";
    vkboard.ctrl["pad0"] = kb_pad_0.sub;
    kb_main.appendChild(kb_pad_0.main);

    var kb_pad_period = setup_key(edge_Y, edge_2, cp, cp, bc, c, lh, fs);
    kb_pad_period.sub.innerHTML = ".";
    kb_pad_period.sub.id = container_id + "___pad_period";
    vkboard.ctrl["padp"] = kb_pad_period.sub;
    kb_main.appendChild(kb_pad_period.main);

    refresh_layout(container_id);
  }
}

function set_key_state(key, onoff, textcolor, bordercolor, backcolor)
{
  if(key && key.style)
  {
    if(backcolor) key.style.backgroundColor = backcolor;
    if(bordercolor) key.style.borderColor = bordercolor;
    if(textcolor) key.style.color = textcolor;
  }

  detach_event(key, 'mousedown', generic_callback_proc);
  if(onoff)
    setup_event(key, 'mousedown', generic_callback_proc);
}

function refresh_layout(container_id)
{
  var vkboard = kbArray[container_id];
  var fc = vkboard.fontcolor;
  var bkc = vkboard.backcolor, bc = vkboard.bordercolor;
  var ibc = vkboard.inactivebc, lic = vkboard.lic;

  var layout_name = vkboard.CurrentLayout;
  var arr_type = vkboard.AltGr ? (vkboard.Shift ? "alt_gr_shift" : "alt_gr") : (vkboard.Shift ? "shift" : (vkboard.Caps ? "caps" : "normal"));

  var nkeys = vkboard.keys.length;

  eval("var caps_arr = typeof(" + layout_name + "_caps) != 'undefined'");
  if(caps_arr)
    eval("caps_arr = " + layout_name + "_caps.length == " + String(nkeys));

  eval("var shift_arr = typeof(" + layout_name + "_shift) != 'undefined'");
  if(shift_arr)
    eval("shift_arr = " + layout_name + "_shift.length == " + String(nkeys));

  eval("var alt_gr_arr = typeof(" + layout_name + "_alt_gr) != 'undefined'");
  if(alt_gr_arr)
    eval("alt_gr_arr = " + layout_name + "_alt_gr.length == " + String(nkeys));

  eval("var alt_gr_shift_arr = alt_gr_arr && typeof(" + layout_name + "_alt_gr_shift) != 'undefined'");
  if(alt_gr_shift_arr)
    eval("alt_gr_shift_arr = " + layout_name + "_alt_gr_shift.length == " + String(nkeys));

  var caps = vkboard.ctrl["caps"], shift = vkboard.ctrl["sh"], shift_r = vkboard.ctrl["sr"];
  var alt_gr = vkboard.ctrl["altgr"], space = vkboard.ctrl["space"], lang = vkboard.ctrl["lang"];
  var enter_t = vkboard.ctrl["et"], enter_l = vkboard.ctrl["el"], enter_c = vkboard.ctrl["e"];

  if(shift_arr)
  {
    set_key_state(shift, true, fc, bc, vkboard.Shift ? lic : bkc);
    set_key_state(shift_r, true, fc, bc, vkboard.Shift ? lic : bkc);
  }
  else
  {
    set_key_state(shift, false, ibc, ibc, bkc);
    set_key_state(shift_r, false, ibc, ibc, bkc);

    if(arr_type == "shift")
    {
      arr_type = "normal";
      vkboard.Shift = false;
    }
  }

  if(alt_gr_arr)
  {
    set_key_state(alt_gr, true, fc, bc, vkboard.AltGr ? lic : bkc);

    if((arr_type == "alt_gr") || (arr_type == "alt_gr_shift"))
    {
      if(alt_gr_shift_arr)
      {
        set_key_state(shift, true, fc, bc, "");
        set_key_state(shift_r, true, fc, bc, "");
      }
      else
      {
        set_key_state(shift, false, ibc, ibc, bkc);
        set_key_state(shift_r, false, ibc, ibc, bkc);

        arr_type = "alt_gr";
        vkboard.Shift = false;
      }
    }
  }
  else
  {
    set_key_state(alt_gr, false, ibc, ibc, bkc);

    if(arr_type == "alt_gr")
    {
      arr_type = "normal";
      vkboard.AltGr = false;
    }
    else if(arr_type == "alt_gr_shift")
    {
      arr_type = "normal";
      vkboard.AltGr = false, vkboard.Shift = false;

      shift.style.backgroundColor = bkc, shift_r.style.backgroundColor = bkc;
    }
  }

  if(caps_arr && (arr_type != "alt_gr") && (arr_type != "alt_gr_shift"))
  {
    set_key_state(caps, true, fc, bc, vkboard.Caps ? lic : bkc);
  }
  else
  {
    set_key_state(caps, false, ibc, ibc, bkc);

    vkboard.Caps = false;
    if(arr_type == "caps") arr_type = "normal";
  }

  var DeadValue = "";

  for(var i = 0; i < nkeys; i++)
  {
    var ndx = "[" + String(i) + "]";

    eval("var key_val = " + layout_name + "_" + arr_type + ndx);
    var key = vkboard.keys[i];

    if(vkboard.Shift && vkboard.Caps)
    {
      eval("var key_nrm = " + layout_name + "_normal" + ndx);
      eval("var key_cps = " + layout_name + "_caps" + ndx);
      eval("var key_shf = " + layout_name + "_shift" + ndx);

      if((key_cps == key_shf) && (key_nrm != key_cps))
        key_val = key_nrm;
    }

    if(String(typeof(key_val)).toLowerCase() == "object")
    {
      key.innerHTML = key_val[0], key.dead = key_val[1];

      if(vkboard.DeadAction == key_val[1]) DeadValue = key_val[0];

      set_key_state(key, true, "#F00", bc, (DeadValue == key_val[0] ? lic : bkc));
    }
    else
    {
      key.dead = null;

      var block = false;
      if((key_val != "") && vkboard.DeadAction)
      {
        eval("for(var j = 0; j < " + vkboard.DeadAction + ".length; j++) { if(" + vkboard.DeadAction + "[j][0] == key_val) { key_val = " + vkboard.DeadAction + "[j][1]; break; }}");

        eval("if(j == " + vkboard.DeadAction + ".length) block = true");
      }

      if(key_val != "")
      {
        key.innerHTML = key_val;

        if(block)
          set_key_state(key, false, ibc, ibc, bkc);
        else
          set_key_state(key, true, fc, bc, bkc);
      }
      else
      {
        key.innerHTML = "&nbsp;";
        set_key_state(key, false, ibc, ibc, bkc);
      }
    }
  }

  for(var k in vkboard.ctrl)
  {
    var key = vkboard.ctrl[k];
    switch(key)
    {
      case caps: case shift: case shift_r: case alt_gr:
        break;

      case space:
        space.innerHTML = vkboard.DeadAction ? DeadValue : "&#x00A0;";
        break;

      case lang:
        detach_event(key, 'mousedown', handle_lang_choice_menu);

        if(vkboard.DeadAction)
          set_key_state(key, false, ibc, ibc, bkc);
        else
        {
          set_key_state(key, false, fc, vkboard.lsc, bkc);
          setup_event(key, 'mousedown', handle_lang_choice_menu);
        }
        break;

      default:
        if(vkboard.DeadAction)
          set_key_state(key, false, ibc, ibc, "");
        else
          set_key_state(key, true, fc, bc, "");

        switch(key)
        {
          case enter_t: key.style.borderBottomColor = bkc; break;
          case enter_l: key.style.borderRightColor = bkc; break;
          case enter_c: key.style.borderTopColor = key.style.borderLeftColor = bkc; break;
        }
    }
  }

  lang.innerHTML = layout_name;
}

function handle_lang_choice_menu(event)
{
  var in_el = get_event_source(event);
  var container_id = in_el.id.substring(0, in_el.id.indexOf("___"));

  var ct = document.getElementById(container_id);
  var menu = document.getElementById(container_id + "___lang_menu");

  if(menu)
    ct.removeChild(menu);
  else
  {
    var vkboard = kbArray[container_id];
    var fs = vkboard.fontsize, fc = vkboard.fontcolor;
    var bkc = vkboard.backcolor, bc = vkboard.bordercolor;
    var ibc = vkboard.inactivebc, lic = vkboard.lic;

    var mag = parseFloat(fs) / 14.0, cell = 25.0 * mag, w = 102 * mag;

    menu = document.createElement("DIV");
    menu.id = container_id + "___lang_menu";
    menu.style.display = "block";
    menu.style.position = "relative";
    menu.style.top = "1px";
    menu.style.left = "0px";
    menu.style.width = String(w) + "px";
    menu.style.border = "1px solid " + bc;
    ct.appendChild(menu);

    var menu_main = document.createElement("DIV");
    menu_main.style.position = "relative";
    menu_main.style.width = String(w) + "px";
    menu_main.style.height = String(avail_langs.length * (cell + mag) + 1) + "px";
    menu_main.style.cursor = "default";
    menu.appendChild(menu_main);

    for(var j = 0; j < avail_langs.length; j++)
    {
      var item = setup_key(String((cell + mag) * j + 1) + "px", "1px", String(w - 2 * mag) + "px", cell + "px", ibc, "left", (cell - 2) + "px", fs, "normal", "4px", "", fc, bkc);
      menu_main.appendChild(item.main);

      item.sub.id = container_id + "___lang_" + String(j);
      item.sub.innerHTML = avail_langs[j][1];

      setup_event(item.sub, 'mousedown', handle_lang_choice_item);
      setup_event(item.sub, 'mouseover', new Function("event", "get_event_source(event).style.backgroundColor = '" + lic + "'"));
      setup_event(item.sub, 'mouseout', new Function("event", "get_event_source(event).style.backgroundColor = '" + bkc + "'"));
    }
  }
}

function handle_lang_choice_item(event)
{
  var in_el = get_event_source(event);

  var ndx = in_el.id.indexOf("___lang_");
  var lng = in_el.id.substring(ndx + 8, in_el.id.length);
  var container_id = in_el.id.substring(0, ndx);

  kbArray[container_id].CurrentLayout = avail_langs[lng][0];
  refresh_layout(container_id);

  document.getElementById(container_id).removeChild(document.getElementById(container_id + "___lang_menu"));
}

function generic_callback_proc(event)
{
  var in_el = get_event_source(event);
  var container_id = in_el.id.substring(0, in_el.id.indexOf("___"));

  var vkboard = kbArray[container_id];
  var val = in_el.subst ? in_el.subst : in_el.innerHTML;

  if((val != "Caps") && (val != "Shift") && (val != "AltGr") && (in_el.dead || vkboard.DeadAction))
  {
    if(vkboard.DeadAction)
    {
      if(in_el.dead) val = "";

      vkboard.DeadAction = null;
      refresh_layout(container_id);
    }
    else
    {
      vkboard.DeadAction = in_el.dead;
      refresh_layout(container_id);
      return;
    }
  }

  switch(val)
  {
    case "Caps": case "Shift": case "AltGr":
    {
      eval("vkboard." + val + " = !vkboard." + val);
      refresh_layout(container_id);
      return;
    }

    case "Tab": val = "   "; break;
    case "&lt;": val = "<"; break;
    case "&gt;": val = ">"; break;
    case "&amp;": val = "&"; break;
    case "&nbsp;": val = " "; break;
    case "&quot;": val = "\""; break;
    default:
      vkboard.AltGr = false, vkboard.Shift = false;
      refresh_layout(container_id);
      break;
  }

  if(val && vkboard.Callback)
    eval(vkboard.Callback + (val == "\"" ? "('" + val + "')" : (val == "\\" ? "(\"\\\\\")" : "(\"" + val + "\")")));
}

// Layout info:

var avail_langs = new Array(Array("Az", "Azeri"));

// Azeri:

var Az_normal = new Array("&#x0027;", "&#x0031;", "&#x0032;", "&#x0033;", "&#x0034;", "&#x0035;", "&#x0036;", "&#x0037;", "&#x0038;", "&#x0039;", "&#x0030;", "&#x002D;", "&#x003D;",
                          "&#x0071;", "&#x00FC;", "&#x0065;", "&#x0072;", "&#x0074;", "&#x0079;", "&#x0075;", "&#x0069;", "&#x006F;", "&#x0070;", "&#x00F6;", "&#x011F;", "&#x005C;",
                          "&#x0061;", "&#x0073;", "&#x0064;", "&#x0066;", "&#x0067;", "&#x0068;", "&#x006A;", "&#x006B;", "&#x006C;", "&#x0131;", "&#x0259;", "",
                          "&#x007A;", "&#x0078;", "&#x0063;", "&#x0076;", "&#x0062;", "&#x006E;", "&#x006D;", "&#x00E7;", "&#x015F;", "&#x002E;");

var Az_caps = new Array("&#x0027;", "&#x0031;", "&#x0032;", "&#x0033;", "&#x0034;", "&#x0035;", "&#x0036;", "&#x0037;", "&#x0038;", "&#x0039;", "&#x0030;", "&#x002D;", "&#x003D;",
                        "&#x0051;", "&#x00DC;", "&#x0045;", "&#x0052;", "&#x0054;", "&#x0059;", "&#x0055;", "&#x0130;", "&#x004F;", "&#x0050;", "&#x00D6;", "&#x011E;", "&#x005C;",
                        "&#x0041;", "&#x0053;", "&#x0044;", "&#x0046;", "&#x0047;", "&#x0048;", "&#x004A;", "&#x004B;", "&#x004C;", "&#x0049;", "&#x018F;", "",
                        "&#x005A;", "&#x0058;", "&#x0043;", "&#x0056;", "&#x0042;", "&#x004E;", "&#x004D;", "&#x00C7;", "&#x015E;", "&#x002C;");

var Az_shift = new Array("&#x0022;", "&#x0021;", "&#x0040;", "&#x0023;", "&#x0024;", "&#x0025;", Array("&#x005E;", "Circumflex"), "&#x0026;", "&#x002A;", "&#x0028;", "&#x0029;", "&#x005F;", "&#x002B;",
                         "&#x0051;", "&#x00DC;", "&#x0045;", "&#x0052;", "&#x0054;", "&#x0059;", "&#x0055;", "&#x0130;", "&#x004F;", "&#x0050;", "&#x00D6;", "&#x011E;", "&#x007C;",
                         "&#x0041;", "&#x0053;", "&#x0044;", "&#x0046;", "&#x0047;", "&#x0048;", "&#x004A;", "&#x004B;", "&#x004C;", "&#x0049;", "&#x018F;", "",
                         "&#x005A;", "&#x0058;", "&#x0043;", "&#x0056;", "&#x0042;", "&#x004E;", "&#x004D;", "&#x00C7;", "&#x015E;", "&#x003F;");
