/*
 *  Guacamole - Pure JavaScript/HTML VNC Client
 *  Copyright (C) 2010  Michael Jumper
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see .
 */
function GuacamoleOnScreenKeyboard(url) {
    var tabIndex = 1;
    var allKeys = new Array();
    var modifierState = new function() {};
    function getKeySize(size) {
        return (5*size) + "ex";
    }
    function getCapSize(size) {
        return (5*size - 0.5) + "ex";
    }
    function clearModifiers() {
        // Send key release events for all pressed modifiers
        for (var k=0; k 0)
            return true;
        return false;
    }
    function toggleModifierPressed(modifier) {
        if (isModifierActive(modifier))
            setModifierReleased(modifier);
        else
            setModifierPressed(modifier);
    }
    function refreshAllKeysState() {
        for (var k=0; k= 0x0000 && charCode <= 0x00FF)
                    keysym = charCode;
                else if (charCode >= 0x0100 && charCode <= 0x10FFFF)
                    keysym = 0x01000000 | charCode;
            }
            // Required modifiers for this keycap
            var reqMod = null;
            if (cap.attributes["if"])
                reqMod = cap.attributes["if"].value.split(",");
            // Modifier represented by this keycap
            var modifier = null;
            if (cap.attributes["modifier"])
                modifier = cap.attributes["modifier"].value;
            
            // Whether this key is sticky (toggles)
            // Currently only valid for modifiers.
            var sticky = false;
            if (cap.attributes["sticky"] && cap.attributes["sticky"].value == "true")
                sticky = true;
            this.getDisplayText = function() {
                return cap.textContent;
            };
            this.getKeySym = function() {
                return keysym;
            };
            this.getRequiredModifiers = function() {
                return reqMod;
            };
            this.getModifier = function() {
                return modifier;
            };
            this.isSticky = function() {
                return sticky;
            };
        }
        var size = null;
        if (key.attributes["size"])
            size = parseFloat(key.attributes["size"].value);
        var caps = key.getElementsByTagName("cap");
        var keycaps = new Array();
        for (var i=0; i can contain  or 
            if (child.tagName == "key") {
                var key = new Key(child);
                keyboardRow.appendChild(key);
                allKeys.push(key);
            }
            else if (child.tagName == "gap") {
                var gap = new Gap(child);
                keyboardRow.appendChild(gap);
            }
            else if (child.tagName == "column") {
                var col = new Column(child);
                keyboardRow.appendChild(col);
            }
        }
        return keyboardRow;
    }
    function Column(col) {
        var keyboardCol = document.createElement("div");
        keyboardCol.className = "col";
        var align = null;
        if (col.attributes["align"])
            align = col.attributes["align"].value;
        var children = col.childNodes;
        for (var j=0; j can only contain  
            if (child.tagName == "row") {
                var row = new Row(child);
                keyboardCol.appendChild(row);
            }
        }
        if (align)
            keyboardCol.style.textAlign = align;
        return keyboardCol;
    }
    // Create keyboard
    var keyboard = document.createElement("div");
    keyboard.className = "keyboard";
    // Retrieve keyboard XML
    var xmlhttprequest = new XMLHttpRequest();
    xmlhttprequest.open("GET", url, false);
    xmlhttprequest.send(null);
    var xml = xmlhttprequest.responseXML;
    if (xml) {
        // Parse document
        var root = xml.documentElement;
        if (root) {
            var children = root.childNodes;
            for (var i=0; i can contain  or 
                if (child.tagName == "row") {
                    keyboard.appendChild(new Row(child));
                }
                else if (child.tagName == "column") {
                    keyboard.appendChild(new Column(child));
                }
            }
        }
    }
    var keyPressedHandler = null;
    var keyReleasedHandler = null;
    keyboard.setKeyPressedHandler = function(kh) { keyPressedHandler = kh; };
    keyboard.setKeyReleasedHandler = function(kh) { keyReleasedHandler = kh; };
    // Do not allow selection or mouse movement to propagate/register.
    keyboard.onselectstart =
    keyboard.onmousemove   =
    keyboard.onmouseup     =
    keyboard.onmousedown   =
    function(e) {
        e.stopPropagation();
        return false;
    };
    return keyboard;
}