mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-25 04:13:24 +08:00
Compare commits
1 Commits
mRemoteNGP
...
sharedlibr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
141b326a20 |
331
SharedLibraryNG/HotkeyControl.cs
Normal file
331
SharedLibraryNG/HotkeyControl.cs
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Hotkey selection control, written by serenity@exscape.org, 2006-08-03
|
||||||
|
// Please mail me if you find a bug.
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace SharedLibraryNG
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A simple control that allows the user to select pretty much any valid hotkey combination
|
||||||
|
/// </summary>
|
||||||
|
public class HotkeyControl : TextBox
|
||||||
|
{
|
||||||
|
private const string KeySeparator = " + ";
|
||||||
|
|
||||||
|
// These variables store the current hotkey and modifier(s)
|
||||||
|
private Keys _keyCode = 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 readonly ArrayList _needNonShiftModifier;
|
||||||
|
private readonly ArrayList _needNonAltGrModifier;
|
||||||
|
|
||||||
|
private readonly ContextMenu _emptyContextMenu = new ContextMenu();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to make sure that there is no right-click menu available
|
||||||
|
/// </summary>
|
||||||
|
public override ContextMenu ContextMenu
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _emptyContextMenu;
|
||||||
|
}
|
||||||
|
// ReSharper disable once ValueParameterNotUsed
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.ContextMenu = _emptyContextMenu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Forces the control to be non-multiline
|
||||||
|
/// </summary>
|
||||||
|
public override bool Multiline
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return base.Multiline;
|
||||||
|
}
|
||||||
|
// ReSharper disable once ValueParameterNotUsed
|
||||||
|
set
|
||||||
|
{
|
||||||
|
// Ignore what the user wants; force Multiline to false
|
||||||
|
base.Multiline = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new HotkeyControl
|
||||||
|
/// </summary>
|
||||||
|
public HotkeyControl()
|
||||||
|
{
|
||||||
|
// Handle events that occurs when keys are pressed
|
||||||
|
KeyUp += HotkeyControl_KeyUp;
|
||||||
|
|
||||||
|
// Fill the ArrayLists that contain all invalid hotkey combinations
|
||||||
|
_needNonShiftModifier = new ArrayList();
|
||||||
|
_needNonAltGrModifier = new ArrayList();
|
||||||
|
PopulateModifierLists();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnCreateControl()
|
||||||
|
{
|
||||||
|
base.OnCreateControl();
|
||||||
|
|
||||||
|
ContextMenu = _emptyContextMenu; // Disable right-clicking
|
||||||
|
Multiline = false;
|
||||||
|
Text = "None";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 (var k = Keys.D0; k <= Keys.Z; k++)
|
||||||
|
_needNonShiftModifier.Add((int)k);
|
||||||
|
|
||||||
|
// Shift + Numpad keys
|
||||||
|
for (var k = Keys.NumPad0; k <= Keys.NumPad9; k++)
|
||||||
|
_needNonShiftModifier.Add((int)k);
|
||||||
|
|
||||||
|
// Shift + Misc (,;<./ etc)
|
||||||
|
for (var k = Keys.Oem1; k <= Keys.OemBackslash; 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 (var k = Keys.D0; k <= Keys.D9; k++)
|
||||||
|
_needNonAltGrModifier.Add((int)k);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 (_keyCode == Keys.None && ModifierKeys == Keys.None) ResetHotkey();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles some misc keys, such as Ctrl+Delete and Shift+Insert
|
||||||
|
/// </summary>
|
||||||
|
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
||||||
|
{
|
||||||
|
var keyCode = keyData & Keys.KeyCode;
|
||||||
|
var modifiers = keyData & Keys.Modifiers;
|
||||||
|
|
||||||
|
if (keyData == Keys.Back || keyData == Keys.Delete)
|
||||||
|
{
|
||||||
|
ResetHotkey();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_keyCode = keyCode;
|
||||||
|
_modifiers = modifiers;
|
||||||
|
Redraw();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the current hotkey and resets the TextBox
|
||||||
|
/// </summary>
|
||||||
|
public void ResetHotkey()
|
||||||
|
{
|
||||||
|
_keyCode = Keys.None;
|
||||||
|
_modifiers = Keys.None;
|
||||||
|
Text = "None";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to get/set the hotkey (e.g. Keys.A)
|
||||||
|
/// </summary>
|
||||||
|
public Keys KeyCode
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _keyCode;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_keyCode = value;
|
||||||
|
Redraw(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to get/set the modifier keys (e.g. Keys.Alt | Keys.Control)
|
||||||
|
/// </summary>
|
||||||
|
public Keys HotkeyModifiers
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _modifiers;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_modifiers = value;
|
||||||
|
Redraw(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Redraws the TextBox when necessary.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="validate">Specifies whether this function was called by the Hotkey/HotkeyModifiers properties or by the user.</param>
|
||||||
|
private void Redraw(bool validate = true)
|
||||||
|
{
|
||||||
|
// Only validate input if it comes from the user
|
||||||
|
if (validate)
|
||||||
|
{
|
||||||
|
// No modifier or shift only, AND a hotkey that needs another modifier
|
||||||
|
if ((_modifiers == Keys.Shift || _modifiers == Keys.None) &&
|
||||||
|
_needNonShiftModifier.Contains((int) _keyCode))
|
||||||
|
{
|
||||||
|
if (_modifiers == Keys.None)
|
||||||
|
{
|
||||||
|
// Set Ctrl+Alt as the modifier unless Ctrl+Alt+<key> won't work...
|
||||||
|
if (_needNonAltGrModifier.Contains((int) _keyCode) == false)
|
||||||
|
_modifiers = Keys.Alt | Keys.Control;
|
||||||
|
else // ... in that case, use Shift+Alt instead.
|
||||||
|
_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
|
||||||
|
_keyCode = Keys.None;
|
||||||
|
Text = _modifiers + " + Invalid Key";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check all Ctrl+Alt keys
|
||||||
|
if ((_modifiers == (Keys.Alt | Keys.Control)) &&
|
||||||
|
_needNonAltGrModifier.Contains((int) _keyCode))
|
||||||
|
{
|
||||||
|
// Ctrl+Alt+4 etc won't work; reset hotkey and tell the user
|
||||||
|
_keyCode = Keys.None;
|
||||||
|
Text = _modifiers + " + Invalid Key";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't allow modifiers keys for _keyCode
|
||||||
|
if (_keyCode == Keys.ShiftKey ||
|
||||||
|
_keyCode == Keys.LShiftKey ||
|
||||||
|
_keyCode == Keys.RShiftKey ||
|
||||||
|
_keyCode == Keys.ControlKey ||
|
||||||
|
_keyCode == Keys.LControlKey ||
|
||||||
|
_keyCode == Keys.RControlKey ||
|
||||||
|
_keyCode == Keys.Menu ||
|
||||||
|
_keyCode == Keys.LMenu ||
|
||||||
|
_keyCode == Keys.RMenu ||
|
||||||
|
_keyCode == Keys.LWin ||
|
||||||
|
_keyCode == Keys.RWin)
|
||||||
|
_keyCode = Keys.None;
|
||||||
|
|
||||||
|
if (_modifiers == Keys.None)
|
||||||
|
{
|
||||||
|
if (_keyCode == Keys.None)
|
||||||
|
{
|
||||||
|
ResetHotkey();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We get here if we've got a hotkey that is valid without a modifier,
|
||||||
|
// like F1-F12, Media-keys etc.
|
||||||
|
Text = _keyCode.ToString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Text = string.Join(KeySeparator, new[] { KeysToString(_modifiers), KeysToString(_keyCode) });
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string KeysToString(Keys keys)
|
||||||
|
{
|
||||||
|
if (keys == Keys.None) return "None";
|
||||||
|
|
||||||
|
var modifiers = (keys & Keys.Modifiers);
|
||||||
|
var keyCode = (keys & Keys.KeyCode);
|
||||||
|
|
||||||
|
var strings = new List<string>();
|
||||||
|
|
||||||
|
if (modifiers != 0)
|
||||||
|
{
|
||||||
|
var modifierStrings = new List<string>(modifiers.ToString().Replace(", ", ",").Split(','));
|
||||||
|
modifierStrings.Sort(new KeyModifierComparer());
|
||||||
|
strings.AddRange(modifierStrings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCode != 0)
|
||||||
|
{
|
||||||
|
var keyString = keyCode.ToString();
|
||||||
|
var keyHashtable = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{"Next", "PageDown"},
|
||||||
|
{"Oemcomma", ","},
|
||||||
|
{"OemMinus", "-"},
|
||||||
|
{"OemOpenBrackets", "["},
|
||||||
|
{"OemPeriod", "."},
|
||||||
|
{"Oemplus", "="},
|
||||||
|
{"OemQuestion", "/"},
|
||||||
|
{"Oemtilde", "`"},
|
||||||
|
{"D0", "0"},
|
||||||
|
{"D1", "1"},
|
||||||
|
{"D2", "2"},
|
||||||
|
{"D3", "3"},
|
||||||
|
{"D4", "4"},
|
||||||
|
{"D5", "5"},
|
||||||
|
{"D6", "6"},
|
||||||
|
{"D7", "7"},
|
||||||
|
{"D8", "8"},
|
||||||
|
{"D9", "9"},
|
||||||
|
};
|
||||||
|
if (keyHashtable.ContainsKey(keyString)) keyString = keyHashtable[keyString];
|
||||||
|
strings.Add(keyString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Join(KeySeparator, strings.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class KeyModifierComparer : IComparer<string>
|
||||||
|
{
|
||||||
|
private static readonly List<string> ModifierOrder = new List<string>
|
||||||
|
{
|
||||||
|
"control",
|
||||||
|
"alt",
|
||||||
|
"shift",
|
||||||
|
};
|
||||||
|
|
||||||
|
public int Compare(string x, string y)
|
||||||
|
{
|
||||||
|
var xIndex = ModifierOrder.IndexOf(x.ToLowerInvariant());
|
||||||
|
var yIndex = ModifierOrder.IndexOf(y.ToLowerInvariant());
|
||||||
|
return xIndex - yIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
258
SharedLibraryNG/KeyboardHook.cs
Normal file
258
SharedLibraryNG/KeyboardHook.cs
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
//
|
||||||
|
// Based on code from Stephen Toub's MSDN blog at
|
||||||
|
// http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace SharedLibraryNG
|
||||||
|
{
|
||||||
|
public class KeyboardHook
|
||||||
|
{
|
||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
public static extern bool PostMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, HookKeyMsgData lParam);
|
||||||
|
// ReSharper restore InconsistentNaming
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum ModifierKeys
|
||||||
|
{
|
||||||
|
None = 0x0000,
|
||||||
|
Shift = 0x0001,
|
||||||
|
LeftShift = 0x002,
|
||||||
|
RightShift = 0x004,
|
||||||
|
Control = 0x0008,
|
||||||
|
LeftControl = 0x010,
|
||||||
|
RightControl = 0x20,
|
||||||
|
Alt = 0x0040,
|
||||||
|
LeftAlt = 0x0080,
|
||||||
|
RightAlt = 0x0100,
|
||||||
|
Win = 0x0200,
|
||||||
|
LeftWin = 0x0400,
|
||||||
|
RightWin = 0x0800,
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class KeyNotificationEntry
|
||||||
|
: IEquatable<KeyNotificationEntry>
|
||||||
|
{
|
||||||
|
public IntPtr WindowHandle;
|
||||||
|
public Int32 KeyCode;
|
||||||
|
public ModifierKeys ModifierKeys;
|
||||||
|
public Boolean Block;
|
||||||
|
|
||||||
|
public bool Equals(KeyNotificationEntry obj)
|
||||||
|
{
|
||||||
|
return (WindowHandle == obj.WindowHandle &&
|
||||||
|
KeyCode == obj.KeyCode &&
|
||||||
|
ModifierKeys == obj.ModifierKeys &&
|
||||||
|
Block == obj.Block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public const string HookKeyMsgName = "HOOKKEYMSG-{56BE0940-34DA-11E1-B308-C6714824019B}";
|
||||||
|
private static Int32 _hookKeyMsg;
|
||||||
|
public static Int32 HookKeyMsg
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_hookKeyMsg == 0)
|
||||||
|
{
|
||||||
|
_hookKeyMsg = Win32.RegisterWindowMessage(HookKeyMsgName).ToInt32();
|
||||||
|
if (_hookKeyMsg == 0)
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||||
|
}
|
||||||
|
return _hookKeyMsg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is a custom structure that will be passed to
|
||||||
|
// the requested hWnd via a WM_APP_HOOKKEYMSG message
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public class HookKeyMsgData
|
||||||
|
{
|
||||||
|
public Int32 KeyCode;
|
||||||
|
public ModifierKeys ModifierKeys;
|
||||||
|
public Boolean WasBlocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int _referenceCount;
|
||||||
|
private static IntPtr _hook;
|
||||||
|
private static readonly Win32.LowLevelKeyboardProcDelegate LowLevelKeyboardProcStaticDelegate = LowLevelKeyboardProc;
|
||||||
|
private static readonly List<KeyNotificationEntry> NotificationEntries = new List<KeyNotificationEntry>();
|
||||||
|
|
||||||
|
public KeyboardHook()
|
||||||
|
{
|
||||||
|
_referenceCount++;
|
||||||
|
SetHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
~KeyboardHook()
|
||||||
|
{
|
||||||
|
_referenceCount--;
|
||||||
|
if (_referenceCount < 1) UnsetHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetHook()
|
||||||
|
{
|
||||||
|
if (_hook != IntPtr.Zero) return;
|
||||||
|
|
||||||
|
var curProcess = Process.GetCurrentProcess();
|
||||||
|
var curModule = curProcess.MainModule;
|
||||||
|
|
||||||
|
var hook = Win32.SetWindowsHookEx(Win32.WH_KEYBOARD_LL, LowLevelKeyboardProcStaticDelegate, Win32.GetModuleHandle(curModule.ModuleName), 0);
|
||||||
|
if (hook == IntPtr.Zero)
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||||
|
|
||||||
|
_hook = hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void UnsetHook()
|
||||||
|
{
|
||||||
|
if (_hook == IntPtr.Zero) return;
|
||||||
|
|
||||||
|
Win32.UnhookWindowsHookEx(_hook);
|
||||||
|
_hook = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IntPtr LowLevelKeyboardProc(Int32 nCode, IntPtr wParam, Win32.KBDLLHOOKSTRUCT lParam)
|
||||||
|
{
|
||||||
|
var wParamInt = wParam.ToInt32();
|
||||||
|
var result = 0;
|
||||||
|
|
||||||
|
if (nCode == Win32.HC_ACTION)
|
||||||
|
{
|
||||||
|
switch (wParamInt)
|
||||||
|
{
|
||||||
|
case Win32.WM_KEYDOWN:
|
||||||
|
case Win32.WM_SYSKEYDOWN:
|
||||||
|
case Win32.WM_KEYUP:
|
||||||
|
case Win32.WM_SYSKEYUP:
|
||||||
|
result = OnKey(wParamInt, lParam);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != 0) return new IntPtr(result);
|
||||||
|
|
||||||
|
return Win32.CallNextHookEx(_hook, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int OnKey(Int32 msg, Win32.KBDLLHOOKSTRUCT key)
|
||||||
|
{
|
||||||
|
var result = 0;
|
||||||
|
|
||||||
|
foreach (var notificationEntry in NotificationEntries)
|
||||||
|
if (GetFocusWindow() == notificationEntry.WindowHandle && notificationEntry.KeyCode == key.vkCode)
|
||||||
|
{
|
||||||
|
var modifierKeys = GetModifierKeyState();
|
||||||
|
if (!ModifierKeysMatch(notificationEntry.ModifierKeys, modifierKeys)) continue;
|
||||||
|
|
||||||
|
var wParam = new IntPtr(msg);
|
||||||
|
var lParam = new HookKeyMsgData
|
||||||
|
{
|
||||||
|
KeyCode = key.vkCode,
|
||||||
|
ModifierKeys = modifierKeys,
|
||||||
|
WasBlocked = notificationEntry.Block,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!PostMessage(notificationEntry.WindowHandle, HookKeyMsg, wParam, lParam))
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||||
|
|
||||||
|
if (notificationEntry.Block) result = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IntPtr GetFocusWindow()
|
||||||
|
{
|
||||||
|
var guiThreadInfo = new Win32.GUITHREADINFO();
|
||||||
|
if (!Win32.GetGUIThreadInfo(0, guiThreadInfo))
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||||
|
return Win32.GetAncestor(guiThreadInfo.hwndFocus, Win32.GA_ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Dictionary<Int32, ModifierKeys> ModifierKeyTable = new Dictionary<Int32, ModifierKeys>
|
||||||
|
{
|
||||||
|
{ Win32.VK_SHIFT, ModifierKeys.Shift },
|
||||||
|
{ Win32.VK_LSHIFT, ModifierKeys.LeftShift },
|
||||||
|
{ Win32.VK_RSHIFT, ModifierKeys.RightShift },
|
||||||
|
{ Win32.VK_CONTROL, ModifierKeys.Control },
|
||||||
|
{ Win32.VK_LCONTROL, ModifierKeys.LeftControl },
|
||||||
|
{ Win32.VK_RCONTROL, ModifierKeys.RightControl },
|
||||||
|
{ Win32.VK_MENU, ModifierKeys.Alt },
|
||||||
|
{ Win32.VK_LMENU, ModifierKeys.LeftAlt },
|
||||||
|
{ Win32.VK_RMENU, ModifierKeys.RightAlt },
|
||||||
|
{ Win32.VK_LWIN, ModifierKeys.LeftWin },
|
||||||
|
{ Win32.VK_RWIN, ModifierKeys.RightWin },
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ModifierKeys GetModifierKeyState()
|
||||||
|
{
|
||||||
|
var modifierKeyState = ModifierKeys.None;
|
||||||
|
|
||||||
|
foreach (KeyValuePair<Int32, ModifierKeys> pair in ModifierKeyTable)
|
||||||
|
{
|
||||||
|
if ((Win32.GetAsyncKeyState(pair.Key) & Win32.KEYSTATE_PRESSED) != 0) modifierKeyState |= pair.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((modifierKeyState & ModifierKeys.LeftWin) != 0) modifierKeyState |= ModifierKeys.Win;
|
||||||
|
if ((modifierKeyState & ModifierKeys.RightWin) != 0) modifierKeyState |= ModifierKeys.Win;
|
||||||
|
|
||||||
|
return modifierKeyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean ModifierKeysMatch(ModifierKeys requestedKeys, ModifierKeys pressedKeys)
|
||||||
|
{
|
||||||
|
if ((requestedKeys & ModifierKeys.Shift) != 0) pressedKeys &= ~(ModifierKeys.LeftShift | ModifierKeys.RightShift);
|
||||||
|
if ((requestedKeys & ModifierKeys.Control) != 0) pressedKeys &= ~(ModifierKeys.LeftControl | ModifierKeys.RightControl);
|
||||||
|
if ((requestedKeys & ModifierKeys.Alt) != 0) pressedKeys &= ~(ModifierKeys.LeftAlt | ModifierKeys.RightAlt);
|
||||||
|
if ((requestedKeys & ModifierKeys.Win) != 0) pressedKeys &= ~(ModifierKeys.LeftWin | ModifierKeys.RightWin);
|
||||||
|
return requestedKeys == pressedKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RequestKeyNotification(IntPtr windowHandle, Int32 keyCode, Boolean block)
|
||||||
|
{
|
||||||
|
RequestKeyNotification(windowHandle, keyCode, ModifierKeys.None, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RequestKeyNotification(IntPtr windowHandle, Int32 keyCode, ModifierKeys modifierKeys = ModifierKeys.None, Boolean block = false)
|
||||||
|
{
|
||||||
|
var newNotificationEntry = new KeyNotificationEntry
|
||||||
|
{
|
||||||
|
WindowHandle = windowHandle,
|
||||||
|
KeyCode = keyCode,
|
||||||
|
ModifierKeys = modifierKeys,
|
||||||
|
Block = block,
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var notificationEntry in NotificationEntries)
|
||||||
|
if (notificationEntry == newNotificationEntry) return;
|
||||||
|
|
||||||
|
NotificationEntries.Add(newNotificationEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CancelKeyNotification(IntPtr windowHandle, Int32 keyCode, Boolean block)
|
||||||
|
{
|
||||||
|
CancelKeyNotification(windowHandle, keyCode, ModifierKeys.None, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CancelKeyNotification(IntPtr windowHandle, Int32 keyCode, ModifierKeys modifierKeys = ModifierKeys.None, Boolean block = false)
|
||||||
|
{
|
||||||
|
var notificationEntry = new KeyNotificationEntry
|
||||||
|
{
|
||||||
|
WindowHandle = windowHandle,
|
||||||
|
KeyCode = keyCode,
|
||||||
|
ModifierKeys = modifierKeys,
|
||||||
|
Block = block,
|
||||||
|
};
|
||||||
|
|
||||||
|
NotificationEntries.Remove(notificationEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
SharedLibraryNG/Properties/AssemblyInfo.cs
Normal file
36
SharedLibraryNG/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("SharedLibraryNG")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("SharedLibraryNG")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2013")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("f4470853-f933-4203-9d2a-b3c731e225c7")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
55
SharedLibraryNG/SharedLibraryNG.csproj
Normal file
55
SharedLibraryNG/SharedLibraryNG.csproj
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProductVersion>8.0.30703</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{0F615504-5F30-4CF2-8341-1DE7FEC95A23}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>SharedLibraryNG</RootNamespace>
|
||||||
|
<AssemblyName>SharedLibraryNG</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="HotkeyControl.cs">
|
||||||
|
<SubType>Component</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="KeyboardHook.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Win32.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
||||||
171
SharedLibraryNG/Win32.cs
Normal file
171
SharedLibraryNG/Win32.cs
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace SharedLibraryNG
|
||||||
|
{
|
||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
public static class Win32
|
||||||
|
{
|
||||||
|
#region Functions
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
|
public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProcDelegate lpfn, IntPtr hMod, Int32 dwThreadId);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
|
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, KBDLLHOOKSTRUCT lParam);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
|
public static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
|
public static extern IntPtr RegisterWindowMessage(string lpString);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
public static extern bool GetGUIThreadInfo(Int32 idThread, GUITHREADINFO lpgui);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
|
public static extern IntPtr GetAncestor(IntPtr hwnd, UInt32 gaFlags);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
|
public static extern Int16 GetAsyncKeyState(Int32 vKey);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Delegates
|
||||||
|
|
||||||
|
public delegate IntPtr LowLevelKeyboardProcDelegate(Int32 nCode, IntPtr wParam, KBDLLHOOKSTRUCT lParam);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Structures
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public class KBDLLHOOKSTRUCT
|
||||||
|
{
|
||||||
|
public Int32 vkCode;
|
||||||
|
public Int32 scanCode;
|
||||||
|
public Int32 flags;
|
||||||
|
public Int32 time;
|
||||||
|
public IntPtr dwExtraInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct RECT
|
||||||
|
{
|
||||||
|
public int left;
|
||||||
|
public int top;
|
||||||
|
public int right;
|
||||||
|
public int bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public class GUITHREADINFO
|
||||||
|
{
|
||||||
|
public GUITHREADINFO()
|
||||||
|
{
|
||||||
|
cbSize = Convert.ToInt32(Marshal.SizeOf(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Int32 cbSize;
|
||||||
|
public Int32 flags;
|
||||||
|
public IntPtr hwndActive;
|
||||||
|
public IntPtr hwndFocus;
|
||||||
|
public IntPtr hwndCapture;
|
||||||
|
public IntPtr hwndMenuOwner;
|
||||||
|
public IntPtr hwndMoveSize;
|
||||||
|
public IntPtr hwndCaret;
|
||||||
|
public RECT rcCaret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
// GetAncestor
|
||||||
|
public const int GA_ROOT = 2;
|
||||||
|
|
||||||
|
// SetWindowsHookEx
|
||||||
|
public const int WH_KEYBOARD_LL = 13;
|
||||||
|
|
||||||
|
// LowLevelKeyboardProcDelegate
|
||||||
|
public const int HC_ACTION = 0;
|
||||||
|
|
||||||
|
// SendMessage
|
||||||
|
public const int WM_KEYDOWN = 0x0100;
|
||||||
|
public const int WM_KEYUP = 0x0101;
|
||||||
|
public const int WM_SYSKEYDOWN = 0x0104;
|
||||||
|
public const int WM_SYSKEYUP = 0x0105;
|
||||||
|
|
||||||
|
// GetAsyncKeyState
|
||||||
|
public const int KEYSTATE_PRESSED = 0x8000;
|
||||||
|
|
||||||
|
#region Virtual Keys
|
||||||
|
public const int VK_CANCEL = 0x0003;
|
||||||
|
public const int VK_BACK = 0x0008;
|
||||||
|
public const int VK_TAB = 0x0009;
|
||||||
|
public const int VK_CLEAR = 0x000C;
|
||||||
|
public const int VK_RETURN = 0x000D;
|
||||||
|
public const int VK_PAUSE = 0x0013;
|
||||||
|
public const int VK_ESCAPE = 0x001B;
|
||||||
|
public const int VK_SNAPSHOT = 0x002C;
|
||||||
|
public const int VK_INSERT = 0x002D;
|
||||||
|
public const int VK_DELETE = 0x002E;
|
||||||
|
public const int VK_HOME = 0x0024;
|
||||||
|
public const int VK_END = 0x0023;
|
||||||
|
public const int VK_PRIOR = 0x0021;
|
||||||
|
public const int VK_NEXT = 0x0022;
|
||||||
|
public const int VK_LEFT = 0x0025;
|
||||||
|
public const int VK_UP = 0x0026;
|
||||||
|
public const int VK_RIGHT = 0x0027;
|
||||||
|
public const int VK_DOWN = 0x0028;
|
||||||
|
public const int VK_SELECT = 0x0029;
|
||||||
|
public const int VK_PRINT = 0x002A;
|
||||||
|
public const int VK_EXECUTE = 0x002B;
|
||||||
|
public const int VK_HELP = 0x002F;
|
||||||
|
public const int VK_LWIN = 0x005B;
|
||||||
|
public const int VK_RWIN = 0x005C;
|
||||||
|
public const int VK_APPS = 0x005D;
|
||||||
|
public const int VK_F1 = 0x0070;
|
||||||
|
public const int VK_F2 = 0x0071;
|
||||||
|
public const int VK_F3 = 0x0072;
|
||||||
|
public const int VK_F4 = 0x0073;
|
||||||
|
public const int VK_F5 = 0x0074;
|
||||||
|
public const int VK_F6 = 0x0075;
|
||||||
|
public const int VK_F7 = 0x0076;
|
||||||
|
public const int VK_F8 = 0x0077;
|
||||||
|
public const int VK_F9 = 0x0078;
|
||||||
|
public const int VK_F10 = 0x0079;
|
||||||
|
public const int VK_F11 = 0x007A;
|
||||||
|
public const int VK_F12 = 0x007B;
|
||||||
|
public const int VK_SHIFT = 0x0010;
|
||||||
|
public const int VK_LSHIFT = 0x00A0;
|
||||||
|
public const int VK_RSHIFT = 0x00A1;
|
||||||
|
public const int VK_CONTROL = 0x0011;
|
||||||
|
public const int VK_LCONTROL = 0x00A2;
|
||||||
|
public const int VK_RCONTROL = 0x00A3;
|
||||||
|
public const int VK_MENU = 0x0012;
|
||||||
|
public const int VK_LMENU = 0x00A4;
|
||||||
|
public const int VK_RMENU = 0x00A5;
|
||||||
|
|
||||||
|
public const int VK_OEM_1 = 0x00BA;
|
||||||
|
public const int VK_OEM_2 = 0x00BF;
|
||||||
|
public const int VK_OEM_3 = 0x00C0;
|
||||||
|
public const int VK_OEM_4 = 0x00DB;
|
||||||
|
public const int VK_OEM_5 = 0x00DC;
|
||||||
|
public const int VK_OEM_6 = 0x00DD;
|
||||||
|
public const int VK_OEM_7 = 0x00DE;
|
||||||
|
public const int VK_OEM_8 = 0x00DF;
|
||||||
|
public const int VK_OEM_102 = 0x00E2;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
// ReSharper restore InconsistentNaming
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,8 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Installer", "mRemoteNGInsta
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mRemoteNGSpecs", "mRemoteNGSpecs\mRemoteNGSpecs.csproj", "{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mRemoteNGSpecs", "mRemoteNGSpecs\mRemoteNGSpecs.csproj", "{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedLibraryNG", "SharedLibraryNG\SharedLibraryNG.csproj", "{0F615504-5F30-4CF2-8341-1DE7FEC95A23}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug Portable|Any CPU = Debug Portable|Any CPU
|
Debug Portable|Any CPU = Debug Portable|Any CPU
|
||||||
@@ -118,6 +120,26 @@ Global
|
|||||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|Any CPU.ActiveCfg = Release|x86
|
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|Any CPU.ActiveCfg = Release|x86
|
||||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|x86.ActiveCfg = Release|x86
|
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|x86.ActiveCfg = Release|x86
|
||||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|x86.Build.0 = Release|x86
|
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|x86.Build.0 = Release|x86
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug Portable|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug Portable|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug Portable|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug Portable|x86.Build.0 = Debug|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Installer|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Installer|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Installer|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Installer|x86.Build.0 = Release|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Portable|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Portable|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Portable|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Portable|x86.Build.0 = Release|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
Reference in New Issue
Block a user