ReactOS 0.4.16-dev-340-g0540c21
lineinput.c
Go to the documentation of this file.
1/*
2 * LICENSE: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/lineinput.c
5 * PURPOSE: Console line input functions
6 * PROGRAMMERS: Jeffrey Morlan
7 */
8
9/* INCLUDES *******************************************************************/
10
11#include "consrv.h"
12#include "history.h"
13#include "popup.h"
14
15#define NDEBUG
16#include <debug.h>
17
18
22 USHORT SourceLength,
23 // BOOLEAN IsUnicode,
25 PUSHORT TargetLength);
29 USHORT SourceLength,
30 // BOOLEAN IsAnsi,
31 PCHAR/* * */ Target,
32 /*P*/USHORT TargetLength);
33
34
35/* PRIVATE FUNCTIONS **********************************************************/
36
37static VOID
39 UINT Pos)
40{
42 {
44 SHORT OldCursorX = Buffer->CursorPosition.X;
45 SHORT OldCursorY = Buffer->CursorPosition.Y;
46 INT XY = OldCursorY * Buffer->ScreenBufferSize.X + OldCursorX;
47
48 XY += (Pos - Console->LinePos);
49 if (XY < 0)
50 XY = 0;
51 else if (XY >= Buffer->ScreenBufferSize.Y * Buffer->ScreenBufferSize.X)
52 XY = Buffer->ScreenBufferSize.Y * Buffer->ScreenBufferSize.X - 1;
53
54 Buffer->CursorPosition.X = XY % Buffer->ScreenBufferSize.X;
55 Buffer->CursorPosition.Y = XY / Buffer->ScreenBufferSize.X;
56 TermSetScreenInfo(Console, Buffer, OldCursorX, OldCursorY);
57 }
58
59 Console->LinePos = Pos;
60}
61
62static VOID
64 UINT NumToDelete,
65 UINT NumToInsert,
66 PWCHAR Insertion)
67{
68 PTEXTMODE_SCREEN_BUFFER ActiveBuffer;
69 UINT Pos = Console->LinePos;
70 UINT NewSize = Console->LineSize - NumToDelete + NumToInsert;
71 UINT i;
72
73 if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER) return;
74 ActiveBuffer = (PTEXTMODE_SCREEN_BUFFER)Console->ActiveBuffer;
75
76 /* Make sure there is always enough room for ending \r\n */
77 if (NewSize + 2 > Console->LineMaxSize)
78 return;
79
80 memmove(&Console->LineBuffer[Pos + NumToInsert],
81 &Console->LineBuffer[Pos + NumToDelete],
82 (Console->LineSize - (Pos + NumToDelete)) * sizeof(WCHAR));
83 memcpy(&Console->LineBuffer[Pos], Insertion, NumToInsert * sizeof(WCHAR));
84
86 {
87 if (Pos < NewSize)
88 {
89 TermWriteStream(Console, ActiveBuffer,
90 &Console->LineBuffer[Pos],
91 NewSize - Pos,
92 TRUE);
93 }
94 for (i = NewSize; i < Console->LineSize; ++i)
95 {
96 TermWriteStream(Console, ActiveBuffer, L" ", 1, TRUE);
97 }
98 Console->LinePos = i;
99 }
100
101 Console->LineSize = NewSize;
102 LineInputSetPos(Console, Pos + NumToInsert);
103}
104
105static VOID
107 PUNICODE_STRING ExeName,
108 INT Offset)
109{
110#if 0
112 UINT Position = 0;
113
114 if (!Hist || Hist->NumEntries == 0) return;
115
116 Position = Hist->Position + Offset;
117 Position = min(max(Position, 0), Hist->NumEntries - 1);
118 Hist->Position = Position;
119
121 LineInputEdit(Console, Console->LineSize,
122 Hist->Entries[Hist->Position].Length / sizeof(WCHAR),
123 Hist->Entries[Hist->Position].Buffer);
124
125#else
126
128
129 if (!HistoryRecallHistory(Console, ExeName, Offset, &Entry)) return;
130
132 LineInputEdit(Console, Console->LineSize,
133 Entry.Length / sizeof(WCHAR),
134 Entry.Buffer);
135#endif
136}
137
138
139// TESTS!!
141
144 PUNICODE_STRING ExeName);
145
146VOID
148 PUNICODE_STRING ExeName,
149 KEY_EVENT_RECORD *KeyEvent)
150{
151 UINT Pos = Console->LinePos;
153
154 /*
155 * First, deal with control keys...
156 */
157
158 switch (KeyEvent->wVirtualKeyCode)
159 {
160 case VK_ESCAPE:
161 {
162 /* Clear the entire line */
164 LineInputEdit(Console, Console->LineSize, 0, NULL);
165
166 // TESTS!!
167 if (Popup)
168 {
170 Popup = NULL;
171 }
172 return;
173 }
174
175 case VK_HOME:
176 {
177 /* Move to start of line. With CTRL, erase everything left of cursor. */
181 return;
182 }
183
184 case VK_END:
185 {
186 /* Move to end of line. With CTRL, erase everything right of cursor. */
188 LineInputEdit(Console, Console->LineSize - Pos, 0, NULL);
189 else
190 LineInputSetPos(Console, Console->LineSize);
191 return;
192 }
193
194 case VK_LEFT:
195 {
196 /* Move to the left. With CTRL, move to beginning of previous word. */
198 {
199 while (Pos > 0 && Console->LineBuffer[Pos - 1] == L' ') Pos--;
200 while (Pos > 0 && Console->LineBuffer[Pos - 1] != L' ') Pos--;
201 }
202 else
203 {
204 Pos -= (Pos > 0);
205 }
207 return;
208 }
209
210 case VK_RIGHT:
211 case VK_F1:
212 {
213 /* Move to the right. With CTRL, move to beginning of next word. */
215 {
216 while (Pos < Console->LineSize && Console->LineBuffer[Pos] != L' ') Pos++;
217 while (Pos < Console->LineSize && Console->LineBuffer[Pos] == L' ') Pos++;
219 }
220 else
221 {
222 /* Recall one character (but don't overwrite current line) */
224 if (Pos < Console->LineSize)
226 else if (Pos * sizeof(WCHAR) < Entry.Length)
227 LineInputEdit(Console, 0, 1, &Entry.Buffer[Pos]);
228 }
229 return;
230 }
231
232 case VK_INSERT:
233 {
234 /* Toggle between insert and overstrike */
235 Console->LineInsertToggle = !Console->LineInsertToggle;
236 TermSetCursorInfo(Console, Console->ActiveBuffer);
237 return;
238 }
239
240 case VK_DELETE:
241 {
242 /* Remove one character to right of cursor */
243 if (Pos != Console->LineSize)
244 LineInputEdit(Console, 1, 0, NULL);
245 return;
246 }
247
248 case VK_PRIOR:
249 {
250 /* Recall the first history entry */
251 LineInputRecallHistory(Console, ExeName, -((WORD)-1));
252 return;
253 }
254
255 case VK_NEXT:
256 {
257 /* Recall the last history entry */
258 LineInputRecallHistory(Console, ExeName, +((WORD)-1));
259 return;
260 }
261
262 case VK_UP:
263 case VK_F5:
264 {
265 /*
266 * Recall the previous history entry. On first time, actually recall
267 * the current (usually last) entry; on subsequent times go back.
268 */
269 LineInputRecallHistory(Console, ExeName, Console->LineUpPressed ? -1 : 0);
270 Console->LineUpPressed = TRUE;
271 return;
272 }
273
274 case VK_DOWN:
275 {
276 /* Recall the next history entry */
277 LineInputRecallHistory(Console, ExeName, +1);
278 return;
279 }
280
281 case VK_F3:
282 {
283 /* Recall the remainder of the current history entry */
285 if (Pos * sizeof(WCHAR) < Entry.Length)
286 {
287 UINT InsertSize = (Entry.Length / sizeof(WCHAR) - Pos);
288 UINT DeleteSize = min(Console->LineSize - Pos, InsertSize);
289 LineInputEdit(Console, DeleteSize, InsertSize, &Entry.Buffer[Pos]);
290 }
291 return;
292 }
293
294 case VK_F6:
295 {
296 /* Insert a ^Z character */
297 KeyEvent->uChar.UnicodeChar = 26;
298 break;
299 }
300
301 case VK_F7:
302 {
304 {
306 }
307 else
308 {
311 }
312 return;
313 }
314
315 case VK_F8:
316 {
317 UNICODE_STRING EntryFound;
318
319 Entry.Length = Console->LinePos * sizeof(WCHAR); // == Pos * sizeof(WCHAR)
320 Entry.Buffer = Console->LineBuffer;
321
322 if (HistoryFindEntryByPrefix(Console, ExeName, &Entry, &EntryFound))
323 {
324 LineInputEdit(Console, Console->LineSize - Pos,
325 EntryFound.Length / sizeof(WCHAR) - Pos,
326 &EntryFound.Buffer[Pos]);
327 /* Cursor stays where it was */
329 }
330
331 return;
332 }
333#if 0
334 {
335 PHISTORY_BUFFER Hist;
336 INT HistPos;
337
338 /* Search for history entries starting with input */
339 Hist = HistoryCurrentBuffer(Console, ExeName);
340 if (!Hist || Hist->NumEntries == 0) return;
341
342 /*
343 * Like Up/F5, on first time start from current (usually last) entry,
344 * but on subsequent times start at previous entry.
345 */
346 if (Console->LineUpPressed)
347 Hist->Position = (Hist->Position ? Hist->Position : Hist->NumEntries) - 1;
348 Console->LineUpPressed = TRUE;
349
350 Entry.Length = Console->LinePos * sizeof(WCHAR); // == Pos * sizeof(WCHAR)
351 Entry.Buffer = Console->LineBuffer;
352
353 /*
354 * Keep going backwards, even wrapping around to the end,
355 * until we get back to starting point.
356 */
357 HistPos = Hist->Position;
358 do
359 {
360 if (RtlPrefixUnicodeString(&Entry, &Hist->Entries[HistPos], FALSE))
361 {
362 Hist->Position = HistPos;
363 LineInputEdit(Console, Console->LineSize - Pos,
364 Hist->Entries[HistPos].Length / sizeof(WCHAR) - Pos,
365 &Hist->Entries[HistPos].Buffer[Pos]);
366 /* Cursor stays where it was */
368 return;
369 }
370 if (--HistPos < 0) HistPos += Hist->NumEntries;
371 } while (HistPos != Hist->Position);
372
373 return;
374 }
375#endif
376
377 return;
378 }
379
380
381 /*
382 * OK, we deal with normal keys, we can continue...
383 */
384
386 {
387 /*
388 * Backspace handling - if processed input enabled then we handle it
389 * here, otherwise we treat it like a normal character.
390 */
391 if (Pos > 0)
392 {
394 LineInputEdit(Console, 1, 0, NULL);
395 }
396 }
397 else if (KeyEvent->uChar.UnicodeChar == L'\r')
398 {
399 /*
400 * Only add a history entry if console echo is enabled. This ensures
401 * that anything sent to the console when echo is disabled (e.g.
402 * binary data, or secrets like passwords...) does not remain stored
403 * in memory.
404 */
406 {
407 Entry.Length = Entry.MaximumLength = Console->LineSize * sizeof(WCHAR);
408 Entry.Buffer = Console->LineBuffer;
409 HistoryAddEntry(Console, ExeName, &Entry);
410 }
411
412 /* TODO: Expand aliases */
413 DPRINT1("TODO: Expand aliases\n");
414
415 LineInputSetPos(Console, Console->LineSize);
416 Console->LineBuffer[Console->LineSize++] = L'\r';
417 if ((GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER) &&
419 {
420 TermWriteStream(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), L"\r", 1, TRUE);
421 }
422
423 /*
424 * Add \n if processed input. There should usually be room for it,
425 * but an exception to the rule exists: the buffer could have been
426 * pre-filled with LineMaxSize - 1 characters.
427 */
429 Console->LineSize < Console->LineMaxSize)
430 {
431 Console->LineBuffer[Console->LineSize++] = L'\n';
432 if ((GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER) &&
434 {
435 TermWriteStream(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), L"\n", 1, TRUE);
436 }
437 }
438 Console->LineComplete = TRUE;
439 Console->LinePos = 0;
440 }
441 else if (KeyEvent->uChar.UnicodeChar != L'\0')
442 {
443 if (KeyEvent->uChar.UnicodeChar < 0x20 &&
444 Console->LineWakeupMask & (1 << KeyEvent->uChar.UnicodeChar))
445 {
446 /* Control key client wants to handle itself (e.g. for tab completion) */
447 Console->LineBuffer[Console->LineSize++] = L' ';
448 Console->LineBuffer[Console->LinePos] = KeyEvent->uChar.UnicodeChar;
449 Console->LineComplete = TRUE;
450 Console->LinePos = 0;
451 }
452 else
453 {
454 /* Normal character */
455 BOOL Overstrike = !Console->LineInsertToggle && (Console->LinePos != Console->LineSize);
456 DPRINT("Overstrike = %s\n", Overstrike ? "true" : "false");
457 LineInputEdit(Console, (Overstrike ? 1 : 0), 1, &KeyEvent->uChar.UnicodeChar);
458 }
459 }
460}
461
462
463/* PUBLIC SERVER APIS *********************************************************/
464
465/* EOF */
unsigned char BOOLEAN
CConsole Console
#define DPRINT1
Definition: precomp.h:8
Definition: bufpool.h:45
ush Pos
Definition: deflate.h:92
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned short WORD
Definition: ntddk_ex.h:93
_Must_inspect_result_ _In_ USHORT NewSize
Definition: fltkernel.h:975
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
PPOPUP_WINDOW Popup
Definition: lineinput.c:140
static VOID LineInputRecallHistory(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, INT Offset)
Definition: lineinput.c:106
VOID LineInputKeyDown(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, KEY_EVENT_RECORD *KeyEvent)
Definition: lineinput.c:147
BOOLEAN ConvertInputUnicodeToAnsi(PCONSRV_CONSOLE Console, PVOID Source, USHORT SourceLength, PCHAR Target, USHORT TargetLength)
Definition: alias.c:64
static VOID LineInputSetPos(PCONSRV_CONSOLE Console, UINT Pos)
Definition: lineinput.c:38
PPOPUP_WINDOW HistoryDisplayCurrentHistory(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName)
Definition: history.c:315
static VOID LineInputEdit(PCONSRV_CONSOLE Console, UINT NumToDelete, UINT NumToInsert, PWCHAR Insertion)
Definition: lineinput.c:63
BOOLEAN ConvertInputAnsiToUnicode(PCONSRV_CONSOLE Console, PVOID Source, USHORT SourceLength, PWCHAR *Target, PUSHORT TargetLength)
Definition: alias.c:37
if(dx< 0)
Definition: linetemp.h:194
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
_In_ UINT _In_ UINT _In_ PNDIS_PACKET Source
Definition: ndis.h:3169
NTSYSAPI BOOLEAN NTAPI RtlPrefixUnicodeString(IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, IN BOOLEAN CaseInSensitive)
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
#define L(x)
Definition: ntvdm.h:50
#define TEXTMODE_BUFFER
Definition: pccons.c:21
short SHORT
Definition: pedump.c:59
unsigned short USHORT
Definition: pedump.c:61
VOID DestroyPopupWindow(IN PPOPUP_WINDOW Popup)
Definition: popup.c:244
#define DPRINT
Definition: sndvol32.h:73
base of all file and directory entries
Definition: entries.h:83
PUNICODE_STRING Entries
Definition: history.c:24
ULONG NumEntries
Definition: history.c:22
ULONG Position
Definition: history.c:20
DWORD dwControlKeyState
Definition: wincon.h:248
WORD wVirtualKeyCode
Definition: wincon.h:242
union _KEY_EVENT_RECORD::@3286 uChar
WCHAR UnicodeChar
Definition: wincon.h:245
static COORD Position
Definition: mouse.c:34
#define max(a, b)
Definition: svc.c:63
#define TermWriteStream(Console, ScreenBuffer, Buffer, Length, Attrib)
Definition: term.h:17
#define TermSetScreenInfo(Console, ScreenBuffer, OldCursorX, OldCursorY)
Definition: term.h:26
#define TermSetCursorInfo(Console, ScreenBuffer)
Definition: term.h:24
int32_t INT
Definition: typedefs.h:58
uint16_t * PUSHORT
Definition: typedefs.h:56
uint16_t * PWCHAR
Definition: typedefs.h:56
char * PCHAR
Definition: typedefs.h:51
_In_ WDFIOTARGET Target
Definition: wdfrequest.h:306
VOID HistoryGetCurrentEntry(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, PUNICODE_STRING Entry)
Definition: history.c:241
static PHISTORY_BUFFER HistoryCurrentBuffer(IN PCONSRV_CONSOLE Console, IN PUNICODE_STRING ExeName)
Definition: history.c:47
VOID HistoryDeleteCurrentBuffer(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName)
Definition: history.c:350
BOOL HistoryFindEntryByPrefix(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, PUNICODE_STRING Prefix, PUNICODE_STRING Entry)
Definition: history.c:273
VOID HistoryAddEntry(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, PUNICODE_STRING Entry)
Definition: history.c:185
BOOL HistoryRecallHistory(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, INT Offset, PUNICODE_STRING Entry)
Definition: history.c:254
#define GetConsoleInputBufferMode(Console)
Definition: conio.h:320
struct _TEXTMODE_SCREEN_BUFFER * PTEXTMODE_SCREEN_BUFFER
#define GetType(This)
Definition: conio.h:54
#define LEFT_CTRL_PRESSED
Definition: wincon.h:140
#define ENABLE_ECHO_INPUT
Definition: wincon.h:80
#define RIGHT_CTRL_PRESSED
Definition: wincon.h:139
#define RIGHT_ALT_PRESSED
Definition: wincon.h:137
#define LEFT_ALT_PRESSED
Definition: wincon.h:138
#define ENABLE_PROCESSED_INPUT
Definition: wincon.h:78
#define VK_UP
Definition: winuser.h:2228
#define VK_F1
Definition: winuser.h:2258
#define VK_F6
Definition: winuser.h:2263
#define VK_NEXT
Definition: winuser.h:2224
#define VK_F5
Definition: winuser.h:2262
#define VK_F8
Definition: winuser.h:2265
#define VK_END
Definition: winuser.h:2225
#define VK_HOME
Definition: winuser.h:2226
#define VK_F3
Definition: winuser.h:2260
#define VK_LEFT
Definition: winuser.h:2227
#define VK_RIGHT
Definition: winuser.h:2229
#define VK_DOWN
Definition: winuser.h:2230
#define VK_PRIOR
Definition: winuser.h:2223
#define VK_DELETE
Definition: winuser.h:2236
#define VK_ESCAPE
Definition: winuser.h:2217
#define VK_F7
Definition: winuser.h:2264
#define VK_INSERT
Definition: winuser.h:2235
__wchar_t WCHAR
Definition: xmlstorage.h:180