В итоге использовал затычку для клавиш с помощью простой обертки над JNA:
class WinXP {
private static boolean isXP;
private static Map<Integer, Integer> faultyXPCodes = new HashMap<>();
static {
String os = System.getProperty("os.name").toLowerCase();
isXP = os.startsWith("windows") && os.contains("xp");
faultyXPCodes.put(91 , 0x1A); // [
faultyXPCodes.put(93 , 0x1B); // ]
faultyXPCodes.put(92 , 0x2B); // \
faultyXPCodes.put(59 , 0x27); // ;
faultyXPCodes.put(222, 0x28); // '
faultyXPCodes.put(44 , 0x33); // ,
faultyXPCodes.put(46 , 0x34); // .
faultyXPCodes.put(47 , 0x35); // /
}
private static boolean isFaulty(int code) {
return isXP && faultyXPCodes.containsKey(code);
}
private static WinUser.INPUT PrepareInput(int flag, int code) {
final WinUser.INPUT input = new WinUser.INPUT();
input.type = new WinDef.DWORD(WinUser.INPUT.INPUT_KEYBOARD);
input.input.setType("ki");
input.input.ki.wScan = new WinDef.WORD(0x0);
input.input.ki.time = new WinDef.DWORD(0x0);
input.input.ki.dwFlags = new WinDef.DWORD(flag | 0x8);
input.input.ki.dwExtraInfo = new BaseTSD.ULONG_PTR(0x0);
input.input.ki.wScan = new WinDef.WORD(faultyXPCodes.get(code));
return input;
}
private static void SendInput(WinUser.INPUT input) {
User32.INSTANCE.SendInput(
new WinDef.DWORD(1),
(WinUser.INPUT[]) input.toArray(1),
input.size()
);
}
private static void Press(int code) {
SendInput(PrepareInput(0x0, code));
}
private static void Release(int code) {
SendInput(PrepareInput(0x2, code));
}
}