コード例 #1
0
        // Note: Sometimes single VKCode represents multiple chars, thus string.
        // E.g. typing "^1" (notice that when pressing 1 the both characters appear,
        // because of this behavior, "^" is called dead key)

        /// <summary>
        ///     Convert VKCode to Unicode.
        ///     <remarks>isKeyDown is required for because of keyboard state inconsistencies!</remarks>
        /// </summary>
        /// <param name="vkCode">VKCode</param>
        /// <param name="isKeyDown">Is the key down event?</param>
        /// <returns>String representing single unicode character.</returns>
        internal static string VkCodeToString(uint vkCode, bool isKeyDown)
        {
            // ToUnicodeEx needs StringBuilder, it populates that during execution.
            var sbString = new StringBuilder(5);

            var  bKeyState = new byte[255];
            bool bKeyStateStatus;
            bool isDead = false;

            // Gets the current windows window handle, threadID, processID
            IntPtr currentHWnd           = (IntPtr)DllUser32.GetForegroundWindow();//may be bag
            uint   currentWindowThreadId = DllUser32.GetWindowThreadProcessId(currentHWnd, out _);

            // This programs Thread ID
            uint thisProgramThreadId = DllUser32.GetCurrentThreadId();

            // Attach to active thread so we can get that keyboard state
            if (DllUser32.AttachThreadInput(thisProgramThreadId, currentWindowThreadId, true))
            {
                // Current state of the modifiers in keyboard
                bKeyStateStatus = DllUser32.GetKeyboardState(bKeyState);

                // Detach
                DllUser32.AttachThreadInput(thisProgramThreadId, currentWindowThreadId, false);
            }
            else
            {
                // Could not attach, perhaps it is this process?
                bKeyStateStatus = DllUser32.GetKeyboardState(bKeyState);
            }

            // On failure we return empty string.
            if (!bKeyStateStatus)
            {
                return("");
            }

            // Gets the layout of keyboard
            var hkl = DllUser32.GetKeyboardLayout(currentWindowThreadId);

            // Maps the virtual keycode
            uint lScanCode = DllUser32.MapVirtualKeyEx(vkCode, 0, hkl);

            // Keyboard state goes inconsistent if this is not in place. In other words, we need to call above commands in UP events also.
            if (!isKeyDown)
            {
                return("");
            }

            // Converts the VKCode to unicode
            int relevantKeyCountInBuffer =
                DllUser32.ToUnicodeEx(vkCode, lScanCode, bKeyState, sbString, sbString.Capacity, 0, hkl);

            string ret = string.Empty;

            switch (relevantKeyCountInBuffer)
            {
            // Dead keys (^,`...)
            case -1:
                isDead = true;

                // We must clear the buffer because ToUnicodeEx messed it up, see below.
                ClearKeyboardBuffer(vkCode, lScanCode, hkl);
                break;

            case 0:
                break;

            // Single character in buffer
            case 1:
                ret = sbString[0].ToString();
                break;

            // Two or more (only two of them is relevant)
            default:
                ret = sbString.ToString().Substring(0, 2);
                break;
            }

            // We inject the last dead key back, since ToUnicodeEx removed it.
            // More about this peculiar behavior see e.g:
            //   http://www.experts-exchange.com/Programming/System/Windows__Programming/Q_23453780.html
            //   http://blogs.msdn.com/michkap/archive/2005/01/19/355870.aspx
            //   http://blogs.msdn.com/michkap/archive/2007/10/27/5717859.aspx
            if (_lastVkCode != 0 && _lastIsDead)
            {
                var sbTemp = new StringBuilder(5);
                DllUser32.ToUnicodeEx(_lastVkCode, _lastScanCode, _lastKeyState, sbTemp, sbTemp.Capacity, 0, hkl);
                _lastVkCode = 0;

                return(ret);
            }

            // Save these
            _lastScanCode = lScanCode;
            _lastVkCode   = vkCode;
            _lastIsDead   = isDead;
            _lastKeyState = (byte[])bKeyState.Clone();

            return(ret);
        }