How can I prevent user typing certain letters?

       function NumberKey(event) {
            let charCode = event.which || event.keyCode;
            console.log(event.keyCode)
            if ((charCode >= 48 && charCode <= 57) || //  Number (0-9)
                (charCode >= 96 && charCode <= 105) || // Numberpad (0-9)
                (charCode >=112 && charCode <= 123)|| // F keys (F1~12)
                charCode === 8 || // backspace
                charCode === 9 || // tab
                charCode === 13|| // enter
                charCode === 37 || // arrow left
                charCode === 39 || // arrow right
                charCode === 46){ // delete
            }else{
            event.preventDefault();
            return false;
            }
        }

this is my code to prevent user typing anything else than numbers

and when I apply it as

onkeydown=”return NumberKey(event)”

{% (with shift)
`qwertyuipasdfgh’zxcvb. (without shift)
+IME based languages
are typable

onkeypress=”return NumberKey(event)”

!@#$%^&*() (with shift)
+IME based languages
are typable

When I apply both,
% (with shift)
+IME based languages
are typable

I do not understand certain things about this result

  1. Why would onkeypress and onkeydown give different result?

  2. Why does onkeypress let % printed while it block all the rest special letters?

And for the other issue, I need help

Through console, I figured out that IME based languages are not counted as event.
I’ve done some searching, finding out that IME takes the letter away as part of composition,
which eventually never let me take the letter before it is shown on the screen.

I knew input type=”password” would force IME to be disabled,
forcing user to type English only.
Which was fascinating just except that the letters are hidden,
so I can’t use them for phone numbers or IDs

tried ime-mode:disabled, found out it was deprecated for security issue long time ago.

Many people I found on web just let the user type whatever
and delete afterwards if typed items do not satisfy certain conditions,
which is definitely not what I want…

document.addEventListener('DOMContentLoaded', function() {
    const inputElement = document.getElementById('yourInputElementId');
    inputElement.addEventListener('compositionstart', function(event) {
        event.preventDefault();
    });
    inputElement.addEventListener('compositionupdate', function(event) {
        event.preventDefault();
    });
    inputElement.addEventListener('compositionend', function(event) {
        event.preventDefault();
    });
});

This is what ChatGPT suggested, which didn’t work at all.

Oh and I forgot to say that I tried regex too, which didn’t work the way I wanted…
Here’s some regex I tried

        function NumberKey(evt) {
            let charCode = evt.which || evt.keyCode;
            let charStr = String.fromCharCode(charCode);
            let numcheck = /^[a-zA-Zㄱ-ㅎ가-힣]$/;
            if (numcheck.test(charStr)) {
                evt.preventDefault();
                return false;  
            } else {
                return true;
            }

        function NumberKey(evt) {
            let charCode = evt.which || evt.keyCode;
            let charStr = String.fromCharCode(charCode);
            let numcheck = /^[0-9]$/;
            if (numcheck.test(charStr)) {
                return true; 
            } else {
                evt.preventDefault();
                return false; 
            }

Sorry for writing too long
Please help me! I’ve been holding on to this for days!