Вот с исправленным шифтом.
Про ИЕ (ctrl+Z) пока ничего не придумал.
function setMask(I,M){
M = M.split('').join('|');
if (/z/.test(M)) M = M.replace(/z/g,'[a-z]');
else if (/я/.test(M)) M = M.replace(/я/g,'[а-яё]');
else if (/a/.test(M)) M = M.replace(/a/g,'[a-zа-яё]');
else if (/\*/.test(M)) M = M.replace(/\*/g,'[a-zа-яё0-9]');
M = M.replace(/\(/g,'\\(').replace(/\)/g,'\\)').replace(/\//g,'\\/').replace(/9/g,'\\d').replace(/\./g,'\\.');
var r = new RegExp(M,'i'), d=document, c='character', y=-100000;
function V(){
setTimeout(function(k){
s=I.gC()[0];
var a=I.value.split(''),x=[];
for(var i=0;i<a.length;i++)if(r.test(a[i]))x.push(a[i]);else s--;
I.value=x.join('');
I.sC(s);
},0)
}
I = typeof I=='string' ? d.getElementById(I) : I;
I.onkeypress = function(e){
e=e||event;
if(e.ctrlKey||e.shiftKey)return true;
V();
return true
}
I.sC = function(l,g){
if(this.setSelectionRange) this.setSelectionRange(l,l);
else {
g = this.createTextRange();
g.collapse(true);
g.moveStart(c,y);
g.move(c,l);
g.select();
}
}
I.gC = function(r,b){
if (this.setSelectionRange) return [this.selectionStart,this.selectionEnd];
else {
r = d.selection.createRange();
b = 0-r.duplicate().moveStart(c,y)
return [b,b+r.text.length]
}
}
if (d.all&&!window.opera) I.onpaste=V;
else I.addEventListener('input',V,false)
}