Reputation: 2026
How to send a string to a virtualbox-guest-machine?
This is my code:
public void testKeyboard() throws Exception {
IVirtualBox b = connect();
List<IMachine> machines = b.getMachines();
for (IMachine m : machines) {
MachineState d = b.getMachineStates(Arrays.asList(m)).iterator().next();
if (d == MachineState.Running) {
ISession s = manager.getSessionObject();
m.lockMachine(s, LockType.Shared);
IConsole console = s.getConsole();
IKeyboard k = console.getKeyboard();
k.putScancodes(Arrays.asList(25, 25 | 0x80)); // <- sends the character P
s.unlockMachine();
}
}
}
java.awt.event.KeyEvent also say its 0x50:
/** Constant for the "P" key. */
public static final int VK_P = 0x50;
In virtualbox its different. P=25 2=0x50 b=0x30
Why in the world is the code of P = 25 in virtualbox?
Upvotes: 4
Views: 185
Reputation: 50041
Virtual key codes and keyboard scan codes are two different things.
Keyboards (still) talk to PCs using a really dusty old protocol. Many years ago I implemented a toy version of the protocol in an OS driver and it was quite annoying. Making it worse, keyboards can use 3 different sets of keyboard scancodes which originated with different flavors of old PCs.
Here is a reference for the 3 sets: https://www.vetra.com/scancodes.html
The constants you discovered line up with Set 1. Note that Set 1 has different codes used to press the key and release the key!
The virtual key constants used by the Java KeyEvent class and by that Windows list both seem to be based closely on ASCII characters, since 'P' = 0x50 in ASCII. But it's the job of the operating system keyboard driver to translate from keyboard scancodes to more logical sets of constants. There is no universal constant for a key.
Since VirtualBox is emulating the physical keyboard interface to the guest OS, its IKeyboard
API takes raw scancodes.
For the VirtualBox GUI, it must have a function which translates from host OS key constants back to scancodes for the guest OS, which might be easier if you can use that, but IKeyboard
appears to be a very low-level interface which bypasses that.
Depending on your use case, perhaps there is a different API you can also use here; or perhaps you can control your VM with guest software like SSH or VNC.
Upvotes: 2
Reputation: 20344
Scan codes are keyboard layout dependent mappings to key layouts. You can send codes based on the scan codes for a USB keyboard, which all modern systems are likely to understand. The codes are documented in Appendix C of the Microsoft document "Keyboard Scan Code Specification". You will see there that character P
is in position 26 in the 1-indexed table of key location. This would explain a 0-indexed code of 25 producing the character P
.
You will see that "key down" needs you to send 25 as the scan code (0x19) and then 0x99 for key up. This is what your (25 | 0x80) is doing. So your code at the moment sends a message meaning "Key P has been pressed (make in the table)" followed by "Key P has been released (break in the table)"
The direct link to the doc I'm referencing here is: https://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc
N.B. These codes are quite different to ASCII codes, which are where you are getting the 0x50 from.
If you want to send a whole string via the keyboard this way, what you will need is a mapping table from ASCII codes for each character to key make and key break codes. You can then take the string character by character and work out which scan code pairs to send for each character. Note - you'll need to deal with case by adding a "Shift down" before the pair and "Shift up" afterwards. This is do-able with a fairly long mapping table, I'd use a WeakHashMap
Upvotes: 0