Why are you trying to use scan code set 1? Every real OS uses scan code set 2, so it's possible VirtualBox simply can't handle set 1.
qookie wrote:
The code works correctly [...] on real hardware
I'm surprised it works on real hardware, since you're not waiting for the keyboard controller to be ready before you send each byte. Actually, the hardware you're using probably doesn't have a "real" keyboard controller, since it should take hundreds of microseconds to send a single byte to the keyboard, and a "real" keyboard controller can't accept another byte while it sends the first one.
Since you're able to get the scan code set but not set it, the lack of appropriate delays is probably not why VirtualBox doesn't work - but emulators are known to be inaccurate, so it's still a possibility.