private IntPtr keyboardHandler(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT kbdStruct)
        {
            IntPtr ret;

            try
            {
                if (nCode >= 0)
                {
                    var virtualKeyCode = (Keys) kbdStruct.KeyCode;
                    var keyData = BuildKeyData(virtualKeyCode);
                    var keyEventArgs = new KeyEventArgs(keyData);

                    var intParam = wParam.ToInt32();
                    switch (intParam)
                    {
                        case NativeMethods.WM_SYSKEYDOWN:
                        case NativeMethods.WM_KEYDOWN:
                            RaiseKeyDownEvent(keyEventArgs);

                            var buffer = ToUnicode(kbdStruct);
                            if (!string.IsNullOrEmpty(buffer))
                            {
                                foreach (var rawKey in buffer)
                                {
                                    var s = _keyConverter.ConvertToString(rawKey);
                                    if (s == null) continue;

                                    var key = s[0];
                                    RaiseKeyPressEvent(key);
                                }
                            }
                            break;
                        case NativeMethods.WM_SYSKEYUP:
                        case NativeMethods.WM_KEYUP:
                            RaiseKeyUpEvent(keyEventArgs);
                            break;
                    }
                    if(keyEventArgs.SuppressKeyPress) return new IntPtr(1);
                }
            }
            finally
            {
                ret = NativeMethods.CallNextHookEx(_previousKeyboardHandler, nCode, wParam, ref kbdStruct);
            }

            return ret;
        }
 internal static extern IntPtr CallNextHookEx(SafeWinHandle hhk, int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);
 internal static extern IntPtr CallNextHookEx(SafeWinHandle hhk, int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);
            public DeadKeyInfo(KBDLLHOOKSTRUCT info, byte[] keyState)
            {
                KeyCode = (Keys) info.KeyCode;
                ScanCode = info.ScanCode;

                KeyboardState = keyState;
            }
        private static string ToUnicode(KBDLLHOOKSTRUCT info)
        {
            string result = null;

            var keyState = new byte[256];
            var buffer = new StringBuilder(128);

            var success = NativeMethods.GetKeyboardState(keyState);
            if(!success) return string.Empty;

            var isAltGr = IsKeyPressed(NativeMethods.VK_RMENU) && IsKeyPressed(NativeMethods.VK_LCONTROL);
            if (isAltGr) keyState[NativeMethods.VK_LCONTROL] = keyState[NativeMethods.VK_LALT] = 0x80;

            var layout = GetForegroundKeyboardLayout();
            var count = ToUnicode((Keys) info.KeyCode, info.ScanCode, keyState, buffer, layout);

            if (count > 0)
            {
                result = buffer.ToString(0, count);

                if (_lastDeadKey != null)
                {
                    ToUnicode(_lastDeadKey.KeyCode,
                              _lastDeadKey.ScanCode,
                              _lastDeadKey.KeyboardState,
                              buffer,
                              layout);

                    _lastDeadKey = null;
                }
            }
            else if (count < 0)
            {
                _lastDeadKey = new DeadKeyInfo(info, keyState);

                while (count < 0)
                {
                    count = ToUnicode(Keys.Decimal, buffer, layout);
                }
            }

            return result;
        }