The standard key handling in VNC protocol is a very bad match for virtualization because it involves sending X keysyms to the server. Hardware scancodes on the VNC client machine are turned into key syms, which are sent to QEMU, which then turns them back into harware scancodes which sends them to the guest which turns them back into key syms again. For this to stand any chance of working at all, the keymaps on your local laptop needs to match the keymap set in QEMU, which needs to match the keymap set inside the guest. Even then it is often not perfect.
Thus QEMU defined a VNC protocol extension for send hardware scancodes from the VNC client. This avoids any kind of translation on the VNC client machine, or in QEMU. Hardware scancodes are sent from VNC client to QEMU, which sends them to the guest. Only the guest needs todo translation.
The virt-viewer application uses the GTK-VNC library which supports this protocol extension and hence why it works nicely for you.
The remote-viewer application is part of the same codebase as virt-viewer and thus can provide a plain VNC client which correctly supports this protocol extension.
It is really not worth trying to configure keymaps with QEMU as the result will always be worse than using the VNC protocol extension for scancodes.
Most historical VNC client does not support the extension, but one that I believe does do it correctly is tigervnc. So if you don't/can't use virt-viewer or remote-viewer, then try using tigervnc.