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. // // '' // '' A simple control that allows the user to select pretty much any valid hotkey combination // '' namespace NvCplAdjust { public partial class ctrlHotkey : 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(); // '' // '' Used to make sure that there is no right-click menu available // '' public override ContextMenu ContextMenu { get { return dummy; } set { base.ContextMenu = dummy; } } public override bool Multiline { get { return base.Multiline; } set { // Ignore what the user wants; force Multiline to false base.Multiline = false; } } public ctrlHotkey() { this.ContextMenu = dummy; // Disable right-clicking this.Text = "None"; this.KeyPress += new KeyPressEventHandler(this.HotkeyControl_KeyPress); this.KeyUp += new KeyEventHandler(this.HotkeyControl_KeyUp); this.KeyDown += new KeyEventHandler(this.HotkeyControl_KeyDown); // Fill the ArrayLists that contain all invalid hotkey combinations needNonShiftModifier = new ArrayList(); needNonAltGrModifier = new ArrayList(); // PopulateModifierLists() } // '' // '' Populates the ArrayLists specifying disallowed hotkeys // '' such as Shift+A, Ctrl+Alt+4 (would produce a dollar sign) etc // '' 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))); } } // '' // '' Resets this hotkey control to None // '' public new void Clear() { this.Hotkey = Keys.None; this.HotkeyModifiers = Keys.None; } // '' // '' 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. // '' private void HotkeyControl_KeyDown(object sender, KeyEventArgs e) { // Clear the current hotkey if (((e.KeyCode == Keys.Back) || (e.KeyCode == Keys.Delete))) { this.ResetHotkey(); } else { this._modifiers = e.Modifiers; this._hotkey = e.KeyCode; this.Redraw(); } } // '' // '' 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. // '' private void HotkeyControl_KeyUp(object sender, KeyEventArgs e) { if ((((this._hotkey == Keys.None) && (Control.ModifierKeys == Keys.None)) || ((this._hotkey == Keys.None) && (Control.ModifierKeys != Keys.None)))) { this.ResetHotkey(); } } // '' // '' Prevents the letter/whatever entered to show up in the TextBox // '' Without this, a "A" key press would appear as "aControl, Alt + A" // '' private void HotkeyControl_KeyPress(object sender, KeyPressEventArgs e) { e.Handled = true; } // '' // '' Handles some misc keys, such as Ctrl+Delete and Shift+Insert // '' protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { if (((keyData == Keys.Delete) || (keyData == (Keys.Control | Keys.Delete)))) { this.ResetHotkey(); return true; } if ((keyData == (Keys.Shift | Keys.Insert))) { return true; } // Don't allow // Allow the rest return base.ProcessCmdKey(ref msg, keyData); } // '' // '' Clears the current hotkey and resets the TextBox // '' public void ResetHotkey() { this._hotkey = Keys.None; this._modifiers = Keys.None; this.Redraw(); } // '' // '' Used to get/set the hotkey (e.g. Keys.A) // '' public Keys Hotkey { get { return this._hotkey; } set { this._hotkey = value; this.Redraw(true); } } public Keys HotkeyModifiers { get { return this._modifiers; } set { this._modifiers = value; this.Redraw(true); } } private void Redraw() { this.Redraw(false); } // '' // '' Redraws the TextBox when necessary. // '' // '' Specifies whether this function was called by the Hotkey/HotkeyModifiers properties or by the user. 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+ won't work... if ((needNonAltGrModifier.Contains(((int)(this._hotkey))) == false)) { this._modifiers = (Keys.Alt | Keys.Control); } else { 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) || ((this._hotkey == Keys.ShiftKey) || (this._hotkey == Keys.ControlKey)))) { this._hotkey = Keys.None; } this.Text = this._modifiers.ToString() + " + " + this._hotkey.ToString(); } } }