MMaurice FlanaganInitial
59b956f7创建于 2018年7月20日历史提交
using System;

using System.Collections;

using System.Windows.Forms;



//

// Hotkey selection control, written by serenity@exscape.org, 2006-08-03

// Please mail me if you find a bug.

//



namespace Bemo.Win32

{

    /// <summary>

    /// A simple control that allows the user to select pretty much any valid hotkey combination

    /// </summary>

    [System.ComponentModel.DesignerCategory("CODE")]

    public class HotKeyControl2 : TextBox

    {

        // These variables store the current hotkey and modifier(s)

        private Keys _hotkey = Keys.None;

        private Keys _modifiers = Keys.None;



        // ArrayLists used to enforce the use of proper modifiers.

        // Shift+A isn't a valid hotkey, for instance, as it would screw up when the user is typing.

        private ArrayList needNonShiftModifier = null;

        private ArrayList needNonAltGrModifier = null;



        private ContextMenu dummy = new ContextMenu();



        /// <summary>

        /// Used to make sure that there is no right-click menu available

        /// </summary>

        public override ContextMenu ContextMenu

        {

            get

            {

                return dummy;

            }

            set

            {

                base.ContextMenu = dummy;

            }

        }



        /// <summary>

        /// Forces the control to be non-multiline

        /// </summary>

        public override bool Multiline

        {

            get

            {

                return base.Multiline;

            }

            set

            {

                // Ignore what the user wants; force Multiline to false

                base.Multiline = false;

            }

        }



        /// <summary>

        /// Creates a new HotkeyControl

        /// </summary>

        public HotKeyControl2()

        {

            this.ContextMenu = dummy; // Disable right-clicking

            this.Text = "None";



            // Handle events that occurs when keys are pressed

            this.KeyPress += new KeyPressEventHandler(HotkeyControl_KeyPress);

            this.KeyUp += new KeyEventHandler(HotkeyControl_KeyUp);

            this.KeyDown += new KeyEventHandler(HotkeyControl_KeyDown);



            // Fill the ArrayLists that contain all invalid hotkey combinations

            needNonShiftModifier = new ArrayList();

            needNonAltGrModifier = new ArrayList();

            PopulateModifierLists();

        }



        /// <summary>

        /// Populates the ArrayLists specifying disallowed hotkeys

        /// such as Shift+A, Ctrl+Alt+4 (would produce a dollar sign) etc

        /// </summary>

        private void PopulateModifierLists()

        {

            //// Shift + 0 - 9, A - Z

            //for (Keys k = Keys.D0; k <= Keys.Z; k++)

            //    needNonShiftModifier.Add((int)k);



            //// Shift + Numpad keys

            //for (Keys k = Keys.NumPad0; k <= Keys.NumPad9; k++)

            //    needNonShiftModifier.Add((int)k);



            //// Shift + Misc (,;<./ etc)

            //for (Keys k = Keys.Oem1; k <= Keys.OemBackslash; k++)

            //    needNonShiftModifier.Add((int)k);



            //// Shift + Space, PgUp, PgDn, End, Home

            //for (Keys k = Keys.Space; k <= Keys.Home; k++)

            //    needNonShiftModifier.Add((int)k);



            //// Misc keys that we can't loop through

            //needNonShiftModifier.Add((int)Keys.Insert);

            //needNonShiftModifier.Add((int)Keys.Help);

            //needNonShiftModifier.Add((int)Keys.Multiply);

            //needNonShiftModifier.Add((int)Keys.Add);

            //needNonShiftModifier.Add((int)Keys.Subtract);

            //needNonShiftModifier.Add((int)Keys.Divide);

            //needNonShiftModifier.Add((int)Keys.Decimal);

            //needNonShiftModifier.Add((int)Keys.Return);

            //needNonShiftModifier.Add((int)Keys.Escape);

            //needNonShiftModifier.Add((int)Keys.NumLock);

            //needNonShiftModifier.Add((int)Keys.Scroll);

            //needNonShiftModifier.Add((int)Keys.Pause);



            //// Ctrl+Alt + 0 - 9

            //for (Keys k = Keys.D0; k <= Keys.D9; k++)

            //    needNonAltGrModifier.Add((int)k);

        }



        /// <summary>

        /// Resets this hotkey control to None

        /// </summary>

        public new void Clear()

        {

            this.Hotkey = Keys.None;

            this.HotkeyModifiers = Keys.None;

        }



        /// <summary>

        /// Fires when a key is pushed down. Here, we'll want to update the text in the box

        /// to notify the user what combination is currently pressed.

        /// </summary>

        void HotkeyControl_KeyDown(object sender, KeyEventArgs e)

        {

            // Clear the current hotkey

            if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete)

            {

                ResetHotkey();

                return;

            }

            else

            {

                this._modifiers = e.Modifiers;

                this._hotkey = e.KeyCode;

                Redraw();

            }

        }



        /// <summary>

