Can I conditionally change the character entered into an input on keypress?

The following will do the job. It’s based on an answer I wrote to another question. Customize the transformTypedChar function to suit your needs; my example capitalizes only the letters a-g.

If you need this on a textarea rather than an <input type="text"> then be aware that there are issues in IE <= 8 with line breaks that the following code doesn’t handle for the sake of brevity. You can find the cross browser function for obtaining the selection within a textarea here: Is there an Internet Explorer approved substitute for selectionStart and selectionEnd?

function transformTypedChar(charStr) {
    return /[a-g]/.test(charStr) ? charStr.toUpperCase() : charStr;
}

document.getElementById("your_input_id").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 > 32) {
        var keyChar = String.fromCharCode(charCode);

        // Transform typed character
        var mappedChar = transformTypedChar(keyChar);

        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;
    }
};

Leave a Comment