Ejemplo n.º 1
0
        void ProcessKeyShiftState(IntPtr hkl, KeysEx[] lpKeyState, uint iKey, ShiftState ss, KeyboardLayoutContent kbl, Dictionary <char, DeadKey> deadKeys)
        {
            // Skip Alt and Shift+Alt because they ain't supported
            if (ss == ShiftState.Menu || ss == ShiftState.ShftMenu)
            {
                return;
            }

            // Scratchpad used in many places
            StringBuilder sbBuffer;

            for (int caps = 0; caps <= 1; caps++)
            {
                Utilities.ClearKeyboardBuffer((uint)KeysEx.VK_DECIMAL, kbl.Keys[(uint)KeysEx.VK_DECIMAL].SC, hkl);
                Utilities.FillKeyState(kbl, lpKeyState, ss, (caps == 0));
                sbBuffer = new StringBuilder(10);
                int rc = NativeMethods.User32.ToUnicodeEx((uint)kbl.Keys[iKey].VK, kbl.Keys[iKey].SC, lpKeyState, sbBuffer, sbBuffer.Capacity, 0, hkl);
                if (rc > 0)
                {
                    if (sbBuffer.Length == 0)
                    {
                        // Someone defined NULL on the keyboard; let's coddle them
                        kbl.Keys[iKey].SetShiftState(ss, "\u0000", false, (caps == 0));
                    }
                    else
                    {
                        if ((rc == 1) &&
                            (ss == ShiftState.Ctrl || ss == ShiftState.ShftCtrl) &&
                            ((uint)kbl.Keys[iKey].VK == ((uint)sbBuffer[0] + 0x40)))
                        {
                            // ToUnicodeEx has an internal knowledge about those
                            // VK_A ~ VK_Z keys to produce the control characters,
                            // when the conversion rule is not provided in keyboard
                            // layout files
                            continue;
                        }
                        kbl.Keys[iKey].SetShiftState(ss, sbBuffer.ToString().Substring(0, rc), false, (caps == 0));
                    }
                }
                else if (rc < 0)
                {
                    kbl.Keys[iKey].SetShiftState(ss, sbBuffer.ToString().Substring(0, 1), true, (caps == 0));

                    // It's a dead key; let's flush out whats stored in the keyboard state.
                    Utilities.ClearKeyboardBuffer((uint)KeysEx.VK_DECIMAL, kbl.Keys[(uint)KeysEx.VK_DECIMAL].SC, hkl);
                    char ch = kbl.Keys[iKey].GetShiftState(ss, caps == 0).Characters[0];
                    if (deadKeys.ContainsKey(ch) == false)
                    {
                        DeadKey dk = Utilities.ProcessDeadKey(kbl, iKey, ss, lpKeyState, kbl.Keys, caps == 0, hkl);
                        deadKeys.Add(ch, dk);
                    }
                }
            }
        }
