forked from amdf/NativeShell
-
Notifications
You must be signed in to change notification settings - Fork 0
/
input.c
335 lines (293 loc) · 7.83 KB
/
input.c
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/*++
Copyright (c) Alex Ionescu. All rights reserved.
Copyright (c) 2011 amdf.
Copyright (c) 2021 Cacodemon345.
THIS CODE AND INFORMATION IS PROVIDED UNDER THE LESSER GNU PUBLIC LICENSE.
PLEASE READ THE FILE "COPYING" IN THE TOP LEVEL DIRECTORY.
Module Name:
input.c
Abstract:
The Native Command Line Interface (NCLI) is the command shell for the
TinyKRNL OS.
This module deals with device input (such as mouse or keyboard).
Environment:
Native mode
Revision History:
Alex Ionescu - Started Implementation - 01-Mar-06
Alex Ionescu - Reworked architecture - 23-Mar-06
amdf - Added correct scancode translation in RtlCliGetChar - 20-Feb-11
Cacodemon345 - Fix backspace behaviour on Windows 8 and later - 23-Jul-21
--*/
#include "precomp.h"
//
// FIXME: Temporary here
//
NTSTATUS
RtlClipBackspace(
VOID
);
//
// Event to wait on for keyboard input
//
HANDLE hEvent;
//
// Raw keyboard character buffer
//
//KEYBOARD_INPUT_DATA CurrentCharBuffer[20];
ULONG CurrentChar = 0;
//
// Input buffer
//
CHAR Line[1024];
CHAR CurrentPosition = 0;
/*++
* @name RtlCliOpenInputDevice
*
* The RtlCliOpenInputDevice routine opens an input device.
*
* @param Handle
* Pointer where the handle for the input device will be returned.
*
* @param Type
* Type of the input device to use.
*
* @return STATUS_SUCCESS or error code when attemping to open the device.
*
* @remarks This routine supports both mouse and keyboard input devices.
*
*--*/
NTSTATUS
RtlCliOpenInputDevice(OUT PHANDLE Handle,
IN CON_DEVICE_TYPE Type)
{
UNICODE_STRING Driver;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK Iosb;
HANDLE hDriver;
NTSTATUS Status;
//
// Chose the driver to use
// FIXME: Support MouseType later
// FIXME: Don't hardcode keyboard path
//
if (Type == KeyboardType)
{
RtlInitUnicodeString(&Driver, L"\\Device\\KeyboardClass0");
}
//
// Initialize the object attributes
//
InitializeObjectAttributes(&ObjectAttributes,
&Driver,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
//
// Open a handle to it
//
Status = NtCreateFile(&hDriver,
SYNCHRONIZE | GENERIC_READ | FILE_READ_ATTRIBUTES,
&ObjectAttributes,
&Iosb,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN,
FILE_DIRECTORY_FILE,
NULL,
0);
//
// Now create an event that will be used to wait on the device
//
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
Status = NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, &ObjectAttributes, 1, 0);
//
// Return the handle
//
*Handle = hDriver;
return Status;
}
/*++
* @name RtlClipWaitForInput
*
* The RtlClipWaitForInput routine waits for input from an input device.
*
* @param hDriver
* Handle of the driver/device to get input from.
*
* @param Buffer
* Input buffer.
*
* @param BufferSize
* Size of the input buffer.
*
* @return STATUS_SUCCESS or error code from the read operation.
*
* @remarks This routine waits for input to be available.
*
*--*/
NTSTATUS
RtlClipWaitForInput(IN HANDLE hDriver,
IN PVOID Buffer,
IN OUT PULONG BufferSize)
{
IO_STATUS_BLOCK Iosb;
LARGE_INTEGER ByteOffset;
NTSTATUS Status;
//
// Clean up the I/O Status block and read from byte 0
//
RtlZeroMemory(&Iosb, sizeof(Iosb));
RtlZeroMemory(&ByteOffset, sizeof(ByteOffset));
//
// Try to read the data
//
Status = NtReadFile(hDriver,
hEvent,
NULL,
NULL,
&Iosb,
Buffer,
*BufferSize,
&ByteOffset,
NULL);
//
// Check if data is pending
//
if (Status == STATUS_PENDING)
{
//
// Wait on the data to be read
//
Status = NtWaitForSingleObject(hEvent, TRUE, NULL);
}
//
// Return status and how much data was read
//
*BufferSize = (ULONG)Iosb.Information;
return Status;
}
/*++
* @name RtlCliGetChar
*
* The RtlCliGetChar routine FILLMEIN
*
* @param hDriver
* FILLMEIN
*
* @return CHAR
*
* @remarks Documentation for this routine needs to be completed.
*
*--*/
CHAR
RtlCliGetChar(IN HANDLE hDriver)
{
KEYBOARD_INPUT_DATA KeyboardData;
KBD_RECORD kbd_rec;
ULONG BufferLength = sizeof(KEYBOARD_INPUT_DATA);
RtlClipWaitForInput(hDriver, &KeyboardData, &BufferLength);
IntTranslateKey(&KeyboardData, &kbd_rec);
if (!kbd_rec.bKeyDown)
{
return (-1);
}
return kbd_rec.AsciiChar;
}
/*++
* @name RtlCliGetLine
*
* The RtlCliGetLine routine FILLMEIN
*
* @param hDriver
* FILLMEIN
*
* @return PCHAR
*
* @remarks Because we don't currently have a thread to display on screen
* whatever is typed, we handle this in the same thread and display
* a character only if someone is actually waiting for it. This
* will be changed later.
*/
PCHAR
RtlCliGetLine(IN HANDLE hDriver)
{
CHAR Char;
BOOLEAN First = FALSE;
//memset(Line, 0x00, 1024);
//
// Wait for a new character
//
while (TRUE)
{
//
// Get the character that was pressed
//
Char = RtlCliGetChar(hDriver);
//
// Check if this was ENTER
//
if (Char == '\r')
{
//
// First, null-terminate the line buffer
//
Line[CurrentPosition] = ANSI_NULL;
CurrentPosition = 0;
//
// Return it
//
return Line;
}
else if (Char == '\b')
{
//
// Make sure we don't back-space beyond the limit
//
if (CurrentPosition)
{
// This was a backspace. NtDisplayString does not handle this, so
// we unfortunately have to rely on a hack. First we erase the
// entire line.
//
RtlCliPutChar('\r');
//
// Now we have to call in the display subsystem to redisplay the
// current text buffer. (NOT the current line input buffer!)
//
// caco345: This needs to be done two times to make the
// character disappear properly on Windows 8+ as '\r' does not
// actually erase the entire line and only puts the position at
// the start of the line on it and later.
//
RtlClipBackspace();
RtlCliPutChar(' ');
RtlCliPutChar('\r');
RtlClipBackspace();
//
// Now we do the only thing we're supposed to do, which is to
// remove a character in the command buffer as well.
//
CurrentPosition--;
}
//
// Continue listening for chars.
//
continue;
}
//
// We got another character. Make sure it's not NULL.
//
if (!Char || Char == -1) continue;
//
// Add it to our line buffer
//
Line[CurrentPosition] = Char;
CurrentPosition++;
//
// Again, as noted earlier, we combine input with display in a very
// unholy way, so we also have to display it on screen.
//
RtlCliPutChar(Char);
}
}