views:

43

answers:

1

I'm working on a javascript keyboard that seeks to enable users to type in various African languages.Currently, this works fine in IE8 and firefox but not google chrome, and I'm actually stuck on this one.What I want to accomplish is for example, to type(on my physical keyboard) 'q'(keyCode=113) and get 'ɛ'(keyCode=603) as the output but currently, my code does nothing in google chrome. The relevant portion of my code is as follows:

var k_layouts = {};  
k_layouts.Akan = {88:390,113:603};//keyCode mappings for Akan language    
k_layouts.Ga = {120:596,81:400};//keyCode mappings for Ga language  
var current_layout = "";  

//function that maps the keyCode of a **typed** key to that of the **expected** key    
function map_key_code(keycode){  
    if(k_layouts[current_layout] && k_layouts[current_layout][keycode])  
        return k_layouts[current_layout][keycode];  
    return keycode;  
}  

//function that actually changes the keyCode of a **typed** key to the **expected** value
function handle_keypress(ev){  
    var ev = ev || window.event;  
    if(ev.bubbles != null ||!ev.bubbles)  
     return true;  
    var target = ev.target || ev.srcElement;  
    var keyCode = window.event? ev.keyCode: ev.which;  
    if(keyCode == 0)  
    return true;  
    var newKeyCode = map_key_code(keyCode);  
    if(newKeyCode == keyCode)  
    return true;  
    if(target.addEventListener){ //for chrome and firefox  
    //cancel event  
    ev.preventDefault();  
    ev.stopPropagation();  
    //create new event with the keycode changed  
    var evt = document.createEvent("KeyboardEvent");  
    try{//for firefox(works fine)  
        evt.initKeyEvent("keypress",false,true,document.defaultView,ev.ctrlKey,ev.altKey,ev.shiftKey,ev.metaKey,newKeyCode,newKeyCode);  
}  
    catch(e){// for google chrome(does not work as expected)  
        evt.initKeyboardEvent("keydown",false,true,document.defaultView,ev.ctrlKey,ev.altKey,ev.shiftKey,ev.metaKey,newKeyCode,newKeyCode);  
    }  
    //dispatch new event  
    target.dispatchEvent(evt);  
    }  
    else if(target.attachEvent){// works for IE  
        ev.keyCode = newKeyCode;  
    }  
} 

Is there a way of achieving what I seek to do in chrome?Or, is there something I'm missing in my approach?I'd be glad for any help, and any thoughts.

+1  A: 

It would be easier not to create a new event, which as you observed is not universally supported, and instead cancel the event and insert the mapped character corresponding to the character typed.

Assuming the user is typing into a textarea with id "ta", the following will handle keyboard input for that textarea in all the major browsers, mapping q to ɛ and all other characters to "X" for illustrative purposes:

var charMap = {
    "q": "ɛ"
};

document.getElementById("ta").onkeypress = function(evt) {
    var val = this.value;
    evt = evt || window.event;

    // Ensure we only handle printable keys, excluding enter and space
    var charCode = typeof evt.which == "number" ? evt.which : evt.keyCode;
    if (charCode && charCode != 13 && charCode != 32) {
        var keyChar = String.fromCharCode(charCode);

        // Get the mapped character (default to "X" for illustration purposes)
        var mappedChar = charMap[keyChar] || "X";

        var start, end;
        if (typeof this.selectionStart == "number" && typeof this.selectionEnd == "number") {
            // Non-IE browsers and IE 9
            start = this.selectionStart;
            end = this.selectionEnd;
            this.value = val.slice(0, start) + mappedChar + val.slice(end);

            // Move the caret
            this.selectionStart = this.selectionEnd = start + 1;
        } else if (document.selection && document.selection.createRange) {
            // For IE up to version 8
            var selectionRange = document.selection.createRange();
            var textInputRange = this.createTextRange();
            var precedingRange = this.createTextRange();
            var bookmark = selectionRange.getBookmark();
            textInputRange.moveToBookmark(bookmark);
            precedingRange.setEndPoint("EndToStart", textInputRange);
            start = precedingRange.text.length;
            end = start + selectionRange.text.length;

            this.value = val.slice(0, start) + mappedChar + val.slice(end);
            start++;

            // Move the caret
            textInputRange = this.createTextRange();
            textInputRange.collapse(true);
            textInputRange.move("character", start - (this.value.slice(0, start).split("\r\n").length - 1));
            textInputRange.select();
        }

        return false;
    }
};
Tim Down
Hi Tim Down, Your solution is perfect and works! I'm grateful.It's been nice being your student :P Enjoy!
ceblay
No problem. It seemed an interesting question and I happened to have written about half of it for another question recently.
Tim Down