Ejemplo n.º 2
0
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            // Get current keystroke and check if this is a new keystroke or
            // if it is a repeated one.
            KeyboardState state = Keyboard.GetState();

            VirtualKeyValue[] keystroke      = keyboardLayout.ProcessKeys(state);
            Keys[]            filteredStroke = keyboardLayout.FilteredPressedKeys;
            bool isNewStroke = true;

            if (previousStroke != null)
            {
                // Check scan codes to handle modifier+char to char transitions.
                // If two or more keys are pressed, the last one is used and when
                // this key is released, no keystroke is generated.

                int newKeyIndex = -1;
                int i;
                int j = 0;
                for (i = 0; i < filteredStroke.Length; i++)
                {
                    // KeyboardLayout.FilteredPressedKeys is sorted
                    while (j < previousStroke.Length && previousStroke[j] < filteredStroke[i])
                    {
                        j++;
                    }

                    if (j >= previousStroke.Length)
                    {
                        newKeyIndex = i;
                        break;
                    }
                    else if (previousStroke[j] > filteredStroke[i])
                    {
                        newKeyIndex = i;
                    }
                }

                if (newKeyIndex > -1)
                {
                    isNewStroke     = currentKeyValue != keystroke[newKeyIndex];
                    currentKeyValue = keystroke[newKeyIndex];
                }
                else
                {
                    isNewStroke = false;
                    if (keystroke.Length == 0)
                    {
                        currentKeyValue = VirtualKeyValue.Empty;
                    }
                }
            }

            for (int i = 0; i < keyStates.Length; i++)
            {
                keyStates[i] = KeyStateFlags.Up;
            }

            // If the keystroke is a new stroke, reset start time and update
            // key state flags to notify that the key was just released
            if (isNewStroke == true)
            {
                strokeStartTime = gameTime.TotalGameTime.TotalMilliseconds;
                repeatTimeCount = -1;

                if (previousStroke != null)
                {
                    foreach (Keys key in previousStroke)
                    {
                        keyStates[(int)key] = KeyStateFlags.Released;
                    }
                }
            }

            // Apply delay and repeat-speed to stroke age
            double        dt               = gameTime.TotalGameTime.TotalMilliseconds - strokeStartTime;
            bool          doSetString      = false;
            KeyStateFlags newKeyStateFlags = KeyStateFlags.Down;

            if (dt <= float.Epsilon)
            {
                // First stroke
                doSetString = true;
            }
            else if (repeatTimeCount == -1 && delayTime - dt < float.Epsilon)
            {
                // Repeat delay time reached
                doSetString     = true;
                repeatTimeCount = 0;

                newKeyStateFlags |= KeyStateFlags.Repeat;
            }
            else if (repeatTimeCount > -1)
            {
                dt -= delayTime;

                // Count stroke repeats
                int i;
                for (i = 0; dt > 0; i++)
                {
                    dt -= repeatTime;
                }

                if (i > repeatTimeCount)
                {
                    doSetString = true;
                    repeatTimeCount++;
                }

                newKeyStateFlags |= KeyStateFlags.Repeat;
            }

            // Build the current key strokes output
            characters = "";
            if (doSetString == true && keystroke.Length > 0)
            {
                VirtualKeyValue keyValue = currentKeyValue;
                if (deadKey != null)
                {
                    char baseChar = keyValue.Characters[0];
                    if (deadKey.ContainsBaseCharacter(baseChar) == true)
                    {
                        characters = deadKey.GetCombinedCharacter(baseChar).ToString();
                    }
                    else
                    {
                        characters = String.Format("{0}{1}", deadKey.DeadCharacter, baseChar);
                    }
                    deadKey = null;
                }
                else if (keyValue.IsDeadKey == true)
                {
                    keyboardLayout.DeadKeys.TryGetValue(keyValue.Characters[0], out deadKey);
                }
                else if (keyValue.Characters != null && Char.IsControl(keyValue.Characters, 0) == false)
                {
                    // Add non-control characters only
                    characters = keyValue.Characters;
                }
            }

            if (doSetString == true && filteredStroke.Length > 0)
            {
                // Update key state flags
                foreach (Keys key in filteredStroke)
                {
                    keyStates[(int)key] = newKeyStateFlags;
                }
            }

            previousStroke = filteredStroke;
        }
