xenadmin/XenAdmin/ConsoleView/ConsoleKeyHandler.cs
Gabor Apati-Nagy 7c0bc50b4a CA-176169: Changed copyright statements to include the comma in Citrix Systems,
Inc.

Signed-off-by: Gabor Apati-Nagy<gabor.apati-nagy@citrix.com>
2017-01-16 19:59:50 +00:00

446 lines
21 KiB
C#

/* 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<int> ModifierScans = new List<int>()
{
CTRL_SCAN,
CTRL2_SCAN,
L_SHIFT_SCAN,
R_SHIFT_SCAN,
ALT_SCAN,
ALT2_SCAN,
GR_SCAN
};
internal List<Keys> ModifierKeys = new List<Keys>()
{
Keys.ControlKey,
Keys.RControlKey,
Keys.LControlKey,
Keys.ShiftKey,
Keys.RShiftKey,
Keys.LShiftKey,
Keys.Menu,
Keys.RMenu,
Keys.LMenu
};
internal Dictionary<Set<int>, MethodInvoker> ExtraScans = new Dictionary<Set<int>, MethodInvoker>();
internal Dictionary<Set<Keys>, MethodInvoker> ExtraKeys = new Dictionary<Set<Keys>, MethodInvoker>();
internal void AddKeyHandler(ConsoleShortcutKey shortcutKey, MethodInvoker methodInvoker)
{
Program.AssertOnEventThread();
switch (shortcutKey)
{
case ConsoleShortcutKey.CTRL_ALT:
AddKeyHandler(new Set<Keys>(Keys.ControlKey, Keys.Menu), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.LControlKey, Keys.LMenu), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.LControlKey, Keys.RMenu), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.RControlKey, Keys.LMenu), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.RControlKey, Keys.RMenu), methodInvoker);
AddKeyHandler(new Set<int>(CTRL_SCAN, ALT_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL2_SCAN, ALT2_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL2_SCAN, ALT2_SCAN, GR_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL2_SCAN, ALT_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL_SCAN, ALT2_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL_SCAN, ALT2_SCAN, GR_SCAN), methodInvoker);
break;
case ConsoleShortcutKey.CTRL_ALT_F:
AddKeyHandler(new Set<Keys>(Keys.ControlKey, Keys.Menu, Keys.F), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.LControlKey, Keys.LMenu, Keys.F), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.LControlKey, Keys.RMenu, Keys.F), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.RControlKey, Keys.LMenu, Keys.F), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.RControlKey, Keys.RMenu, Keys.F), methodInvoker);
AddKeyHandler(new Set<int>(CTRL_SCAN, ALT_SCAN, F_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL2_SCAN, ALT2_SCAN, F_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL2_SCAN, ALT2_SCAN, GR_SCAN, F_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL2_SCAN, ALT_SCAN, F_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL_SCAN, ALT2_SCAN, F_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL_SCAN, ALT2_SCAN, GR_SCAN, F_SCAN), methodInvoker);
break;
case ConsoleShortcutKey.F12:
AddKeyHandler(new Set<Keys>(Keys.F12), methodInvoker);
AddKeyHandler(new Set<int>(F12_SCAN), methodInvoker);
break;
case ConsoleShortcutKey.CTRL_ENTER:
AddKeyHandler(new Set<Keys>(Keys.ControlKey, Keys.Enter), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.LControlKey, Keys.Enter), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.RControlKey, Keys.Enter), methodInvoker);
AddKeyHandler(new Set<int>(CTRL_SCAN, ENTER_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL2_SCAN, ENTER_SCAN), methodInvoker);
break;
case ConsoleShortcutKey.ALT_SHIFT_U:
AddKeyHandler(new Set<Keys>(Keys.Menu, Keys.ShiftKey, Keys.U), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.LMenu, Keys.LShiftKey, Keys.U), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.LMenu, Keys.RShiftKey, Keys.U), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.RMenu, Keys.LShiftKey, Keys.U), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.RMenu, Keys.RShiftKey, Keys.U), methodInvoker);
AddKeyHandler(new Set<int>(ALT_SCAN, L_SHIFT_SCAN, U_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(ALT2_SCAN, L_SHIFT_SCAN, U_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(ALT_SCAN, R_SHIFT_SCAN, U_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(ALT2_SCAN, R_SHIFT_SCAN, U_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(ALT2_SCAN, R_SHIFT_SCAN, GR_SCAN, U_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(ALT2_SCAN, L_SHIFT_SCAN, GR_SCAN, U_SCAN), methodInvoker);
break;
case ConsoleShortcutKey.F11:
AddKeyHandler(new Set<Keys>(Keys.F11), methodInvoker);
AddKeyHandler(new Set<int>(F11_SCAN), methodInvoker);
break;
case ConsoleShortcutKey.RIGHT_CTRL:
AddKeyHandler(new Set<Keys>(Keys.RControlKey), methodInvoker);
AddKeyHandler(new Set<int>(CTRL2_SCAN), methodInvoker);
break;
case ConsoleShortcutKey.LEFT_ALT:
AddKeyHandler(new Set<Keys>(Keys.LMenu), methodInvoker);
AddKeyHandler(new Set<int>(ALT_SCAN), methodInvoker);
break;
case ConsoleShortcutKey.CTRL_ALT_INS:
AddKeyHandler(new Set<Keys>(Keys.ControlKey, Keys.Menu, Keys.Insert), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.LControlKey, Keys.LMenu, Keys.Insert), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.LControlKey, Keys.RMenu, Keys.Insert), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.RControlKey, Keys.LMenu, Keys.Insert), methodInvoker);
AddKeyHandler(new Set<Keys>(Keys.RControlKey, Keys.RMenu, Keys.Insert), methodInvoker);
AddKeyHandler(new Set<int>(CTRL_SCAN, ALT_SCAN, INS_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL2_SCAN, ALT2_SCAN, INS_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL2_SCAN, ALT2_SCAN, GR_SCAN, INS_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL_SCAN, ALT2_SCAN, INS_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL2_SCAN, ALT_SCAN, INS_SCAN), methodInvoker);
AddKeyHandler(new Set<int>(CTRL_SCAN, ALT2_SCAN, GR_SCAN, INS_SCAN), methodInvoker);
break;
}
}
internal void AddKeyHandler(Set<Keys> keySet, MethodInvoker methodInvoker)
{
Program.AssertOnEventThread();
if (ExtraKeys.ContainsKey(keySet))
ExtraKeys.Remove(keySet);
ExtraKeys.Add(keySet, methodInvoker);
}
internal void AddKeyHandler(Set<int> 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>(Keys.ControlKey, Keys.Menu));
RemoveKeyHandler(new Set<Keys>(Keys.LControlKey, Keys.LMenu));
RemoveKeyHandler(new Set<Keys>(Keys.LControlKey, Keys.RMenu));
RemoveKeyHandler(new Set<Keys>(Keys.RControlKey, Keys.LMenu));
RemoveKeyHandler(new Set<Keys>(Keys.RControlKey, Keys.RMenu));
RemoveKeyHandler(new Set<int>(CTRL_SCAN, ALT_SCAN));
RemoveKeyHandler(new Set<int>(CTRL2_SCAN, ALT2_SCAN));
RemoveKeyHandler(new Set<int>(CTRL2_SCAN, ALT2_SCAN, GR_SCAN));
RemoveKeyHandler(new Set<int>(CTRL2_SCAN, ALT_SCAN));
RemoveKeyHandler(new Set<int>(CTRL_SCAN, ALT2_SCAN));
RemoveKeyHandler(new Set<int>(CTRL_SCAN, ALT2_SCAN, GR_SCAN));
break;
case ConsoleShortcutKey.CTRL_ALT_F:
RemoveKeyHandler(new Set<Keys>(Keys.ControlKey, Keys.Menu, Keys.F));
RemoveKeyHandler(new Set<Keys>(Keys.LControlKey, Keys.LMenu, Keys.F));
RemoveKeyHandler(new Set<Keys>(Keys.LControlKey, Keys.RMenu, Keys.F));
RemoveKeyHandler(new Set<Keys>(Keys.RControlKey, Keys.LMenu, Keys.F));
RemoveKeyHandler(new Set<Keys>(Keys.RControlKey, Keys.RMenu, Keys.F));
RemoveKeyHandler(new Set<int>(CTRL_SCAN, ALT_SCAN, F_SCAN));
RemoveKeyHandler(new Set<int>(CTRL2_SCAN, ALT2_SCAN, F_SCAN));
RemoveKeyHandler(new Set<int>(CTRL2_SCAN, ALT2_SCAN, GR_SCAN, F_SCAN));
RemoveKeyHandler(new Set<int>(CTRL2_SCAN, ALT_SCAN, F_SCAN));
RemoveKeyHandler(new Set<int>(CTRL_SCAN, ALT2_SCAN, F_SCAN));
RemoveKeyHandler(new Set<int>(CTRL_SCAN, ALT2_SCAN, GR_SCAN, F_SCAN));
break;
case ConsoleShortcutKey.F12:
RemoveKeyHandler(new Set<Keys>(Keys.F12));
RemoveKeyHandler(new Set<int>(F12_SCAN));
break;
case ConsoleShortcutKey.CTRL_ENTER:
RemoveKeyHandler(new Set<Keys>(Keys.ControlKey, Keys.Enter));
RemoveKeyHandler(new Set<Keys>(Keys.LControlKey, Keys.Enter));
RemoveKeyHandler(new Set<Keys>(Keys.RControlKey, Keys.Enter));
RemoveKeyHandler(new Set<int>(CTRL_SCAN, ENTER_SCAN));
RemoveKeyHandler(new Set<int>(CTRL2_SCAN, ENTER_SCAN));
break;
case ConsoleShortcutKey.ALT_SHIFT_U:
RemoveKeyHandler(new Set<Keys>(Keys.Menu, Keys.ShiftKey, Keys.U));
RemoveKeyHandler(new Set<Keys>(Keys.LMenu, Keys.LShiftKey, Keys.U));
RemoveKeyHandler(new Set<Keys>(Keys.LMenu, Keys.RShiftKey, Keys.U));
RemoveKeyHandler(new Set<Keys>(Keys.RMenu, Keys.LShiftKey, Keys.U));
RemoveKeyHandler(new Set<Keys>(Keys.RMenu, Keys.RShiftKey, Keys.U));
RemoveKeyHandler(new Set<int>(ALT_SCAN, L_SHIFT_SCAN, U_SCAN));
RemoveKeyHandler(new Set<int>(ALT2_SCAN, L_SHIFT_SCAN, U_SCAN));
RemoveKeyHandler(new Set<int>(ALT_SCAN, R_SHIFT_SCAN, U_SCAN));
RemoveKeyHandler(new Set<int>(ALT2_SCAN, R_SHIFT_SCAN, U_SCAN));
RemoveKeyHandler(new Set<int>(ALT2_SCAN, R_SHIFT_SCAN, GR_SCAN, U_SCAN));
RemoveKeyHandler(new Set<int>(ALT2_SCAN, L_SHIFT_SCAN, GR_SCAN, U_SCAN));
break;
case ConsoleShortcutKey.F11:
RemoveKeyHandler(new Set<Keys>(Keys.F11));
RemoveKeyHandler(new Set<int>(F11_SCAN));
break;
case ConsoleShortcutKey.RIGHT_CTRL:
RemoveKeyHandler(new Set<Keys>(Keys.RControlKey));
RemoveKeyHandler(new Set<int>(CTRL2_SCAN));
break;
case ConsoleShortcutKey.LEFT_ALT:
RemoveKeyHandler(new Set<Keys>(Keys.LMenu));
RemoveKeyHandler(new Set<int>(ALT_SCAN));
break;
case ConsoleShortcutKey.CTRL_ALT_INS:
RemoveKeyHandler(new Set<Keys>(Keys.ControlKey, Keys.Menu, Keys.Insert));
RemoveKeyHandler(new Set<Keys>(Keys.LControlKey, Keys.LMenu, Keys.Insert));
RemoveKeyHandler(new Set<Keys>(Keys.LControlKey, Keys.RMenu, Keys.Insert));
RemoveKeyHandler(new Set<Keys>(Keys.RControlKey, Keys.LMenu, Keys.Insert));
RemoveKeyHandler(new Set<Keys>(Keys.RControlKey, Keys.RMenu, Keys.Insert));
RemoveKeyHandler(new Set<int>(CTRL_SCAN, ALT_SCAN, INS_SCAN));
RemoveKeyHandler(new Set<int>(CTRL2_SCAN, ALT2_SCAN, INS_SCAN));
RemoveKeyHandler(new Set<int>(CTRL2_SCAN, ALT2_SCAN, GR_SCAN, INS_SCAN));
RemoveKeyHandler(new Set<int>(CTRL_SCAN, ALT2_SCAN, INS_SCAN));
RemoveKeyHandler(new Set<int>(CTRL2_SCAN, ALT_SCAN, INS_SCAN));
RemoveKeyHandler(new Set<int>(CTRL_SCAN, ALT2_SCAN, GR_SCAN, INS_SCAN));
break;
}
}
internal void RemoveKeyHandler(Set<Keys> keySet)
{
Program.AssertOnEventThread();
if (ExtraKeys.ContainsKey(keySet))
ExtraKeys.Remove(keySet);
}
internal void RemoveKeyHandler(Set<int> keySet)
{
Program.AssertOnEventThread();
if (ExtraScans.ContainsKey(keySet))
ExtraScans.Remove(keySet);
}
/// <summary>
/// Generic function to handle key tracking and event firing
/// </summary>
/// <typeparam name="T">either int or Keys</typeparam>
/// <param name="pressed"></param>
/// <param name="depressed"></param>
/// <param name="methods"></param>
/// <param name="key"></param>
/// <param name="modifierKeyPressedAlone"></param>
/// <param name="modifierKeys"></param>
/// <returns>Handled or not</returns>
public bool handleExtras<T>(bool pressed, Set<T> depressed, Dictionary<Set<T>, MethodInvoker> methods, T key, List<T> 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;
}
/// <summary>
/// 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].
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
internal static List<Keys> GetExtendedKeys(Keys key)
{
List<Keys> list = new List<Keys>();
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;
}
/// <summary>
/// Translates Left and Right modifier keys into simple keys, like ControlKey, ShiftKey and Menu.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
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;
}
}
}
}