-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathKeyboardHook.cs
More file actions
180 lines (144 loc) · 6.13 KB
/
KeyboardHook.cs
File metadata and controls
180 lines (144 loc) · 6.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//Code sample: Using Windows low-level keyboard hook to intercept key events and print them into console,
// taking into account shift/caps state and keyboard layout
//
//Author: MSDN-WhiteKnight (https://github.com/MSDN-WhiteKnight)
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Windows.Forms;
namespace KeyboardHookSample
{
class Program
{
static KeyLogger k;
static void Main(string[] args)
{
k = new KeyLogger();
k.Start();
Console.CancelKeyPress += Console_CancelKeyPress;
Console.WriteLine("Started listening for keyboard events...");
Application.Run();
}
private static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
k.Stop();
Application.Exit();
}
}
sealed class KeyLogger : IDisposable //отслеживает события клавиатуры с помощью низкоуровневого хука Windows
{
//объявления типов, констант и функций Windows API
delegate IntPtr KeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
const int WH_KEYBOARD_LL = 13;
const int HC_ACTION = 0;
const int WM_KEYDOWN = 0x0100;
const uint VK_CAPITAL = 0x14;
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
static extern IntPtr SetWindowsHookEx(int idHook, KeyboardProc lpfn, IntPtr hInstance, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("USER32.dll")]
public static extern short GetKeyState(int vKey);
[DllImport("user32.dll")]
public static extern short GetAsyncKeyState(int vKey);
[DllImport("user32.dll")]
public static extern int ToUnicodeEx(
uint wVirtKey,
uint wScanCode,
byte[] lpKeyState,
[Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszBuff,
int cchBuff,
uint wFlags,
IntPtr dwhkl);
[DllImport("user32.dll")]
public static extern bool GetKeyboardState(byte[] lpKeyState);
[DllImport("user32.dll")]
public static extern uint MapVirtualKey(
uint uCode,
uint uMapType);
[DllImport("user32.dll")]
public static extern IntPtr GetKeyboardLayout(uint idThread);
[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
//преобразование виртуального кода клавиши в его Юникод-представление
public static string VKCodeToUnicode(uint vkCode)
{
StringBuilder buf = new StringBuilder();
byte[] keyboardState = new byte[255];
short x;
byte y;
for (int i = 0; i < 255; i++)
{
if (i == VK_CAPITAL)
{
x = GetKeyState(i);
}
else
{
x = GetAsyncKeyState(i);
}
y = 0;
if ((x & 0x8000) != 0) y = (byte)(y | 0x80);
if ((x & 0x0001) != 0) y = (byte)(y | 0x01);
keyboardState[i] = y;
}
ToUnicodeEx(vkCode, MapVirtualKey(vkCode, 0), keyboardState, buf, 5, 0,
GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero)));
return buf.ToString();
}
IntPtr _hookID = IntPtr.Zero;
//начинает отслеживание событий клавиатуры
public void Start()
{
if (disposed) throw new ObjectDisposedException("KeyLogger");
if (_hookID != IntPtr.Zero) return;
_hookID = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookCallback, IntPtr.Zero, 0);
if (_hookID == IntPtr.Zero)
{
int error = Marshal.GetLastWin32Error();
throw new Win32Exception(error, "Failed to install hook! Error: "+ error.ToString());
}
}
//останавливает отслеживание событий клавиатуры
public void Stop()
{
if (disposed) return;
if (_hookID == IntPtr.Zero) return;
UnhookWindowsHookEx(_hookID);
_hookID = IntPtr.Zero;
}
//вызывается Windows при нажатии клавиши
IntPtr KeyboardHookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
string s = VKCodeToUnicode((uint)vkCode);
Console.Out.WriteLine("Key: " + ((Keys)vkCode).ToString() + "; Character: " + s);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
//так как KeyLogger использует неуправляемый ресурс, реализуем Dispose и Finalize...
bool disposed = false;
public void Dispose()
{
if (disposed) return;
Stop();
disposed = true;
GC.SuppressFinalize(this);
}
~KeyLogger()
{
Dispose();
}
}
}