Ejemplo n.º 3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="iKeyDead">The index into the VirtualKey of the dead key</param>
        /// <param name="shiftStateDead">The shiftstate that contains the dead key</param>
        /// <param name="lpKeyStateDead">The key state for the dead key</param>
        /// <param name="rgKey">Our array of dead keys</param>
        /// <param name="fCapsLock">Was the caps lock key pressed?</param>
        /// <param name="hkl">The keyboard layout</param>
        /// <returns></returns>
        internal static DeadKey ProcessDeadKey(KeyboardLayoutContent kbl, uint iKeyDead, ShiftState shiftStateDead, KeysEx[] lpKeyStateDead, VirtualKeyContent[] rgKey, bool fCapsLock, IntPtr hkl)
        {
            KeysEx[] lpKeyState   = new KeysEx[256];
            String   dkShiftState = rgKey[iKeyDead].GetShiftState(shiftStateDead, fCapsLock).Characters;
            DeadKey  deadKey      = new DeadKey(dkShiftState[0]);

            for (uint iKey = 0; iKey < rgKey.Length; iKey++)
            {
                if (rgKey[iKey] != null)
                {
                    StringBuilder sbBuffer = new StringBuilder(10);                         // Scratchpad we use many places

                    for (ShiftState ss = ShiftState.Base; ss <= kbl.MaxShiftState; ss++)
                    {
                        int rc = 0;
                        if (ss == ShiftState.Menu || ss == ShiftState.ShftMenu)
                        {
                            // Alt and Shift+Alt don't work, so skip them
                            continue;
                        }

                        for (int caps = 0; caps <= 1; caps++)
                        {
                            // First the dead key
                            while (rc >= 0)
                            {
                                // We know that this is a dead key coming up, otherwise
                                // this function would never have been called. If we do
                                // *not* get a dead key then that means the state is
                                // messed up so we run again and again to clear it up.
                                // Risk is technically an infinite loop but per Hiroyama
                                // that should be impossible here.
                                rc = NativeMethods.User32.ToUnicodeEx((uint)rgKey[iKeyDead].VK, rgKey[iKeyDead].SC, lpKeyStateDead, sbBuffer, sbBuffer.Capacity, 0, hkl);
                            }

                            // Now fill the key state for the potential base character
                            FillKeyState(kbl, lpKeyState, ss, (caps != 0));

                            sbBuffer = new StringBuilder(10);
                            rc       = NativeMethods.User32.ToUnicodeEx((uint)rgKey[iKey].VK, rgKey[iKey].SC, lpKeyState, sbBuffer, sbBuffer.Capacity, 0, hkl);
                            if (rc == 1)
                            {
                                // That was indeed a base character for our dead key.
                                // And we now have a composite character. Let's run
                                // through one more time to get the actual base
                                // character that made it all possible?
                                char combchar = sbBuffer[0];
                                sbBuffer = new StringBuilder(10);
                                rc       = NativeMethods.User32.ToUnicodeEx((uint)rgKey[iKey].VK, rgKey[iKey].SC, lpKeyState, sbBuffer, sbBuffer.Capacity, 0, hkl);

                                char basechar = sbBuffer[0];

                                if (deadKey.DeadCharacter == combchar)
                                {
                                    // Since the combined character is the same as the dead key,
                                    // we must clear out the keyboard buffer.
                                    ClearKeyboardBuffer((uint)KeysEx.VK_DECIMAL, rgKey[(uint)KeysEx.VK_DECIMAL].SC, hkl);
                                }

                                if ((((ss == ShiftState.Ctrl) || (ss == ShiftState.ShftCtrl)) && (char.IsControl(basechar))) || (basechar.Equals(combchar)))
                                {
                                    // ToUnicodeEx has an internal knowledge about those
                                    // VK_A ~ VK_Z keys to produce the control characters,
                                    // when the conversion rule is not provided in keyboard
                                    // layout files

                                    // Additionally, dead key state is lost for some of these
                                    // character combinations, for unknown reasons.

                                    // Therefore, if the base character and combining are equal,
                                    // and its a CTRL or CTRL+SHIFT state, and a control character
                                    // is returned, then we do not add this "dead key" (which
                                    // is not really a dead key).
                                    continue;
                                }

                                if (!deadKey.ContainsBaseCharacter(basechar))
                                {
                                    deadKey.AddDeadKeyRow(basechar, combchar);
                                }
                            }
                            else if (rc > 1)
                            {
                                // Not a valid dead key combination, sorry! We just ignore it.
                            }
                            else if (rc < 0)
                            {
                                // It's another dead key, so we ignore it (other than to flush it from the state)
                                ClearKeyboardBuffer((uint)KeysEx.VK_DECIMAL, rgKey[(uint)KeysEx.VK_DECIMAL].SC, hkl);
                            }
                        }
                    }
                }
            }
            return(deadKey);
        }