        /// Fires when all keys are released. If the current hotkey isn't valid, reset it.

        /// Otherwise, do nothing and keep the text and hotkey as it was.

        /// </summary>

        void HotkeyControl_KeyUp(object sender, KeyEventArgs e)

        {

            if (this._hotkey == Keys.None && Control.ModifierKeys == Keys.None)

            {

                ResetHotkey();

                return;

            }

        }



        /// <summary>

        /// Prevents the letter/whatever entered to show up in the TextBox

        /// Without this, a "A" key press would appear as "aControl, Alt + A"

        /// </summary>

        void HotkeyControl_KeyPress(object sender, KeyPressEventArgs e)

        {

            e.Handled = true;

        }



        /// <summary>

        /// Handles some misc keys, such as Ctrl+Delete and Shift+Insert

        /// </summary>

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)

        {

            if (keyData == Keys.Delete || keyData == (Keys.Control | Keys.Delete))

            {

                ResetHotkey();

                return true;

            }



            if (keyData == (Keys.Shift | Keys.Insert)) // Paste

                return true; // Don't allow



            // Allow the rest

            return base.ProcessCmdKey(ref msg, keyData);

        }



        /// <summary>

        /// Clears the current hotkey and resets the TextBox

        /// </summary>

        public void ResetHotkey()

        {

            this._hotkey = Keys.None;

            this._modifiers = Keys.None;

            Redraw();

        }



        /// <summary>

        /// Used to get/set the hotkey (e.g. Keys.A)

        /// </summary>

        public Keys Hotkey

        {

            get

            {

                return this._hotkey;

            }

            set

            {

                this._hotkey = value;

                Redraw(true);

            }

        }



        /// <summary>

        /// Used to get/set the modifier keys (e.g. Keys.Alt | Keys.Control)

        /// </summary>

        public Keys HotkeyModifiers

        {

            get

            {

                return this._modifiers;

            }

            set

            {

                this._modifiers = value;

                Redraw(true);

            }

        }



        /// <summary>

        /// Helper function

        /// </summary>

        private void Redraw()

        {

            Redraw(false);

        }



        /// <summary>

        /// Redraws the TextBox when necessary.

        /// </summary>

        /// <param name="bCalledProgramatically">Specifies whether this function was called by the Hotkey/HotkeyModifiers properties or by the user.</param>

        private void Redraw(bool bCalledProgramatically)

        {

            // No hotkey set

            if (this._hotkey == Keys.None)

            {

                this.Text = "None";

                return;

            }



            // LWin/RWin doesn't work as hotkeys (neither do they work as modifier keys in .NET 2.0)

            if (this._hotkey == Keys.LWin || this._hotkey == Keys.RWin)

            {

                this.Text = "None";

                return;

            }



            // Only validate input if it comes from the user

            if (bCalledProgramatically == false)

            {

                // No modifier or shift only, AND a hotkey that needs another modifier

                if ((this._modifiers == Keys.Shift || this._modifiers == Keys.None) &&

                this.needNonShiftModifier.Contains((int)this._hotkey))

                {

                    if (this._modifiers == Keys.None)

                    {

                        // Set Ctrl+Alt as the modifier unless Ctrl+Alt+<key> won't work...

                        if (needNonAltGrModifier.Contains((int)this._hotkey) == false)

                            this._modifiers = Keys.Alt | Keys.Control;

                        else // ... in that case, use Shift+Alt instead.

                            this._modifiers = Keys.Alt | Keys.Shift;

                    }

                    else

                    {

                        // User pressed Shift and an invalid key (e.g. a letter or a number),

                        // that needs another set of modifier keys

                        this._hotkey = Keys.None;

                        this.Text = this._modifiers.ToString() + " + Invalid key";

                        return;

                    }

                }

                // Check all Ctrl+Alt keys

                if ((this._modifiers == (Keys.Alt | Keys.Control)) &&

                    this.needNonAltGrModifier.Contains((int)this._hotkey))

                {

                    // Ctrl+Alt+4 etc won't work; reset hotkey and tell the user

                    this._hotkey = Keys.None;

                    this.Text = this._modifiers.ToString() + " + Invalid key";

                    return;

                }

            }



            if (this._modifiers == Keys.None)

            {

                if (this._hotkey == Keys.None)

                {

                    this.Text = "None";

                    return;

                }

                else

                {

                    // We get here if we've got a hotkey that is valid without a modifier,

                    // like F1-F12, Media-keys etc.

                    this.Text = this._hotkey.ToString();

                    return;

                }

            }



            // I have no idea why this is needed, but it is. Without this code, pressing only Ctrl

            // will show up as "Control + ControlKey", etc.

            if (this._hotkey == Keys.Menu /* Alt */ ||

                this._hotkey == Keys.ShiftKey || 

                this._hotkey == Keys.ControlKey)

                this._hotkey = Keys.None;



            this.Text = this._modifiers.ToString() + " + " + this._hotkey.ToString();

        }

    }

}