Siento decirte que según mis informaciones es símplemente imposible hacerlo en VBNET (al menos usando un hook de bajo nivel como haces),
es más, si quisieras hacerlo en otro lenguaje necesitarías pasar a un siguiente nivel muy superior de experiencia para escribir el hook, inyectarlo, hacerlo compatible con 64 bits, y bypassear UAC.
Intenté solucionar el mismo problema, pero mis capacidades para esto son igual de limitadas e inexpertas, te cito la respuesta a mi problema por parte de un Dios de la programación, para que lo entiendas mejor:
You can never write a correct low-level keyboard hook that translates virtual keys to typing keys. The keyboard state and the active keyboard layout are properties of the process that owns the foreground window. Never of the process that implements the hook.
In particular the keyboard state will be wrong, you don't know if the logical state of the keyboard for the process has the shift, alt, control and Windows key active. That state is recorded when the program receives a keyboard event. Particular to a keyboard layout for languages that use diacritics are the state of the dead keys, the ones you type to get the next typed letter to have an accent. This keyboard state is a per-process state and cannot be retrieved from another process. It is only discoverable within the process itself, GetKeyboardState() function. Much the same for the active keyboard layout, GetKeyboardLayout() function. The language bar allows processes to use different layouts.
It can only ever work 100% correctly when you use a WH_KEYBOARD hook. It requires a DLL that can be injected into other processes. The 3rd argument of SetWindowsHookEx(). Which ensures that GetKeyboardState and GetKeyboardLayout return accurate information. You cannot write such a DLL in VB.NET, the process you inject won't have the CLR loaded to execute managed code. A language like C, C++ or Delphi is required, languages that have very modest runtime support requirements. This is usually where the project peters out. Not just because of the runtime injection problem, debugging such code and dealing with the bitness of a process on a 64-bit operating system as well as UAC are major headaches.
You can limp along somewhat by using GetAsyncKeyState() to get the state of the modifier keys. There is no solution for dead keys other than an injected DLL. This is not a helpful answer, it merely explains why you can never make it work completely reliably in vb.net.
The mapping of Keys.Oemtilde to a typing key is the job of the keyboard layout. Different keyboards produce different letters for that key. The underlying winapi function is ToUnicodeEx(). Note how it requires the keyboard state and layout as I described.
Si quieres leer el resto:
http://stackoverflow.com/questions/16893190/issue-with-the-keys-enumeration-and-a-low-level-keyboard-hook#comment24389665_16900034EDITO: y esto por otra parte para aclarártelo aún más:
A global WH_KEYBOARD hook however executes in teh context of the app. that is recieving the keyboard message so your code has to be injected into every running process. This is NOT a good idea IMHO.
Saludos