Ainda outra versão, clara e simples, lida com capsLock deslocado, e não restrita a ascii, penso:
document.onkeypress = function (e)
{
e = e || window.event;
if (e.charCode === 0 || e.ctrlKey || document.onkeypress.punctuation.indexOf(e.charCode) >= 0)
return;
var s = String.fromCharCode(e.charCode); // or e.keyCode for compatibility, but then have to handle MORE non-character keys
var s2 = e.shiftKey ? s.toUpperCase() : s.toLowerCase();
var capsLockOn = (s2 !== s);
document.getElementById('capslockWarning').style.display = capsLockOn ? '' : 'none';
}
document.onkeypress.punctuation = [33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,91,92,93,94,95,96,123,124,125,126];
Edit: O sentido de capsLockOn foi revertido, doh, corrigido.
Editar # 2: depois de verificar isso um pouco mais, fiz algumas alterações, um código um pouco mais detalhado, infelizmente, mas ele lida com mais ações de maneira apropriada.
O uso de e.charCode em vez de e.keyCode e a verificação de valores 0 ignoram muitas pressionamentos de tecla sem caracteres, sem codificar nada específico para um determinado idioma ou conjunto de caracteres. Pelo que entendi, é um pouco menos compatível, portanto navegadores mais antigos, não convencionais ou móveis podem não se comportar conforme o esperado, mas vale a pena, de qualquer maneira, para a minha situação.
A verificação em uma lista de códigos de pontuação conhecidos evita que eles sejam vistos como falsos negativos, pois não são afetados pelo caps lock. Sem isso, o indicador caps lock fica oculto quando você digita algum desses caracteres de pontuação. Ao especificar um conjunto excluído, em vez de um incluído, ele deve ser mais compatível com caracteres estendidos. Esse é o bit mais feio e mais especial, e há algumas chances de que os idiomas não ocidentais tenham códigos de pontuação e / ou pontuação diferentes o suficiente para serem um problema, mas novamente vale a pena IMO, pelo menos para a minha situação.