Как вариант может подойти wm_char, но есть ограничения. Описан тут (там же можно найти и другую инфу по сообщениям и работе с клавиатурой).
Также сказано, что при отсутствии фокуса следует посылать wm_SysChar.
Чтобы не было обломов, следует учесть две вещи:
*Некоторые сообщения возвращают ответ.
*Некоторые сообщения в параметрах lparam/wparam передают дополнительную информацию, без которой ничего не выйдет.
Для исключения таких ситуаций следует внимательно изучить все параметры выбранного сообщения, и желательно в первоисточнике.
Некоторые параметры необязательны, другие-же имеют сложную структуру(описанную в msdn), третьи вообще не используются. Так-же и с ответами.
И, как уже сказали, нужно экспериментировать. Неизвестно, что именно ждет ваша программа на входе, как она работает с клавиатурой, как она реагирует на фокус и сворачивание (некоторые игры при сворачивании автоматически останавливаются).
ClassName=GxWindowClassD3d
Caption=игра
Для надежности имеет смысл применить компонент WinEnum. Он переберет окна по заголовкам и найдет нужное окно, а заодно скажет его класс (только он уже не нужен - хэндл уже есть).
Caption=игра
Вообще игры, как и браузеры, не имеют WinApi, за исключением главного окна. Все внутри своего окна они рисуют самостоятельно. Потому если не удастся обмануть окно с помощью сообщений, останется только внедрить в игру свою процедуру. Это сложный путь, и я, например, его не потяну.
Например простейший сканер клавиатуры на blitz3D так и не удалось ничем обмануть - он железно вцепился в настоящую клавиатуру.