/* Copyright (c) Citrix Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System; using System.Collections.Generic; using System.Windows.Forms; using XenAdmin.Core; namespace XenAdmin.ConsoleView { public enum ConsoleShortcutKey { CTRL_ALT, CTRL_ALT_F, F12, CTRL_ENTER, ALT_SHIFT_U, F11, RIGHT_CTRL, LEFT_ALT, CTRL_ALT_INS } public class ConsoleKeyHandler { public const int CTRL_SCAN = 29; public const int ALT_SCAN = 56; public const int CTRL2_SCAN = 157; public const int ALT2_SCAN = 184; public const int GR_SCAN = 541; public const int DEL_SCAN = 211; public const int INS_SCAN = 210; public const int L_SHIFT_SCAN = 0x2A; public const int R_SHIFT_SCAN = 0x36; public const int F11_SCAN = 87; public const int F12_SCAN = 88; public const int F_SCAN = 33; public const int U_SCAN = 22; public const int ENTER_SCAN = 28; internal List ModifierScans = new List() { CTRL_SCAN, CTRL2_SCAN, L_SHIFT_SCAN, R_SHIFT_SCAN, ALT_SCAN, ALT2_SCAN, GR_SCAN }; internal List ModifierKeys = new List() { Keys.ControlKey, Keys.RControlKey, Keys.LControlKey, Keys.ShiftKey, Keys.RShiftKey, Keys.LShiftKey, Keys.Menu, Keys.RMenu, Keys.LMenu }; internal Dictionary, MethodInvoker> ExtraScans = new Dictionary, MethodInvoker>(); internal Dictionary, MethodInvoker> ExtraKeys = new Dictionary, MethodInvoker>(); internal void AddKeyHandler(ConsoleShortcutKey shortcutKey, MethodInvoker methodInvoker) { Program.AssertOnEventThread(); switch (shortcutKey) { case ConsoleShortcutKey.CTRL_ALT: AddKeyHandler(new Set(Keys.ControlKey, Keys.Menu), methodInvoker); AddKeyHandler(new Set(Keys.LControlKey, Keys.LMenu), methodInvoker); AddKeyHandler(new Set(Keys.LControlKey, Keys.RMenu), methodInvoker); AddKeyHandler(new Set(Keys.RControlKey, Keys.LMenu), methodInvoker); AddKeyHandler(new Set(Keys.RControlKey, Keys.RMenu), methodInvoker); AddKeyHandler(new Set(CTRL_SCAN, ALT_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL2_SCAN, ALT2_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL2_SCAN, ALT2_SCAN, GR_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL2_SCAN, ALT_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL_SCAN, ALT2_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL_SCAN, ALT2_SCAN, GR_SCAN), methodInvoker); break; case ConsoleShortcutKey.CTRL_ALT_F: AddKeyHandler(new Set(Keys.ControlKey, Keys.Menu, Keys.F), methodInvoker); AddKeyHandler(new Set(Keys.LControlKey, Keys.LMenu, Keys.F), methodInvoker); AddKeyHandler(new Set(Keys.LControlKey, Keys.RMenu, Keys.F), methodInvoker); AddKeyHandler(new Set(Keys.RControlKey, Keys.LMenu, Keys.F), methodInvoker); AddKeyHandler(new Set(Keys.RControlKey, Keys.RMenu, Keys.F), methodInvoker); AddKeyHandler(new Set(CTRL_SCAN, ALT_SCAN, F_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL2_SCAN, ALT2_SCAN, F_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL2_SCAN, ALT2_SCAN, GR_SCAN, F_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL2_SCAN, ALT_SCAN, F_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL_SCAN, ALT2_SCAN, F_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL_SCAN, ALT2_SCAN, GR_SCAN, F_SCAN), methodInvoker); break; case ConsoleShortcutKey.F12: AddKeyHandler(new Set(Keys.F12), methodInvoker); AddKeyHandler(new Set(F12_SCAN), methodInvoker); break; case ConsoleShortcutKey.CTRL_ENTER: AddKeyHandler(new Set(Keys.ControlKey, Keys.Enter), methodInvoker); AddKeyHandler(new Set(Keys.LControlKey, Keys.Enter), methodInvoker); AddKeyHandler(new Set(Keys.RControlKey, Keys.Enter), methodInvoker); AddKeyHandler(new Set(CTRL_SCAN, ENTER_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL2_SCAN, ENTER_SCAN), methodInvoker); break; case ConsoleShortcutKey.ALT_SHIFT_U: AddKeyHandler(new Set(Keys.Menu, Keys.ShiftKey, Keys.U), methodInvoker); AddKeyHandler(new Set(Keys.LMenu, Keys.LShiftKey, Keys.U), methodInvoker); AddKeyHandler(new Set(Keys.LMenu, Keys.RShiftKey, Keys.U), methodInvoker); AddKeyHandler(new Set(Keys.RMenu, Keys.LShiftKey, Keys.U), methodInvoker); AddKeyHandler(new Set(Keys.RMenu, Keys.RShiftKey, Keys.U), methodInvoker); AddKeyHandler(new Set(ALT_SCAN, L_SHIFT_SCAN, U_SCAN), methodInvoker); AddKeyHandler(new Set(ALT2_SCAN, L_SHIFT_SCAN, U_SCAN), methodInvoker); AddKeyHandler(new Set(ALT_SCAN, R_SHIFT_SCAN, U_SCAN), methodInvoker); AddKeyHandler(new Set(ALT2_SCAN, R_SHIFT_SCAN, U_SCAN), methodInvoker); AddKeyHandler(new Set(ALT2_SCAN, R_SHIFT_SCAN, GR_SCAN, U_SCAN), methodInvoker); AddKeyHandler(new Set(ALT2_SCAN, L_SHIFT_SCAN, GR_SCAN, U_SCAN), methodInvoker); break; case ConsoleShortcutKey.F11: AddKeyHandler(new Set(Keys.F11), methodInvoker); AddKeyHandler(new Set(F11_SCAN), methodInvoker); break; case ConsoleShortcutKey.RIGHT_CTRL: AddKeyHandler(new Set(Keys.RControlKey), methodInvoker); AddKeyHandler(new Set(CTRL2_SCAN), methodInvoker); break; case ConsoleShortcutKey.LEFT_ALT: AddKeyHandler(new Set(Keys.LMenu), methodInvoker); AddKeyHandler(new Set(ALT_SCAN), methodInvoker); break; case ConsoleShortcutKey.CTRL_ALT_INS: AddKeyHandler(new Set(Keys.ControlKey, Keys.Menu, Keys.Insert), methodInvoker); AddKeyHandler(new Set(Keys.LControlKey, Keys.LMenu, Keys.Insert), methodInvoker); AddKeyHandler(new Set(Keys.LControlKey, Keys.RMenu, Keys.Insert), methodInvoker); AddKeyHandler(new Set(Keys.RControlKey, Keys.LMenu, Keys.Insert), methodInvoker); AddKeyHandler(new Set(Keys.RControlKey, Keys.RMenu, Keys.Insert), methodInvoker); AddKeyHandler(new Set(CTRL_SCAN, ALT_SCAN, INS_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL2_SCAN, ALT2_SCAN, INS_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL2_SCAN, ALT2_SCAN, GR_SCAN, INS_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL_SCAN, ALT2_SCAN, INS_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL2_SCAN, ALT_SCAN, INS_SCAN), methodInvoker); AddKeyHandler(new Set(CTRL_SCAN, ALT2_SCAN, GR_SCAN, INS_SCAN), methodInvoker); break; } } internal void AddKeyHandler(Set keySet, MethodInvoker methodInvoker) { Program.AssertOnEventThread(); if (ExtraKeys.ContainsKey(keySet)) ExtraKeys.Remove(keySet); ExtraKeys.Add(keySet, methodInvoker); } internal void AddKeyHandler(Set keySet, MethodInvoker methodInvoker) { Program.AssertOnEventThread(); if (ExtraScans.ContainsKey(keySet)) ExtraScans.Remove(keySet); ExtraScans.Add(keySet, methodInvoker); } internal void RemoveKeyHandler(ConsoleShortcutKey shortcutKey) { Program.AssertOnEventThread(); switch (shortcutKey) { case ConsoleShortcutKey.CTRL_ALT: RemoveKeyHandler(new Set(Keys.ControlKey, Keys.Menu)); RemoveKeyHandler(new Set(Keys.LControlKey, Keys.LMenu)); RemoveKeyHandler(new Set(Keys.LControlKey, Keys.RMenu)); RemoveKeyHandler(new Set(Keys.RControlKey, Keys.LMenu)); RemoveKeyHandler(new Set(Keys.RControlKey, Keys.RMenu)); RemoveKeyHandler(new Set(CTRL_SCAN, ALT_SCAN)); RemoveKeyHandler(new Set(CTRL2_SCAN, ALT2_SCAN)); RemoveKeyHandler(new Set(CTRL2_SCAN, ALT2_SCAN, GR_SCAN)); RemoveKeyHandler(new Set(CTRL2_SCAN, ALT_SCAN)); RemoveKeyHandler(new Set(CTRL_SCAN, ALT2_SCAN)); RemoveKeyHandler(new Set(CTRL_SCAN, ALT2_SCAN, GR_SCAN)); break; case ConsoleShortcutKey.CTRL_ALT_F: RemoveKeyHandler(new Set(Keys.ControlKey, Keys.Menu, Keys.F)); RemoveKeyHandler(new Set(Keys.LControlKey, Keys.LMenu, Keys.F)); RemoveKeyHandler(new Set(Keys.LControlKey, Keys.RMenu, Keys.F)); RemoveKeyHandler(new Set(Keys.RControlKey, Keys.LMenu, Keys.F)); RemoveKeyHandler(new Set(Keys.RControlKey, Keys.RMenu, Keys.F)); RemoveKeyHandler(new Set(CTRL_SCAN, ALT_SCAN, F_SCAN)); RemoveKeyHandler(new Set(CTRL2_SCAN, ALT2_SCAN, F_SCAN)); RemoveKeyHandler(new Set(CTRL2_SCAN, ALT2_SCAN, GR_SCAN, F_SCAN)); RemoveKeyHandler(new Set(CTRL2_SCAN, ALT_SCAN, F_SCAN)); RemoveKeyHandler(new Set(CTRL_SCAN, ALT2_SCAN, F_SCAN)); RemoveKeyHandler(new Set(CTRL_SCAN, ALT2_SCAN, GR_SCAN, F_SCAN)); break; case ConsoleShortcutKey.F12: RemoveKeyHandler(new Set(Keys.F12)); RemoveKeyHandler(new Set(F12_SCAN)); break; case ConsoleShortcutKey.CTRL_ENTER: RemoveKeyHandler(new Set(Keys.ControlKey, Keys.Enter)); RemoveKeyHandler(new Set(Keys.LControlKey, Keys.Enter)); RemoveKeyHandler(new Set(Keys.RControlKey, Keys.Enter)); RemoveKeyHandler(new Set(CTRL_SCAN, ENTER_SCAN)); RemoveKeyHandler(new Set(CTRL2_SCAN, ENTER_SCAN)); break; case ConsoleShortcutKey.ALT_SHIFT_U: RemoveKeyHandler(new Set(Keys.Menu, Keys.ShiftKey, Keys.U)); RemoveKeyHandler(new Set(Keys.LMenu, Keys.LShiftKey, Keys.U)); RemoveKeyHandler(new Set(Keys.LMenu, Keys.RShiftKey, Keys.U)); RemoveKeyHandler(new Set(Keys.RMenu, Keys.LShiftKey, Keys.U)); RemoveKeyHandler(new Set(Keys.RMenu, Keys.RShiftKey, Keys.U)); RemoveKeyHandler(new Set(ALT_SCAN, L_SHIFT_SCAN, U_SCAN)); RemoveKeyHandler(new Set(ALT2_SCAN, L_SHIFT_SCAN, U_SCAN)); RemoveKeyHandler(new Set(ALT_SCAN, R_SHIFT_SCAN, U_SCAN)); RemoveKeyHandler(new Set(ALT2_SCAN, R_SHIFT_SCAN, U_SCAN)); RemoveKeyHandler(new Set(ALT2_SCAN, R_SHIFT_SCAN, GR_SCAN, U_SCAN)); RemoveKeyHandler(new Set(ALT2_SCAN, L_SHIFT_SCAN, GR_SCAN, U_SCAN)); break; case ConsoleShortcutKey.F11: RemoveKeyHandler(new Set(Keys.F11)); RemoveKeyHandler(new Set(F11_SCAN)); break; case ConsoleShortcutKey.RIGHT_CTRL: RemoveKeyHandler(new Set(Keys.RControlKey)); RemoveKeyHandler(new Set(CTRL2_SCAN)); break; case ConsoleShortcutKey.LEFT_ALT: RemoveKeyHandler(new Set(Keys.LMenu)); RemoveKeyHandler(new Set(ALT_SCAN)); break; case ConsoleShortcutKey.CTRL_ALT_INS: RemoveKeyHandler(new Set(Keys.ControlKey, Keys.Menu, Keys.Insert)); RemoveKeyHandler(new Set(Keys.LControlKey, Keys.LMenu, Keys.Insert)); RemoveKeyHandler(new Set(Keys.LControlKey, Keys.RMenu, Keys.Insert)); RemoveKeyHandler(new Set(Keys.RControlKey, Keys.LMenu, Keys.Insert)); RemoveKeyHandler(new Set(Keys.RControlKey, Keys.RMenu, Keys.Insert)); RemoveKeyHandler(new Set(CTRL_SCAN, ALT_SCAN, INS_SCAN)); RemoveKeyHandler(new Set(CTRL2_SCAN, ALT2_SCAN, INS_SCAN)); RemoveKeyHandler(new Set(CTRL2_SCAN, ALT2_SCAN, GR_SCAN, INS_SCAN)); RemoveKeyHandler(new Set(CTRL_SCAN, ALT2_SCAN, INS_SCAN)); RemoveKeyHandler(new Set(CTRL2_SCAN, ALT_SCAN, INS_SCAN)); RemoveKeyHandler(new Set(CTRL_SCAN, ALT2_SCAN, GR_SCAN, INS_SCAN)); break; } } internal void RemoveKeyHandler(Set keySet) { Program.AssertOnEventThread(); if (ExtraKeys.ContainsKey(keySet)) ExtraKeys.Remove(keySet); } internal void RemoveKeyHandler(Set keySet) { Program.AssertOnEventThread(); if (ExtraScans.ContainsKey(keySet)) ExtraScans.Remove(keySet); } /// /// Generic function to handle key tracking and event firing /// /// either int or Keys /// /// /// /// /// /// /// Handled or not public bool handleExtras(bool pressed, Set depressed, Dictionary, MethodInvoker> methods, T key, List modifierKeys, ref bool modifierKeyPressedAlone) where T : IComparable { if (pressed) { depressed.Add(key); if (modifierKeyPressedAlone) modifierKeyPressedAlone = false; } else { if (modifierKeyPressedAlone && methods.ContainsKey(depressed) && depressed.Count == 1) { methods[depressed](); depressed.Clear(); return true; } depressed.Remove(key); } if (pressed && methods.ContainsKey(depressed)) { if (depressed.Count == 1 && modifierKeys.Contains(key)) //single modifier keys are processed when the key is released { modifierKeyPressedAlone = true; } else { methods[depressed](); return true; } } return false; } internal static Keys TranslateKeyMessage(Message msg) { // Determine the virtual key code. int virtualKeyCode = (int)msg.WParam; // Determine whether the key is an extended key, e.g. a right hand Alt, Ctrl or Shift. int lParam = (int)msg.LParam; bool extended = (lParam & (1 << 24)) != 0; // Left Alt or Right Alt if (virtualKeyCode == 18) return extended ? Keys.RMenu : Keys.LMenu; // Left Ctrl or Right Ctrl if (virtualKeyCode == 17) return extended ? Keys.RControlKey : Keys.LControlKey; // Left Shift or Right Shift if (virtualKeyCode == 16) return extended ? Keys.RShiftKey : Keys.LShiftKey; // Default return (Keys)msg.WParam; } /// /// Given a modifier key (Ctrl, Shift or Alt), it builds a list of extended (Left and Right) keys. /// For example, if ControlKey is passed in, the result will be [RControlKey, LControlKey]. /// /// /// internal static List GetExtendedKeys(Keys key) { List list = new List(); if (key == Keys.ControlKey) { list.Add(Keys.RControlKey); list.Add(Keys.LControlKey); } if (key == Keys.ShiftKey) { list.Add(Keys.RShiftKey); list.Add(Keys.LShiftKey); } if (key == Keys.Menu) { list.Add(Keys.RMenu); list.Add(Keys.LMenu); } return list; } /// /// Translates Left and Right modifier keys into simple keys, like ControlKey, ShiftKey and Menu. /// /// /// internal static Keys GetSimpleKey(Keys key) { switch (key) { case Keys.LControlKey: case Keys.RControlKey: return Keys.ControlKey; case Keys.LShiftKey: case Keys.RShiftKey: return Keys.ShiftKey; case Keys.LMenu: case Keys.RMenu: return Keys.Menu; default: return key; } } } }