728x90
반응형
728x170
▶ HookType.cs
namespace TestProject
{
/// <summary>
/// 후킹 타입
/// </summary>
public enum HookType : int
{
/// <summary>
/// WH_JOURNALRECORD
/// </summary>
WH_JOURNALRECORD = 0,
/// <summary>
/// WH_JOURNALPLAYBACK
/// </summary>
WH_JOURNALPLAYBACK = 1,
/// <summary>
/// WH_KEYBOARD
/// </summary>
WH_KEYBOARD = 2,
/// <summary>
/// WH_GETMESSAGE
/// </summary>
WH_GETMESSAGE = 3,
/// <summary>
/// WH_CALLWNDPROC
/// </summary>
WH_CALLWNDPROC = 4,
/// <summary>
/// WH_CBT
/// </summary>
WH_CBT = 5,
/// <summary>
/// WH_SYSMSGFILTER
/// </summary>
WH_SYSMSGFILTER = 6,
/// <summary>
/// WH_MOUSE
/// </summary>
WH_MOUSE = 7,
/// <summary>
/// WH_HARDWARE
/// </summary>
WH_HARDWARE = 8,
/// <summary>
/// WH_DEBUG
/// </summary>
WH_DEBUG = 9,
/// <summary>
/// WH_SHELL
/// </summary>
WH_SHELL = 10,
/// <summary>
/// WH_FOREGROUNDIDLE
/// </summary>
WH_FOREGROUNDIDLE = 11,
/// <summary>
/// WH_CALLWNDPROCRET
/// </summary>
WH_CALLWNDPROCRET = 12,
/// <summary>
/// WH_KEYBOARD_LL
/// </summary>
WH_KEYBOARD_LL = 13,
/// <summary>
/// WH_MOUSE_LL
/// </summary>
WH_MOUSE_LL = 14
}
}
728x90
▶ KeyboardHookStructureFlag.cs
namespace TestProject
{
/// <summary>
/// 키보드 후킹 구조체 플래그
/// </summary>
public enum KeyboardHookStructureFlag
{
/// <summary>
/// LLKHF_EXTENDED
/// </summary>
LLKHF_EXTENDED = 0x01,
/// <summary>
/// LLKHF_INJECTED
/// </summary>
LLKHF_INJECTED = 0x10,
/// <summary>
/// LLKHF_ALTDOWN
/// </summary>
LLKHF_ALTDOWN = 0x20,
/// <summary>
/// LLKHF_UP
/// </summary>
LLKHF_UP = 0x80
}
}
300x250
▶ MouseMessage.cs
namespace TestProject
{
/// <summary>
/// 마우스 메시지
/// </summary>
public enum MouseMessage
{
/// <summary>
/// WM_LBUTTONDOWN
/// </summary>
WM_LBUTTONDOWN = 0x0201,
/// <summary>
/// WM_LBUTTONUP
/// </summary>
WM_LBUTTONUP = 0x0202,
/// <summary>
/// WM_MOUSEMOVE
/// </summary>
WM_MOUSEMOVE = 0x0200,
/// <summary>
/// WM_MOUSEWHEEL
/// </summary>
WM_MOUSEWHEEL = 0x020A,
/// <summary>
/// WM_RBUTTONDOWN
/// </summary>
WM_RBUTTONDOWN = 0x0204,
/// <summary>
/// WM_RBUTTONUP
/// </summary>
WM_RBUTTONUP = 0x0205,
/// <summary>
/// WM_NCLBUTTONDOWN
/// </summary>
WM_NCLBUTTONDOWN = 0x00A
}
}
▶ POINT.cs
using System.Runtime.InteropServices;
namespace TestProject
{
/// <summary>
/// 포인트
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// X
/// </summary>
public int X;
/// <summary>
/// Y
/// </summary>
public int Y;
#endregion
}
}
▶ KEYBOARDHOOKSTRUCT.cs
using System;
using System.Runtime.InteropServices;
namespace TestProject
{
/// <summary>
/// 키보드 후킹 구조체
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public class KEYBOARDHOOKSTRUCT
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 가상 키 코드
/// </summary>
public uint VirtualKeyCode;
/// <summary>
/// 스캔 코드
/// </summary>
public uint ScanCode;
/// <summary>
/// 키보드 후킹 구조체 플래그
/// </summary>
public KeyboardHookStructureFlag Flag;
/// <summary>
/// 시간
/// </summary>
public uint Time;
/// <summary>
/// 부가 정보 핸들
/// </summary>
public UIntPtr ExtraInformationHandle;
#endregion
}
}
▶ MOUSEHOOKSTRUCT.cs
using System;
using System.Runtime.InteropServices;
namespace TestProject
{
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEHOOKSTRUCT
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 위치
/// </summary>
public POINT Location;
/// <summary>
/// 윈도우 핸들
/// </summary>
public IntPtr WindowHandle;
/// <summary>
/// 히트 테스트 코드
/// </summary>
public uint HitTestCode;
/// <summary>
/// 부가 정보 핸들
/// </summary>
public IntPtr ExtraInformationHandle;
#endregion
}
}
▶ KeyData.cs
namespace TestProject
{
/// <summary>
/// 키 데이터
/// </summary>
public class KeyData
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 디폴트 키 - DefaultKey
/// <summary>
/// 디폴트 키
/// </summary>
public string DefaultKey;
#endregion
#region SHIFT 키 - ShiftKey
/// <summary>
/// SHIFT 키
/// </summary>
public string ShiftKey;
#endregion
#region 한글 키 - HangulKey
/// <summary>
/// 한글 키
/// </summary>
public string HangulKey;
#endregion
#region 한글 SHIFT 키 - HangulShiftKey
/// <summary>
/// 한글 SHIFT 키
/// </summary>
public string HangulShiftKey;
#endregion
}
}
▶ WIN32Helper.cs
using System;
using System.Runtime.InteropServices;
namespace TestProject
{
/// <summary>
/// WIN32 헬퍼
/// </summary>
public class WIN32Helper
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Import
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 윈도우 후킹 설정하기 (확장) - SetWindowsHookEx(hookID, hookProc, moduleHandle, threadID)
/// <summary>
/// 윈도우 후킹 설정하기 (확장)
/// </summary>
/// <param name="hookID">후킹 ID</param>
/// <param name="hookProc">후킹 프로시저</param>
/// <param name="moduleHandle">모듈 핸들</param>
/// <param name="threadID">스레드 ID</param>
/// <returns>후킹 핸들</returns>
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int hookID, HookProc hookProc, IntPtr moduleHandle, uint threadID);
#endregion
#region 윈도우 후킹 해제하기 (확장) - UnhookWindowsHookEx(hookHandle)
/// <summary>
/// 윈도우 후킹 해제하기 (확장)
/// </summary>
/// <param name="hookHandle">후킹 핸들</param>
/// <returns>처리 결과</returns>
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hookHandle);
#endregion
#region 다음 후킹 호출하기 (확장) - CallNextHookEx(hookHandle, code, wordParameter, longParameter)
/// <summary>
/// 다음 후킹 호출하기 (확장)
/// </summary>
/// <param name="hookHandle">후킹 핸들</param>
/// <param name="code">코드</param>
/// <param name="wordParameter">WORD 매개 변수</param>
/// <param name="longParameter">LONG 매개 변수</param>
/// <returns>처리 결과</returns>
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(IntPtr hookHandle, int code, IntPtr wordParameter, IntPtr longParameter);
#endregion
#region 모듈 핸들 구하기 - GetModuleHandle(moduleName)
/// <summary>
/// 모듈 핸들 구하기
/// </summary>
/// <param name="moduleName">모듈명</param>
/// <returns>모듈 핸들</returns>
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string moduleName);
#endregion
#region 현재 스레드 ID 구하기 - GetCurrentThreadId()
/// <summary>
/// 현재 스레드 ID 구하기
/// </summary>
/// <returns>현재 스레드 ID</returns>
[DllImport("kernel32.dll")]
public static extern uint GetCurrentThreadId();
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Delegate
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 후킹 프로시저 대리자 - HookProc(code, wordParameter, longParameter)
/// <summary>
/// 후킹 프로시저 대리자
/// </summary>
/// <param name="code">코드</param>
/// <param name="wordParameter">WORD 매개 변수</param>
/// <param name="longParameter">LONG 매개 변수</param>
/// <returns>처리 결과</returns>
public delegate IntPtr HookProc(int code, IntPtr wordParameter, IntPtr longParameter);
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// HC_ACTION
/// </summary>
public const int HC_ACTION = 0;
#endregion
}
}
▶ VisualElementHelper.cs
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
namespace TestProject
{
/// <summary>
/// 비주얼 엘리먼트 헬퍼
/// </summary>
public static class VisualElementHelper
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 부모 구하기 - GetParent(child)
/// <summary>
/// 부모 구하기
/// </summary>
/// <param name="child">자식</param>
/// <returns>부모</returns>
public static DependencyObject GetParent(this DependencyObject child)
{
if(child == null)
{
return null;
}
ContentElement childContentElement = child as ContentElement;
if(childContentElement != null)
{
DependencyObject parent = ContentOperations.GetParent(childContentElement);
if(parent != null)
{
return parent;
}
FrameworkContentElement childFrameworkContentElement = childContentElement as FrameworkContentElement;
return childFrameworkContentElement != null ? childFrameworkContentElement.Parent : null;
}
FrameworkElement childFrameworkElement = child as FrameworkElement;
if(childFrameworkElement != null)
{
DependencyObject parent = childFrameworkElement.Parent;
if(parent != null)
{
return parent;
}
}
return VisualTreeHelper.GetParent(child);
}
#endregion
#region 부모 찾기 시도하기 - TryFindParent<TParent>(child)
/// <summary>
/// 부모 찾기 시도하기
/// </summary>
/// <typeparam name="TParent">부모 타입</typeparam>
/// <param name="child">자식</param>
/// <returns>부모</returns>
public static TParent TryFindParent<TParent>(this DependencyObject child) where TParent : DependencyObject
{
DependencyObject parentObject = GetParent(child);
if(parentObject == null)
{
return null;
}
TParent parent = parentObject as TParent;
if(parent != null)
{
return parent;
}
else
{
return TryFindParent<TParent>(parentObject);
}
}
#endregion
#region 자식 열거 가능형 구하기 - GetChildEnumerable(parent)
/// <summary>
/// 자식 열거 가능형 구하기
/// </summary>
/// <param name="parent">부모</param>
/// <returns>자식 열거 가능형</returns>
public static IEnumerable<DependencyObject> GetChildEnumerable(this DependencyObject parent)
{
if(parent == null)
{
yield break;
}
if(parent is ContentElement || parent is FrameworkElement)
{
foreach(object childObject in LogicalTreeHelper.GetChildren(parent))
{
DependencyObject child = childObject as DependencyObject;
if(child != null)
{
yield return (DependencyObject)childObject;
}
}
}
else
{
int count = VisualTreeHelper.GetChildrenCount(parent);
for(int i = 0; i < count; i++)
{
yield return VisualTreeHelper.GetChild(parent, i);
}
}
}
#endregion
#region 자식 찾기 - FindChildren<TChild>(parent)
/// <summary>
/// 자식 찾기
/// </summary>
/// <typeparam name="TChild">자식 타입</typeparam>
/// <param name="parent">부모</param>
/// <returns>자식 열거 가능형</returns>
public static IEnumerable<TChild> FindChildren<TChild>(this DependencyObject parent) where TChild : DependencyObject
{
if(parent != null)
{
IEnumerable<DependencyObject> childEnumerable = GetChildEnumerable(parent);
foreach(DependencyObject child in childEnumerable)
{
if(child != null && child is TChild)
{
yield return (TChild)child;
}
foreach(TChild descendant in FindChildren<TChild>(child))
{
yield return descendant;
}
}
}
}
#endregion
#region 포인트에서 찾기 시도하기 - TryFindFromPoint<T>(referenceElement, point)
/// <summary>
/// 포인트에서 찾기 시도하기
/// </summary>
/// <typeparam name="TElement">엘리먼트 타입</typeparam>
/// <param name="referenceElement">참조 엘리먼트</param>
/// <param name="point">포인트</param>
/// <returns>엘리먼트</returns>
public static TElement TryFindFromPoint<TElement>(UIElement referenceElement, Point point) where TElement : DependencyObject
{
DependencyObject element = referenceElement.InputHitTest(point) as DependencyObject;
if(element == null)
{
return null;
}
else if(element is TElement)
{
return (TElement)element;
}
else
{
return TryFindParent<TElement>(element);
}
}
#endregion
}
}
▶ HookingHelper.cs
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
namespace TestProject
{
/// <summary>
/// 후킹 헬퍼
/// </summary>
public class HookingHelper
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Delegate
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 키 클릭시 핸들러 - KeyClickHandler(keyCode)
/// <summary>
/// 키 클릭시 핸들러
/// </summary>
/// <param name="keyCode">키 코드</param>
public delegate void KeyClickHandler(uint keyCode);
#endregion
#region 마우스 클릭시 핸들러 - MouseClickHandler(point, message)
/// <summary>
/// 마우스 클릭시 핸들러
/// </summary>
/// <param name="point">포인트</param>
/// <param name="message">메시지</param>
public delegate void MouseClickHandler(POINT point, MouseMessage message);
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Event
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 키 클릭시 이벤트 - KeyClick
/// <summary>
/// 키 클릭시 이벤트
/// </summary>
public static event KeyClickHandler KeyClick;
#endregion
#region 마우스 클릭시 이벤트 - MouseClick
/// <summary>
/// 마우스 클릭시 이벤트
/// </summary>
public static event MouseClickHandler MouseClick;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 핸들
/// </summary>
private static IntPtr _handle = IntPtr.Zero;
/// <summary>
/// 모듈 핸들
/// </summary>
private static IntPtr _moduleHandle = IntPtr.Zero;
/// <summary>
/// 키보드 후킹 핸들
/// </summary>
private static IntPtr _keyboardHookHandle = IntPtr.Zero;
/// <summary>
/// 마우스 후킹 핸들
/// </summary>
private static IntPtr _mouseHookHandle = IntPtr.Zero;
/// <summary>
/// 키보드 프로시저
/// </summary>
private static WIN32Helper.HookProc _keyboardProc = new WIN32Helper.HookProc(KeyboardProc);
/// <summary>
/// 마우스 프로시저
/// </summary>
private static WIN32Helper.HookProc _mouseProc = new WIN32Helper.HookProc(MouseProc);
/// <summary>
/// 마우스 후킹 구조체
/// </summary>
private static MOUSEHOOKSTRUCT _mouseHookStructure;
/// <summary>
/// 이전 윈도우 핸들
/// </summary>
private static IntPtr _previousWindowHandle = IntPtr.Zero;
/// <summary>
/// 이전 포커스 핸들
/// </summary>
private static IntPtr _previusFocusHandle = IntPtr.Zero;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 실행 여부 - IsRun
/// <summary>
/// 실행 여부
/// </summary>
public static bool IsRun { get; private set; }
#endregion
#region 전역 사용 여부 - UseGlobal
/// <summary>
/// 전역 사용 여부
/// </summary>
public static bool UseGlobal { get; set; }
#endregion
#region 후킹 영역 - HookArea
/// <summary>
/// 후킹 영역
/// </summary>
public static Rect HookArea { get; set; }
#endregion
#region 후킹 엘리먼트 - HookElement
/// <summary>
/// 후킹 엘리먼트
/// </summary>
public static UIElement HookElement { get; set; }
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 시작하기 - Start()
/// <summary>
/// 시작하기
/// </summary>
public static void Start()
{
if(!IsRun)
{
uint threadID = WIN32Helper.GetCurrentThreadId();
using(Process process = Process.GetCurrentProcess())
{
using(ProcessModule processModule = process.MainModule)
{
_handle = process.MainWindowHandle;
_moduleHandle = WIN32Helper.GetModuleHandle(processModule.ModuleName);
_keyboardHookHandle = WIN32Helper.SetWindowsHookEx
(
(int)HookType.WH_KEYBOARD_LL,
_keyboardProc,
_moduleHandle,
0
);
_mouseHookHandle = WIN32Helper.SetWindowsHookEx
(
(int)HookType.WH_MOUSE_LL,
_mouseProc,
_moduleHandle,
0
);
IsRun = true;
}
}
}
}
#endregion
#region 중단하기 - Stop()
/// <summary>
/// 중단하기
/// </summary>
public static void Stop()
{
if(IsRun)
{
WIN32Helper.UnhookWindowsHookEx(_keyboardHookHandle);
WIN32Helper.UnhookWindowsHookEx(_mouseHookHandle );
IsRun = false;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Private
#region 후킹 영역 여부 구하기 - IsHookingArea()
/// <summary>
/// 후킹 영역 여부 구하기
/// </summary>
/// <returns>후킹 영역 여부</returns>
private static bool IsHookingArea()
{
if(HookElement != null && !HookArea.IsEmpty)
{
Point point = HookElement.PointFromScreen
(
new Point
(
_mouseHookStructure.Location.X,
_mouseHookStructure.Location.Y)
);
bool contains = HookArea.Contains(point);
return contains;
}
return true;
}
#endregion
#region 키보드 프로시저 처리하기 - KeyboardProc(code, wordParameter, longParameter)
/// <summary>
/// 키보드 프로시저 처리하기
/// </summary>
/// <param name="code">코드</param>
/// <param name="wordParameter">WORD 매개 변수</param>
/// <param name="longParameter">LONG 매개 변수</param>
/// <returns>처리 결과</returns>
private static IntPtr KeyboardProc(int code, IntPtr wordParameter, IntPtr longParameter)
{
if(code == WIN32Helper.HC_ACTION)
{
uint wordParameterValue = (uint)wordParameter;
long longParamererValue = (long)longParameter;
if(wordParameterValue == 256)
{
KEYBOARDHOOKSTRUCT keyboardHookStructure = (KEYBOARDHOOKSTRUCT)Marshal.PtrToStructure
(
longParameter,
typeof(KEYBOARDHOOKSTRUCT)
);
KeyClick?.Invoke(keyboardHookStructure.VirtualKeyCode);
}
if((wordParameterValue == 229 && longParamererValue == -2147483647) || (wordParameterValue == 229 && longParamererValue == -2147483648))
{
if(IsHookingArea())
{
return (IntPtr)1;
}
}
}
return WIN32Helper.CallNextHookEx(_keyboardHookHandle, code, wordParameter, longParameter);
}
#endregion
#region 마우스 프로시저 처리하기 - MouseProc(code, wordParameter, longParameter)
/// <summary>
/// 마우스 프로시저 처리하기
/// </summary>
/// <param name="code">코드</param>
/// <param name="wordParameter">WORD 매개 변수</param>
/// <param name="longParameter">LONG 매개 변수</param>
/// <returns>처리 결과</returns>
private static IntPtr MouseProc(int code, IntPtr wordParameter, IntPtr longParameter)
{
if(code >= 0)
{
_mouseHookStructure = (MOUSEHOOKSTRUCT)Marshal.PtrToStructure
(
longParameter,
typeof(MOUSEHOOKSTRUCT)
);
MouseMessage mouseMessage = (MouseMessage)wordParameter;
if(UseGlobal)
{
if(mouseMessage == MouseMessage.WM_LBUTTONDOWN || mouseMessage == MouseMessage.WM_LBUTTONUP)
{
MouseClick?.Invoke(_mouseHookStructure.Location, mouseMessage);
if(mouseMessage == MouseMessage.WM_LBUTTONDOWN && IsHookingArea())
{
return (IntPtr)1;
}
}
}
}
return WIN32Helper.CallNextHookEx(_mouseHookHandle, code, wordParameter, longParameter);
}
#endregion
}
}
▶ Simulator.cs
using WindowsInput;
namespace TestProject
{
/// <summary>
/// 시뮬레이터
/// </summary>
internal class Simulator
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Internal
#region 입력 시뮬레이터 - Input
/// <summary>
/// 입력 시뮬레이터
/// </summary>
internal static InputSimulator Input { get; private set; }
#endregion
#region 키보드 시뮬레이터 - Keyboard
/// <summary>
/// 키보드 시뮬레이터
/// </summary>
internal static KeyboardSimulator Keyboard { get; private set; }
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Static
#region 생성자 - Simulator()
/// <summary>
/// 생성자
/// </summary>
static Simulator()
{
Input = new InputSimulator();
Keyboard = new KeyboardSimulator(Input);
}
#endregion
}
}
▶ KeyButton.cs
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using WindowsInput.Native;
namespace TestProject
{
/// <summary>
/// 키 버튼
/// </summary>
public class KeyButton : Button
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Dependency Property
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 키 코드 속성 - KeyCodeProperty
/// <summary>
/// 키 코드 속성
/// </summary>
public static readonly DependencyProperty KeyCodeProperty = DependencyProperty.Register
(
"KeyCode",
typeof(VirtualKeyCode),
typeof(KeyButton)
);
#endregion
#region PRESS 여부 속성 - IsPressedProperty
/// <summary>
/// PRESS 여부 속성
/// </summary>
public static readonly new DependencyProperty IsPressedProperty = DependencyProperty.Register
(
"IsPressed",
typeof(bool),
typeof(KeyButton)
);
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 키 데이터 딕셔너리
/// </summary>
private static Dictionary<VirtualKeyCode, KeyData> _keyDataDictionary;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region PRESS 여부 - IsPressed
/// <summary>
/// PRESS 여부
/// </summary>
public new bool IsPressed
{
get
{
return (bool)GetValue(IsPressedProperty);
}
set
{
SetValue(IsPressedProperty, value);
}
}
#endregion
#region 키 코드 - KeyCode
/// <summary>
/// 키 코드
/// </summary>
public VirtualKeyCode KeyCode
{
get
{
return (VirtualKeyCode)GetValue(KeyCodeProperty);
}
set
{
SetValue(KeyCodeProperty, value);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Static
#region 생성자 - KeyButton()
/// <summary>
/// 생성자
/// </summary>
static KeyButton()
{
SetKeyDataDictionary();
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - KeyButton()
/// <summary>
/// 생성자
/// </summary>
public KeyButton()
{
Focusable = false;
IsTabStop = false;
ClickMode = ClickMode.Press;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region 키 데이터 딕셔너리 설정하기 - SetKeyDataDictionary()
/// <summary>
/// 키 데이터 딕셔너리 설정하기
/// </summary>
private static void SetKeyDataDictionary()
{
_keyDataDictionary = new Dictionary<VirtualKeyCode, KeyData>();
_keyDataDictionary.Add(VirtualKeyCode.VK_1, new KeyData { DefaultKey = "1", ShiftKey = "!" });
_keyDataDictionary.Add(VirtualKeyCode.VK_2, new KeyData { DefaultKey = "2", ShiftKey = "@" });
_keyDataDictionary.Add(VirtualKeyCode.VK_3, new KeyData { DefaultKey = "3", ShiftKey = "#" });
_keyDataDictionary.Add(VirtualKeyCode.VK_4, new KeyData { DefaultKey = "4", ShiftKey = "$" });
_keyDataDictionary.Add(VirtualKeyCode.VK_5, new KeyData { DefaultKey = "5", ShiftKey = "%" });
_keyDataDictionary.Add(VirtualKeyCode.VK_6, new KeyData { DefaultKey = "6", ShiftKey = "^" });
_keyDataDictionary.Add(VirtualKeyCode.VK_7, new KeyData { DefaultKey = "7", ShiftKey = "&" });
_keyDataDictionary.Add(VirtualKeyCode.VK_8, new KeyData { DefaultKey = "8", ShiftKey = "*" });
_keyDataDictionary.Add(VirtualKeyCode.VK_9, new KeyData { DefaultKey = "9", ShiftKey = "(" });
_keyDataDictionary.Add(VirtualKeyCode.VK_0, new KeyData { DefaultKey = "0", ShiftKey = ")" });
_keyDataDictionary.Add(VirtualKeyCode.VK_A, new KeyData { DefaultKey = "a", HangulKey = "ㅁ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_B, new KeyData { DefaultKey = "b", HangulKey = "ㅠ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_C, new KeyData { DefaultKey = "c", HangulKey = "ㅊ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_D, new KeyData { DefaultKey = "d", HangulKey = "ㅇ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_E, new KeyData { DefaultKey = "e", HangulKey = "ㄷ", HangulShiftKey = "ㄸ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_F, new KeyData { DefaultKey = "f", HangulKey = "ㄹ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_G, new KeyData { DefaultKey = "g", HangulKey = "ㅎ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_H, new KeyData { DefaultKey = "h", HangulKey = "ㅗ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_I, new KeyData { DefaultKey = "i", HangulKey = "ㅑ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_J, new KeyData { DefaultKey = "j", HangulKey = "ㅓ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_K, new KeyData { DefaultKey = "k", HangulKey = "ㅏ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_L, new KeyData { DefaultKey = "l", HangulKey = "ㅣ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_M, new KeyData { DefaultKey = "m", HangulKey = "ㅡ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_N, new KeyData { DefaultKey = "n", HangulKey = "ㅜ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_O, new KeyData { DefaultKey = "o", HangulKey = "ㅐ", HangulShiftKey = "ㅒ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_P, new KeyData { DefaultKey = "p", HangulKey = "ㅔ", HangulShiftKey = "ㅖ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_Q, new KeyData { DefaultKey = "q", HangulKey = "ㅂ", HangulShiftKey = "ㅃ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_R, new KeyData { DefaultKey = "r", HangulKey = "ㄱ", HangulShiftKey = "ㄲ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_S, new KeyData { DefaultKey = "s", HangulKey = "ㄴ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_T, new KeyData { DefaultKey = "t", HangulKey = "ㅅ", HangulShiftKey = "ㅆ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_U, new KeyData { DefaultKey = "u", HangulKey = "ㅕ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_V, new KeyData { DefaultKey = "v", HangulKey = "ㅍ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_W, new KeyData { DefaultKey = "w", HangulKey = "ㅈ", HangulShiftKey = "ㅉ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_X, new KeyData { DefaultKey = "x", HangulKey = "ㅌ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_Y, new KeyData { DefaultKey = "y", HangulKey = "ㅛ" });
_keyDataDictionary.Add(VirtualKeyCode.VK_Z, new KeyData { DefaultKey = "z", HangulKey = "ㅋ" });
_keyDataDictionary.Add(VirtualKeyCode.OEM_3 , new KeyData { DefaultKey = "`" , ShiftKey = "~" });
_keyDataDictionary.Add(VirtualKeyCode.OEM_MINUS , new KeyData { DefaultKey = "-" , ShiftKey = "_" });
_keyDataDictionary.Add(VirtualKeyCode.OEM_PLUS , new KeyData { DefaultKey = "=" , ShiftKey = "+" });
_keyDataDictionary.Add(VirtualKeyCode.BACK , new KeyData { DefaultKey = "Backspace" });
_keyDataDictionary.Add(VirtualKeyCode.TAB , new KeyData { DefaultKey = "Tab" });
_keyDataDictionary.Add(VirtualKeyCode.OEM_4 , new KeyData { DefaultKey = "[" , ShiftKey = "{" });
_keyDataDictionary.Add(VirtualKeyCode.OEM_6 , new KeyData { DefaultKey = "]" , ShiftKey = "}" });
_keyDataDictionary.Add(VirtualKeyCode.OEM_5 , new KeyData { DefaultKey = "₩" , ShiftKey = "|" });
_keyDataDictionary.Add(VirtualKeyCode.CAPITAL , new KeyData { DefaultKey = "Caps Lock" });
_keyDataDictionary.Add(VirtualKeyCode.OEM_1 , new KeyData { DefaultKey = ";" , ShiftKey = ":" });
_keyDataDictionary.Add(VirtualKeyCode.OEM_7 , new KeyData { DefaultKey = "'" , ShiftKey = "″" });
_keyDataDictionary.Add(VirtualKeyCode.RETURN , new KeyData { DefaultKey = "Enter" });
_keyDataDictionary.Add(VirtualKeyCode.SHIFT , new KeyData { DefaultKey = "Shift" });
_keyDataDictionary.Add(VirtualKeyCode.OEM_COMMA , new KeyData { DefaultKey = "," , ShiftKey = "<" });
_keyDataDictionary.Add(VirtualKeyCode.OEM_PERIOD, new KeyData { DefaultKey = "." , ShiftKey = ">" });
_keyDataDictionary.Add(VirtualKeyCode.OEM_2 , new KeyData { DefaultKey = "/" , ShiftKey = "?" });
_keyDataDictionary.Add(VirtualKeyCode.HANGUL , new KeyData { DefaultKey = "한/영" });
_keyDataDictionary.Add(VirtualKeyCode.SPACE , new KeyData { DefaultKey = "icodebroker" });
_keyDataDictionary.Add(VirtualKeyCode.NUMPAD0, new KeyData { DefaultKey = "0" });
_keyDataDictionary.Add(VirtualKeyCode.NUMPAD1, new KeyData { DefaultKey = "1" });
_keyDataDictionary.Add(VirtualKeyCode.NUMPAD2, new KeyData { DefaultKey = "2" });
_keyDataDictionary.Add(VirtualKeyCode.NUMPAD3, new KeyData { DefaultKey = "3" });
_keyDataDictionary.Add(VirtualKeyCode.NUMPAD4, new KeyData { DefaultKey = "4" });
_keyDataDictionary.Add(VirtualKeyCode.NUMPAD5, new KeyData { DefaultKey = "5" });
_keyDataDictionary.Add(VirtualKeyCode.NUMPAD6, new KeyData { DefaultKey = "6" });
_keyDataDictionary.Add(VirtualKeyCode.NUMPAD7, new KeyData { DefaultKey = "7" });
_keyDataDictionary.Add(VirtualKeyCode.NUMPAD8, new KeyData { DefaultKey = "8" });
_keyDataDictionary.Add(VirtualKeyCode.NUMPAD9, new KeyData { DefaultKey = "9" });
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region 키 업데이트하기 - UpdateKey(shift, capsLock, hangul)
/// <summary>
/// 키 업데이트하기
/// </summary>
/// <param name="shift">SHIFT 키 눌림 여부</param>
/// <param name="capsLock">CAPS LOCK 키 눌림 여부</param>
/// <param name="hangul">한글 키 눌림 여부</param>
public void UpdateKey(bool shift, bool capsLock, bool hangul)
{
if(!_keyDataDictionary.ContainsKey(KeyCode))
{
return;
}
KeyData keyData = _keyDataDictionary[KeyCode];
string key = keyData.DefaultKey;
if(KeyCode >= VirtualKeyCode.VK_A && KeyCode <= VirtualKeyCode.VK_Z)
{
if(hangul)
{
key = keyData.HangulKey;
if
(
shift &&
(
KeyCode == VirtualKeyCode.VK_Q ||
KeyCode == VirtualKeyCode.VK_W ||
KeyCode == VirtualKeyCode.VK_E ||
KeyCode == VirtualKeyCode.VK_R ||
KeyCode == VirtualKeyCode.VK_T ||
KeyCode == VirtualKeyCode.VK_O ||
KeyCode == VirtualKeyCode.VK_P
)
)
{
key = keyData.HangulShiftKey;
}
}
else if(shift && !capsLock)
{
key = key.ToUpper();
}
else if(capsLock && (KeyCode >= VirtualKeyCode.VK_A && KeyCode <= VirtualKeyCode.VK_Z))
{
key = key.ToUpper();
if(shift && capsLock)
{
key = key.ToLower();
}
}
}
else
{
if(!hangul)
{
key = keyData.DefaultKey;
if(shift && !capsLock)
{
key = string.IsNullOrWhiteSpace(keyData.ShiftKey) ? key : keyData.ShiftKey;
}
else if(shift && capsLock)
{
key = string.IsNullOrWhiteSpace(keyData.ShiftKey) ? key : keyData.ShiftKey;
}
}
else if(hangul)
{
if(shift && !capsLock)
{
key = string.IsNullOrWhiteSpace(keyData.ShiftKey) ? key : keyData.ShiftKey;
}
else if(shift && capsLock)
{
key = string.IsNullOrWhiteSpace(keyData.ShiftKey) ? key : keyData.ShiftKey;
}
}
}
Content = key;
}
#endregion
}
}
▶ VirtualKeyboard.cs
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using WindowsInput.Native;
namespace TestProject
{
/// <summary>
/// 가상 키보드
/// </summary>
public class VirtualKeyboard : UserControl
{
//////////////////////////////////////////////////////////////////////////////////////////////////// ROUTED EVENT
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 가상 키 DOWN 이벤트 - VirtualKeyDownEvent
/// <summary>
/// 가상 키 DOWN 이벤트
/// </summary>
public static readonly RoutedEvent VirtualKeyDownEvent = EventManager.RegisterRoutedEvent
(
"VirtualKeyDown",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(VirtualKeyboard)
);
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Dependency Property
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 표시 여부 속성 - IsShowProperty
/// <summary>
/// 표시 여부 속성
/// </summary>
public static readonly DependencyProperty IsShowProperty = DependencyProperty.Register
(
"IsShow",
typeof(bool),
typeof(VirtualKeyboard),
new PropertyMetadata(true, IsShowPropertyChangedCallback)
);
#endregion
#region 전역 사용 여부 속성 - UseGlobalProperty
/// <summary>
/// 전역 사용 여부 속성
/// </summary>
public static readonly DependencyProperty UseGlobalProperty = DependencyProperty.Register
(
"UseGlobal",
typeof(bool),
typeof(VirtualKeyboard),
new PropertyMetadata(true, UseGlobalPropertyChangedCallback)
);
#endregion
#region 후킹 이용 가능 여부 속성 - IsEnableHookProperty
/// <summary>
/// 후킹 이용 가능 여부 속성
/// </summary>
public static readonly DependencyProperty IsEnableHookProperty = DependencyProperty.Register
(
"IsEnableHook",
typeof(bool),
typeof(VirtualKeyboard),
new PropertyMetadata(false, IsEnableHookPropertyChangedCallback)
);
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 키 눌림 여부
/// </summary>
private bool keyPressed;
/// <summary>
/// 이전 키 버튼
/// </summary>
private KeyButton previusKeyButton;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Event
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 가상 키 DOWN 이벤트 - VirtualKeyDown
/// <summary>
/// 가상 키 DOWN 이벤트
/// </summary>
public event RoutedEventHandler VirtualKeyDown
{
add
{
AddHandler(VirtualKeyDownEvent, value);
}
remove
{
RemoveHandler(VirtualKeyDownEvent, value);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 표시 여부 - IsShow
/// <summary>
/// 표시 여부
/// </summary>
public bool IsShow
{
get
{
return (bool)GetValue(IsShowProperty);
}
set
{
SetValue(IsShowProperty, value);
}
}
#endregion
#region 전역 사용 여부 - UseGlobal
/// <summary>
/// 전역 사용 여부
/// </summary>
public bool UseGlobal
{
get
{
return (bool)GetValue(UseGlobalProperty);
}
set
{
SetValue(UseGlobalProperty, value);
}
}
#endregion
#region 후킹 이용 가능 여부 - IsEnableHook
/// <summary>
/// 후킹 이용 가능 여부
/// </summary>
public bool IsEnableHook
{
get
{
return (bool)GetValue(IsEnableHookProperty);
}
set
{
SetValue(IsEnableHookProperty, value);
}
}
#endregion
#region SHIFT 눌림 여부 - IsPressedShift
/// <summary>
/// SHIFT 눌림 여부
/// </summary>
public bool IsPressedShift { get; private set; }
#endregion
#region 한글 눌림 여부 - IsPressedHangul
/// <summary>
/// 한글 눌림 여부
/// </summary>
public bool IsPressedHangul { get; private set; }
#endregion
#region CAPS LOCK 눌림 여부 - IsPressedCapsLock
/// <summary>
/// CAPS LOCK 눌림 여부
/// </summary>
public bool IsPressedCapsLock { get; private set; }
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region 표시 여부 속성 변경시 콜백 처리하기 - IsShowPropertyChangedCallback(d, e)
/// <summary>
/// 표시 여부 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void IsShowPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
VirtualKeyboard keyboard = d as VirtualKeyboard;
bool isShow = (bool)e.NewValue;
keyboard.ChangeShow(isShow);
}
#endregion
#region 전역 사용 여부 속성 변경시 콜백 처리하기 - UseGlobalPropertyChangedCallback(d, e)
/// <summary>
/// 전역 사용 여부 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void UseGlobalPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
HookingHelper.UseGlobal = (bool)e.NewValue;
}
#endregion
#region 후킹 이용 가능 여부 속성 변경시 콜백 처리하기 - IsEnableHookPropertyChangedCallback(d, e)
/// <summary>
/// 후킹 이용 가능 여부 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void IsEnableHookPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
VirtualKeyboard virtualKeyboard = d as VirtualKeyboard;
if((bool)e.NewValue)
{
virtualKeyboard.UpdateHookData();
HookingHelper.UseGlobal = virtualKeyboard.UseGlobal;
HookingHelper.MouseClick += virtualKeyboard.Hook_MouseClick;
HookingHelper.KeyClick += virtualKeyboard.Hook_KeyClick;
HookingHelper.Start();
}
else
{
HookingHelper.MouseClick -= virtualKeyboard.Hook_MouseClick;
HookingHelper.KeyClick -= virtualKeyboard.Hook_KeyClick;
HookingHelper.Stop();
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - VirtualKeyboard()
/// <summary>
/// 생성자
/// </summary>
public VirtualKeyboard()
{
Loaded += UserControl_Loaded;
Unloaded += UserControl_Unloaded;
IsVisibleChanged += UserControl_IsVisibleChanged;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Protected
#region 키 업데이트하기 - UpdateKeys(panel)
/// <summary>
/// 키 업데이트하기
/// </summary>
/// <param name="panel">패널</param>
protected void UpdateKeys(Panel panel)
{
foreach(UIElement child in panel.Children)
{
if(child is Panel)
{
Panel content = child as Panel;
UpdateKeys(content);
}
else if(child is KeyButton)
{
KeyButton keyButton = child as KeyButton;
keyButton.UpdateKey(IsPressedShift, IsPressedCapsLock, IsPressedHangul);
}
}
}
#endregion
#region 키 업데이트하기 - UpdateKeys()
/// <summary>
/// 키 업데이트하기
/// </summary>
protected void UpdateKeys()
{
Panel content = Content as Panel;
UpdateKeys(content);
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
//////////////////////////////////////////////////////////////////////////////// Event
#region 사용자 컨트롤 로드시 처리하기 - UserControl_Loaded(sender, e)
/// <summary>
/// 사용자 컨트롤 로드시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
if(DesignerProperties.GetIsInDesignMode(this))
{
return;
}
RenderTransform = new TranslateTransform();
AddHandler(KeyButton.ClickEvent, (RoutedEventHandler)KeyButton_Click);
if(IsEnableHook)
{
UpdateHookData();
HookingHelper.KeyClick += Hook_KeyClick;
HookingHelper.UseGlobal = UseGlobal;
HookingHelper.Start();
}
Application.Current.MainWindow.Closed += (sender2, e2) => HookingHelper.Stop();
}
#endregion
#region 사용자 컨트롤 언로드시 처리하기 - UserControl_Unloaded(sender, e)
/// <summary>
/// 사용자 컨트롤 언로드시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
{
HookingHelper.MouseClick -= Hook_MouseClick;
HookingHelper.KeyClick -= Hook_KeyClick;
}
#endregion
#region 사용자 컨트롤 표시 여부 변경시 처리하기 - UserControl_IsVisibleChanged(sender, e)
/// <summary>
/// 사용자 컨트롤 표시 여부 변경시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void UserControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
IsPressedHangul = true;
if((bool)e.NewValue)
{
if(IsEnableHook)
{
IsPressedHangul = !Simulator.Input.InputDeviceState.IsTogglingKeyInEffect(VirtualKeyCode.HANGUL );
IsPressedCapsLock = Simulator.Input.InputDeviceState.IsTogglingKeyInEffect(VirtualKeyCode.CAPITAL);
UpdateHookData();
}
UpdateKeys();
}
}
#endregion
#region 후킹 마우스 클릭시 처리하기 - Hook_MouseClick(point, message)
/// <summary>
/// 후킹 마우스 클릭시 처리하기
/// </summary>
/// <param name="point">포인트</param>
/// <param name="message">메시지</param>
private void Hook_MouseClick(POINT point, MouseMessage message)
{
Point screenPoint = PointFromScreen(new Point(point.X, point.Y));
KeyButton keyButton = VisualElementHelper.TryFindFromPoint<KeyButton>(this, screenPoint);
if(keyButton == null)
{
return;
}
VirtualKeyCode keyCode = keyButton.KeyCode;
if(message == MouseMessage.WM_LBUTTONDOWN)
{
this.previusKeyButton = keyButton;
keyButton.IsPressed = true;
if(keyButton.ClickMode == ClickMode.Press)
{
keyButton.RaiseEvent(new RoutedEventArgs(KeyButton.ClickEvent));
}
}
else if(message == MouseMessage.WM_LBUTTONUP)
{
if(keyCode != VirtualKeyCode.CAPITAL && keyCode != VirtualKeyCode.SHIFT)
{
if(this.previusKeyButton != null)
{
this.previusKeyButton.IsPressed = false;
this.previusKeyButton = null;
}
keyButton.IsPressed = false;
}
if(keyButton.ClickMode == ClickMode.Release)
{
keyButton.RaiseEvent(new RoutedEventArgs(KeyButton.ClickEvent));
}
}
}
#endregion
#region 후킹 키 클릭시 처리하기 - Hook_KeyClick(keyCode)
/// <summary>
/// 후킹 키 클릭시 처리하기
/// </summary>
/// <param name="keyCode">키 코드</param>
private void Hook_KeyClick(uint keyCode)
{
if(this.keyPressed)
{
return;
}
switch((VirtualKeyCode)keyCode)
{
case VirtualKeyCode.HANGUL :
IsPressedHangul = !Simulator.Input.InputDeviceState.IsTogglingKeyInEffect(VirtualKeyCode.HANGUL);
break;
case VirtualKeyCode.CAPITAL :
IsPressedCapsLock = !Simulator.Input.InputDeviceState.IsTogglingKeyInEffect(VirtualKeyCode.CAPITAL);
break;
case VirtualKeyCode.LSHIFT :
case VirtualKeyCode.RSHIFT :
IsPressedShift = !Simulator.Input.InputDeviceState.IsTogglingKeyInEffect(VirtualKeyCode.SHIFT);
break;
}
if(IsShow || Visibility == Visibility.Visible)
{
UpdateKeys();
}
}
#endregion
#region 키 버튼 클릭시 처리하기 - KeyButton_Click(sender, e)
/// <summary>
/// 키 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void KeyButton_Click(object sender, RoutedEventArgs e)
{
KeyButton keyButton = e.OriginalSource as KeyButton;
if(keyButton == null || (IsEnableHook && keyButton.IsStylusCaptured))
{
return;
}
this.keyPressed = true;
if(keyButton.KeyCode == VirtualKeyCode.CAPITAL)
{
IsPressedCapsLock = !IsPressedCapsLock;
Simulator.Keyboard.KeyPress(keyButton.KeyCode);
}
else if(keyButton.KeyCode == VirtualKeyCode.SHIFT)
{
IsPressedShift = !IsPressedShift;
if(IsPressedShift)
{
Simulator.Keyboard.KeyDown(keyButton.KeyCode);
}
else
{
Simulator.Keyboard.KeyUp(keyButton.KeyCode);
}
}
else if(keyButton.KeyCode == VirtualKeyCode.HANGUL)
{
IsPressedHangul = !IsPressedHangul;
Simulator.Keyboard.KeyPress(keyButton.KeyCode);
}
else
{
if(keyButton.KeyCode == VirtualKeyCode.RETURN)
{
if(Keyboard.FocusedElement is TextBox)
{
TextBox textBox = Keyboard.FocusedElement as TextBox;
BindingExpression expression = textBox.GetBindingExpression(TextBox.TextProperty);
expression?.UpdateSource();
}
}
if(IsPressedShift)
{
IsPressedShift = false;
Simulator.Keyboard.KeyPress(keyButton.KeyCode);
Simulator.Keyboard.KeyUp(VirtualKeyCode.SHIFT);
}
else
{
Simulator.Keyboard.KeyPress(keyButton.KeyCode);
}
}
UpdateKeys();
RaiseEvent(new RoutedEventArgs(VirtualKeyDownEvent, keyButton.KeyCode));
this.keyPressed = false;
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Function
#region 후킹 데이터 업데이트하기 - UpdateHookData()
/// <summary>
/// 후킹 데이터 업데이트하기
/// </summary>
private void UpdateHookData()
{
FrameworkElement content = Content as FrameworkElement;
if(content == null)
{
return;
}
Rect area = VisualTreeHelper.GetDescendantBounds(content);
if(!area.IsEmpty)
{
HookingHelper.HookArea = area;
HookingHelper.HookElement = this;
}
}
#endregion
#region 표시 여부 변경하기 - ChangeShow(isShow)
/// <summary>
/// 표시 여부 변경하기
/// </summary>
/// <param name="isShow">표시 여부</param>
private void ChangeShow(bool isShow)
{
Vector offset = VisualTreeHelper.GetOffset(this);
Storyboard storyboard = new Storyboard();
double to = isShow ? 0 : ActualHeight + offset.Y;
DoubleAnimation doubleAnimation = new DoubleAnimation(to, new Duration(TimeSpan.FromSeconds(0.35)));
doubleAnimation.EasingFunction = new QuinticEase { EasingMode = EasingMode.EaseInOut };
storyboard.Children.Add(doubleAnimation);
Storyboard.SetTargetProperty
(
storyboard,
new PropertyPath
(
"(0).(1)",
new DependencyProperty[] { UIElement.RenderTransformProperty, TranslateTransform.YProperty }
)
);
BeginStoryboard(storyboard, HandoffBehavior.SnapshotAndReplace);
}
#endregion
}
}
▶ VirtualKeyboardControl.xaml
<local:VirtualKeyboard x:Class="TestProject.VirtualKeyboardControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestProject">
<local:VirtualKeyboard.Resources>
<Style TargetType="{x:Type local:KeyButton}">
<Setter Property="Margin" Value="1" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Background" Value="RoyalBlue" />
<Setter Property="Padding" Value="1" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="22" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="0.00000000001" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:KeyButton}">
<Border Name="border"
Margin="1"
CornerRadius="3"
Padding="1 0"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<ContentPresenter Name="contentPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
Content="{TemplateBinding Content}"
Focusable="False"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="#f1685e" />
<Setter TargetName="border" Property="Background" Value="#f1685e" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="#f1685e" />
<Setter TargetName="border" Property="Background" Value="#f1685e" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</local:VirtualKeyboard.Resources>
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<local:KeyButton KeyCode="OEM_3" Grid.Column="0" />
<local:KeyButton KeyCode="VK_1" Grid.Column="1" />
<local:KeyButton KeyCode="VK_2" Grid.Column="2" />
<local:KeyButton KeyCode="VK_3" Grid.Column="3" />
<local:KeyButton KeyCode="VK_4" Grid.Column="4" />
<local:KeyButton KeyCode="VK_5" Grid.Column="5" />
<local:KeyButton KeyCode="VK_6" Grid.Column="6" />
<local:KeyButton KeyCode="VK_7" Grid.Column="7" />
<local:KeyButton KeyCode="VK_8" Grid.Column="8" />
<local:KeyButton KeyCode="VK_9" Grid.Column="9" />
<local:KeyButton KeyCode="VK_0" Grid.Column="10" />
<local:KeyButton KeyCode="OEM_MINUS" Grid.Column="11" />
<local:KeyButton KeyCode="OEM_PLUS" Grid.Column="12" />
<local:KeyButton KeyCode="BACK" Grid.Column="13" FontSize="18" />
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions >
<ColumnDefinition Width="1.8*" />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition Width="1.8*" />
</Grid.ColumnDefinitions>
<local:KeyButton KeyCode="TAB" Grid.Column="0" FontSize="18" />
<local:KeyButton KeyCode="VK_Q" Grid.Column="1" />
<local:KeyButton KeyCode="VK_W" Grid.Column="2" />
<local:KeyButton KeyCode="VK_E" Grid.Column="3" />
<local:KeyButton KeyCode="VK_R" Grid.Column="4" />
<local:KeyButton KeyCode="VK_T" Grid.Column="5" />
<local:KeyButton KeyCode="VK_Y" Grid.Column="6" />
<local:KeyButton KeyCode="VK_U" Grid.Column="7" />
<local:KeyButton KeyCode="VK_I" Grid.Column="8" />
<local:KeyButton KeyCode="VK_O" Grid.Column="9" />
<local:KeyButton KeyCode="VK_P" Grid.Column="10" />
<local:KeyButton KeyCode="OEM_4" Grid.Column="11" />
<local:KeyButton KeyCode="OEM_6" Grid.Column="12" />
<local:KeyButton KeyCode="OEM_5" Grid.Column="13" />
</Grid>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<local:KeyButton KeyCode="CAPITAL" Grid.Column="0" FontSize="18" />
<local:KeyButton KeyCode="VK_A" Grid.Column="1" />
<local:KeyButton KeyCode="VK_S" Grid.Column="2" />
<local:KeyButton KeyCode="VK_D" Grid.Column="3" />
<local:KeyButton KeyCode="VK_F" Grid.Column="4" />
<local:KeyButton KeyCode="VK_G" Grid.Column="5" />
<local:KeyButton KeyCode="VK_H" Grid.Column="6" />
<local:KeyButton KeyCode="VK_J" Grid.Column="7" />
<local:KeyButton KeyCode="VK_K" Grid.Column="8" />
<local:KeyButton KeyCode="VK_L" Grid.Column="9" />
<local:KeyButton KeyCode="OEM_1" Grid.Column="10" />
<local:KeyButton KeyCode="OEM_7" Grid.Column="11" />
<local:KeyButton KeyCode="RETURN" Grid.Column="12" FontSize="18" />
</Grid>
<Grid Grid.Row="3">
<Grid.ColumnDefinitions >
<ColumnDefinition Width="2.2*" />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition Width="2.2*" />
</Grid.ColumnDefinitions>
<local:KeyButton KeyCode="SHIFT" Grid.Column="0" FontSize="18" />
<local:KeyButton KeyCode="VK_Z" Grid.Column="1" />
<local:KeyButton KeyCode="VK_X" Grid.Column="2" />
<local:KeyButton KeyCode="VK_C" Grid.Column="3" />
<local:KeyButton KeyCode="VK_V" Grid.Column="4" />
<local:KeyButton KeyCode="VK_B" Grid.Column="5" />
<local:KeyButton KeyCode="VK_N" Grid.Column="6" />
<local:KeyButton KeyCode="VK_M" Grid.Column="7" />
<local:KeyButton KeyCode="OEM_COMMA" Grid.Column="8" />
<local:KeyButton KeyCode="OEM_PERIOD" Grid.Column="9" />
<local:KeyButton KeyCode="OEM_2" Grid.Column="10" />
<local:KeyButton KeyCode="SHIFT" Grid.Column="11" FontSize="18" />
</Grid>
<Grid Grid.Row="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6*" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<local:KeyButton KeyCode="SPACE" Grid.Column="0" FontSize="18" />
<local:KeyButton KeyCode="HANGEUL" Grid.Column="1" FontSize="18" />
</Grid>
</Grid>
</local:VirtualKeyboard>
▶ VirtualKeyboardControl.xaml.CS
namespace TestProject
{
/// <summary>
/// 가상 키보드 컨트롤
/// </summary>
public partial class VirtualKeyboardControl : VirtualKeyboard
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - VirtualKeyboardControl()
/// <summary>
/// 생성자
/// </summary>
public VirtualKeyboardControl()
{
InitializeComponent();
IsEnableHook = false;
}
#endregion
}
}
▶ MainWindow.xaml
<Window x:Class="TestProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestProject"
Width="800"
Height="600"
Title="가상 키보드 사용하기"
FontFamily="나눔고딕코딩"
FontSize="16">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Name="inputTextBox" Grid.Row="0"
Height="200"
InputMethod.PreferredImeState="On"
InputMethod.PreferredImeConversionMode="Native" />
<local:VirtualKeyboardControl Grid.Row="1"
Margin="0 10 0 0"
IsShow="True" />
</Grid>
</Window>
▶ MainWindow.xaml.cs
using System.Windows;
namespace TestProject
{
/// <summary>
/// 메인 윈도우
/// </summary>
public partial class MainWindow : Window
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainWindow()
/// <summary>
/// 생성자
/// </summary>
public MainWindow()
{
InitializeComponent();
this.inputTextBox.Focus();
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] ScrollViewer 클래스 : 애니메이션 스크롤 뷰어 사용하기 (0) | 2021.04.28 |
---|---|
[C#/WPF] UWP API 사용하기 (0) | 2021.04.26 |
[C#/WPF] TOTP(Time-based One-Time Password) 사용하기 (0) | 2021.04.26 |
[C#/WPF] Dispatcher 클래스 : Invoke 메소드를 사용해 UI 업데이트 하기 (0) | 2021.04.22 |
[C#/WPF] 관리자 권한으로 실행하기 (0) | 2021.04.03 |
[C#/WPF] HTML을 XAML로 변환하기 (0) | 2021.03.20 |
[C#/WPF] LogicalTreeHelper 클래스 : GetChildren 정적 메소드를 사용해 논리적 자식 열거 가능형 구하기 (0) | 2021.03.20 |
[C#/WPF] ListBox 엘리먼트 : 마우스 진입시 애니메이션 사용하기 (0) | 2021.03.07 |
[C#/WPF] ListBox 클래스 : 항목 선택시 슬라이딩 리스트 박스 사용하기 (0) | 2021.03.07 |
[C#/WPF] 누겟 설치 : VirtualDesktop.WPF (0) | 2021.03.06 |
댓글을 달아 주세요