ReactOS  0.4.14-dev-1034-g1e60116
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 "popup.h"
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 
18 BOOLEAN
20  PVOID Source,
21  USHORT SourceLength,
22  // BOOLEAN IsUnicode,
23  PWCHAR* Target,
24  PUSHORT TargetLength);
25 BOOLEAN
27  PVOID Source,
28  USHORT SourceLength,
29  // BOOLEAN IsAnsi,
30  PCHAR/* * */ Target,
31  /*P*/USHORT TargetLength);
32 
33 
34 VOID
38 BOOL
41  INT Offset,
43 VOID
47 VOID
50 BOOL
55 
56 
57 /* PRIVATE FUNCTIONS **********************************************************/
58 
59 static VOID
61  UINT Pos)
62 {
64  {
65  PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer;
66  SHORT OldCursorX = Buffer->CursorPosition.X;
67  SHORT OldCursorY = Buffer->CursorPosition.Y;
68  INT XY = OldCursorY * Buffer->ScreenBufferSize.X + OldCursorX;
69 
70  XY += (Pos - Console->LinePos);
71  if (XY < 0)
72  XY = 0;
73  else if (XY >= Buffer->ScreenBufferSize.Y * Buffer->ScreenBufferSize.X)
74  XY = Buffer->ScreenBufferSize.Y * Buffer->ScreenBufferSize.X - 1;
75 
76  Buffer->CursorPosition.X = XY % Buffer->ScreenBufferSize.X;
77  Buffer->CursorPosition.Y = XY / Buffer->ScreenBufferSize.X;
78  TermSetScreenInfo(Console, Buffer, OldCursorX, OldCursorY);
79  }
80 
81  Console->LinePos = Pos;
82 }
83 
84 static VOID
86  UINT NumToDelete,
87  UINT NumToInsert,
88  PWCHAR Insertion)
89 {
90  PTEXTMODE_SCREEN_BUFFER ActiveBuffer;
91  UINT Pos = Console->LinePos;
92  UINT NewSize = Console->LineSize - NumToDelete + NumToInsert;
93  UINT i;
94 
95  if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER) return;
96  ActiveBuffer = (PTEXTMODE_SCREEN_BUFFER)Console->ActiveBuffer;
97 
98  /* Make sure there is always enough room for ending \r\n */
99  if (NewSize + 2 > Console->LineMaxSize)
100  return;
101 
102  memmove(&Console->LineBuffer[Pos + NumToInsert],
103  &Console->LineBuffer[Pos + NumToDelete],
104  (Console->LineSize - (Pos + NumToDelete)) * sizeof(WCHAR));
105  memcpy(&Console->LineBuffer[Pos], Insertion, NumToInsert * sizeof(WCHAR));
106 
108  {
109  if (Pos < NewSize)
110  {
111  TermWriteStream(Console, ActiveBuffer,
112  &Console->LineBuffer[Pos],
113  NewSize - Pos,
114  TRUE);
115  }
116  for (i = NewSize; i < Console->LineSize; ++i)
117  {
118  TermWriteStream(Console, ActiveBuffer, L" ", 1, TRUE);
119  }
120  Console->LinePos = i;
121  }
122 
123  Console->LineSize = NewSize;
124  LineInputSetPos(Console, Pos + NumToInsert);
125 }
126 
127 static VOID
130  INT Offset)
131 {
132 #if 0
134  UINT Position = 0;
135 
136  if (!Hist || Hist->NumEntries == 0) return;
137 
138  Position = Hist->Position + Offset;
139  Position = min(max(Position, 0), Hist->NumEntries - 1);
140  Hist->Position = Position;
141 
143  LineInputEdit(Console, Console->LineSize,
144  Hist->Entries[Hist->Position].Length / sizeof(WCHAR),
145  Hist->Entries[Hist->Position].Buffer);
146 
147 #else
148 
150 
151  if (!HistoryRecallHistory(Console, ExeName, Offset, &Entry)) return;
152 
154  LineInputEdit(Console, Console->LineSize,
155  Entry.Length / sizeof(WCHAR),
156  Entry.Buffer);
157 #endif
158 }
159 
160 
161 // TESTS!!
163 
167 
168 VOID
171  KEY_EVENT_RECORD *KeyEvent)
172 {
173  UINT Pos = Console->LinePos;
175 
176  /*
177  * First, deal with control keys...
178  */
179 
180  switch (KeyEvent->wVirtualKeyCode)
181  {
182  case VK_ESCAPE:
183  {
184  /* Clear the entire line */
186  LineInputEdit(Console, Console->LineSize, 0, NULL);
187 
188  // TESTS!!
189  if (Popup)
190  {
192  Popup = NULL;
193  }
194  return;
195  }
196 
197  case VK_HOME:
198  {
199  /* Move to start of line. With CTRL, erase everything left of cursor. */
203  return;
204  }
205 
206  case VK_END:
207  {
208  /* Move to end of line. With CTRL, erase everything right of cursor. */
210  LineInputEdit(Console, Console->LineSize - Pos, 0, NULL);
211  else
212  LineInputSetPos(Console, Console->LineSize);
213  return;
214  }
215 
216  case VK_LEFT:
217  {
218  /* Move to the left. With CTRL, move to beginning of previous word. */
220  {
221  while (Pos > 0 && Console->LineBuffer[Pos - 1] == L' ') Pos--;
222  while (Pos > 0 && Console->LineBuffer[Pos - 1] != L' ') Pos--;
223  }
224  else
225  {
226  Pos -= (Pos > 0);
227  }
229  return;
230  }
231 
232  case VK_RIGHT:
233  case VK_F1:
234  {
235  /* Move to the right. With CTRL, move to beginning of next word. */
237  {
238  while (Pos < Console->LineSize && Console->LineBuffer[Pos] != L' ') Pos++;
239  while (Pos < Console->LineSize && Console->LineBuffer[Pos] == L' ') Pos++;
241  }
242  else
243  {
244  /* Recall one character (but don't overwrite current line) */
246  if (Pos < Console->LineSize)
248  else if (Pos * sizeof(WCHAR) < Entry.Length)
249  LineInputEdit(Console, 0, 1, &Entry.Buffer[Pos]);
250  }
251  return;
252  }
253 
254  case VK_INSERT:
255  {
256  /* Toggle between insert and overstrike */
257  Console->LineInsertToggle = !Console->LineInsertToggle;
258  TermSetCursorInfo(Console, Console->ActiveBuffer);
259  return;
260  }
261 
262  case VK_DELETE:
263  {
264  /* Remove one character to right of cursor */
265  if (Pos != Console->LineSize)
266  LineInputEdit(Console, 1, 0, NULL);
267  return;
268  }
269 
270  case VK_PRIOR:
271  {
272  /* Recall the first history entry */
274  return;
275  }
276 
277  case VK_NEXT:
278  {
279  /* Recall the last history entry */
281  return;
282  }
283 
284  case VK_UP:
285  case VK_F5:
286  {
287  /*
288  * Recall the previous history entry. On first time, actually recall
289  * the current (usually last) entry; on subsequent times go back.
290  */
291  LineInputRecallHistory(Console, ExeName, Console->LineUpPressed ? -1 : 0);
292  Console->LineUpPressed = TRUE;
293  return;
294  }
295 
296  case VK_DOWN:
297  {
298  /* Recall the next history entry */
300  return;
301  }
302 
303  case VK_F3:
304  {
305  /* Recall the remainder of the current history entry */
307  if (Pos * sizeof(WCHAR) < Entry.Length)
308  {
309  UINT InsertSize = (Entry.Length / sizeof(WCHAR) - Pos);
310  UINT DeleteSize = min(Console->LineSize - Pos, InsertSize);
311  LineInputEdit(Console, DeleteSize, InsertSize, &Entry.Buffer[Pos]);
312  }
313  return;
314  }
315 
316  case VK_F6:
317  {
318  /* Insert a ^Z character */
319  KeyEvent->uChar.UnicodeChar = 26;
320  break;
321  }
322 
323  case VK_F7:
324  {
327  else
328  {
331  }
332  return;
333  }
334 
335  case VK_F8:
336  {
337  UNICODE_STRING EntryFound;
338 
339  Entry.Length = Console->LinePos * sizeof(WCHAR); // == Pos * sizeof(WCHAR)
340  Entry.Buffer = Console->LineBuffer;
341 
342  if (HistoryFindEntryByPrefix(Console, ExeName, &Entry, &EntryFound))
343  {
344  LineInputEdit(Console, Console->LineSize - Pos,
345  EntryFound.Length / sizeof(WCHAR) - Pos,
346  &EntryFound.Buffer[Pos]);
347  /* Cursor stays where it was */
349  }
350 
351  return;
352  }
353 #if 0
354  {
355  PHISTORY_BUFFER Hist;
356  INT HistPos;
357 
358  /* Search for history entries starting with input */
360  if (!Hist || Hist->NumEntries == 0) return;
361 
362  /*
363  * Like Up/F5, on first time start from current (usually last) entry,
364  * but on subsequent times start at previous entry.
365  */
366  if (Console->LineUpPressed)
367  Hist->Position = (Hist->Position ? Hist->Position : Hist->NumEntries) - 1;
368  Console->LineUpPressed = TRUE;
369 
370  Entry.Length = Console->LinePos * sizeof(WCHAR); // == Pos * sizeof(WCHAR)
371  Entry.Buffer = Console->LineBuffer;
372 
373  /*
374  * Keep going backwards, even wrapping around to the end,
375  * until we get back to starting point.
376  */
377  HistPos = Hist->Position;
378  do
379  {
380  if (RtlPrefixUnicodeString(&Entry, &Hist->Entries[HistPos], FALSE))
381  {
382  Hist->Position = HistPos;
383  LineInputEdit(Console, Console->LineSize - Pos,
384  Hist->Entries[HistPos].Length / sizeof(WCHAR) - Pos,
385  &Hist->Entries[HistPos].Buffer[Pos]);
386  /* Cursor stays where it was */
388  return;
389  }
390  if (--HistPos < 0) HistPos += Hist->NumEntries;
391  } while (HistPos != Hist->Position);
392 
393  return;
394  }
395 #endif
396 
397  return;
398  }
399 
400 
401  /*
402  * OK, we deal with normal keys, we can continue...
403  */
404 
406  {
407  /*
408  * Backspace handling - if processed input enabled then we handle it
409  * here, otherwise we treat it like a normal character.
410  */
411  if (Pos > 0)
412  {
414  LineInputEdit(Console, 1, 0, NULL);
415  }
416  }
417  else if (KeyEvent->uChar.UnicodeChar == L'\r')
418  {
419  /*
420  * Only add a history entry if console echo is enabled. This ensures
421  * that anything sent to the console when echo is disabled (e.g.
422  * binary data, or secrets like passwords...) does not remain stored
423  * in memory.
424  */
426  {
427  Entry.Length = Entry.MaximumLength = Console->LineSize * sizeof(WCHAR);
428  Entry.Buffer = Console->LineBuffer;
430  }
431 
432  /* TODO: Expand aliases */
433  DPRINT1("TODO: Expand aliases\n");
434 
435  LineInputSetPos(Console, Console->LineSize);
436  Console->LineBuffer[Console->LineSize++] = L'\r';
437  if ((GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER) &&
439  {
440  TermWriteStream(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), L"\r", 1, TRUE);
441  }
442 
443  /*
444  * Add \n if processed input. There should usually be room for it,
445  * but an exception to the rule exists: the buffer could have been
446  * pre-filled with LineMaxSize - 1 characters.
447  */
449  Console->LineSize < Console->LineMaxSize)
450  {
451  Console->LineBuffer[Console->LineSize++] = L'\n';
452  if ((GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER) &&
454  {
455  TermWriteStream(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), L"\n", 1, TRUE);
456  }
457  }
458  Console->LineComplete = TRUE;
459  Console->LinePos = 0;
460  }
461  else if (KeyEvent->uChar.UnicodeChar != L'\0')
462  {
463  if (KeyEvent->uChar.UnicodeChar < 0x20 &&
464  Console->LineWakeupMask & (1 << KeyEvent->uChar.UnicodeChar))
465  {
466  /* Control key client wants to handle itself (e.g. for tab completion) */
467  Console->LineBuffer[Console->LineSize++] = L' ';
468  Console->LineBuffer[Console->LinePos] = KeyEvent->uChar.UnicodeChar;
469  Console->LineComplete = TRUE;
470  Console->LinePos = 0;
471  }
472  else
473  {
474  /* Normal character */
475  BOOL Overstrike = !Console->LineInsertToggle && (Console->LinePos != Console->LineSize);
476  DPRINT("Overstrike = %s\n", Overstrike ? "true" : "false");
477  LineInputEdit(Console, (Overstrike ? 1 : 0), 1, &KeyEvent->uChar.UnicodeChar);
478  }
479  }
480 }
481 
482 
483 /* PUBLIC SERVER APIS *********************************************************/
484 
485 /* EOF */
signed char * PCHAR
Definition: retypes.h:7
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define max(a, b)
Definition: svc.c:63
#define TRUE
Definition: types.h:120
_In_ __drv_aliasesMem PSTRING Prefix
Definition: rtlfuncs.h:1631
WCHAR UnicodeChar
Definition: wincon.h:245
static PHISTORY_BUFFER HistoryCurrentBuffer(PCONSOLE Console)
Definition: lineinput.c:33
#define VK_F5
Definition: winuser.h:2234
#define VK_F6
Definition: winuser.h:2235
struct _Entry Entry
Definition: kefuncs.h:627
ULONG NumEntries
Definition: history.c:22
static COORD Position
Definition: mouse.c:34
ush Pos
Definition: deflate.h:92
DWORD dwControlKeyState
Definition: wincon.h:248
#define VK_LEFT
Definition: winuser.h:2199
#define VK_DOWN
Definition: winuser.h:2202
#define VK_INSERT
Definition: winuser.h:2207
#define VK_PRIOR
Definition: winuser.h:2195
uint16_t * PWCHAR
Definition: typedefs.h:55
#define TEXTMODE_BUFFER
Definition: pccons.c:21
#define PCONSRV_CONSOLE
Definition: conio.h:27
#define VK_ESCAPE
Definition: winuser.h:2189
VOID LineInputKeyDown(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, KEY_EVENT_RECORD *KeyEvent)
Definition: lineinput.c:169
int32_t INT
Definition: typedefs.h:57
#define VK_NEXT
Definition: winuser.h:2196
VOID HistoryDeleteCurrentBuffer(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName)
Definition: history.c:306
WORD wVirtualKeyCode
Definition: wincon.h:242
#define ENABLE_ECHO_INPUT
Definition: wincon.h:80
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
#define VK_HOME
Definition: winuser.h:2198
#define VK_UP
Definition: winuser.h:2200
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
unsigned int BOOL
Definition: ntddk_ex.h:94
#define TermSetScreenInfo(Console, ScreenBuffer, OldCursorX, OldCursorY)
Definition: term.h:26
short SHORT
Definition: pedump.c:59
BOOLEAN ConvertInputAnsiToUnicode(PCONSRV_CONSOLE Console, PVOID Source, USHORT SourceLength, PWCHAR *Target, PUSHORT TargetLength)
Definition: alias.c:37
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define GetConsoleInputBufferMode(Console)
Definition: conio.h:364
void DPRINT(...)
Definition: polytest.cpp:61
Definition: bufpool.h:45
#define VK_DELETE
Definition: winuser.h:2208
#define LEFT_ALT_PRESSED
Definition: wincon.h:138
VOID HistoryGetCurrentEntry(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, PUNICODE_STRING Entry)
Definition: history.c:197
PPOPUP_WINDOW Popup
Definition: lineinput.c:162
PUNICODE_STRING Entries
Definition: history.c:24
PPOPUP_WINDOW HistoryDisplayCurrentHistory(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName)
Definition: history.c:271
#define VK_F7
Definition: winuser.h:2236
if(!(yy_init))
Definition: macro.lex.yy.c:714
__wchar_t WCHAR
Definition: xmlstorage.h:180
unsigned short WORD
Definition: ntddk_ex.h:93
ULONG Position
Definition: history.c:20
_Must_inspect_result_ typedef _In_ ULONG _In_ BOOLEAN Target
Definition: iotypes.h:1068
#define VK_F3
Definition: winuser.h:2232
BOOLEAN ConvertInputUnicodeToAnsi(PCONSRV_CONSOLE Console, PVOID Source, USHORT SourceLength, PCHAR Target, USHORT TargetLength)
Definition: alias.c:64
#define VK_F8
Definition: winuser.h:2237
#define LEFT_CTRL_PRESSED
Definition: wincon.h:140
INT GetType(BOOL bLocal, LPOSVERSIONINFOEX osvi, LPSERVER_INFO_102 pBuf102)
Definition: gettype.c:129
static const WCHAR L[]
Definition: oid.c:1250
VOID HistoryAddEntry(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, PUNICODE_STRING Entry)
Definition: history.c:141
UNICODE_STRING ExeName
Definition: alias.c:29
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
_Must_inspect_result_ _In_ USHORT NewSize
Definition: fltkernel.h:975
#define VK_RIGHT
Definition: winuser.h:2201
#define ENABLE_PROCESSED_INPUT
Definition: wincon.h:78
#define TermSetCursorInfo(Console, ScreenBuffer)
Definition: term.h:24
union _KEY_EVENT_RECORD::@3172 uChar
unsigned short USHORT
Definition: pedump.c:61
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
NTSYSAPI BOOLEAN NTAPI RtlPrefixUnicodeString(IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, IN BOOLEAN CaseInSensitive)
static VOID LineInputSetPos(PCONSRV_CONSOLE Console, UINT Pos)
Definition: lineinput.c:60
#define VK_F1
Definition: winuser.h:2230
CConsole Console
#define DPRINT1
Definition: precomp.h:8
BOOL HistoryFindEntryByPrefix(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, PUNICODE_STRING Prefix, PUNICODE_STRING Entry)
Definition: history.c:229
_In_ UINT _In_ UINT _In_ PNDIS_PACKET Source
Definition: ndis.h:3167
#define TermWriteStream(Console, ScreenBuffer, Buffer, Length, Attrib)
Definition: term.h:17
#define RIGHT_CTRL_PRESSED
Definition: wincon.h:139
BOOL HistoryRecallHistory(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, INT Offset, PUNICODE_STRING Entry)
Definition: history.c:210
static VOID LineInputEdit(PCONSRV_CONSOLE Console, UINT NumToDelete, UINT NumToInsert, PWCHAR Insertion)
Definition: lineinput.c:85
static VOID LineInputRecallHistory(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, INT Offset)
Definition: lineinput.c:128
struct _TEXTMODE_SCREEN_BUFFER * PTEXTMODE_SCREEN_BUFFER
#define VK_END
Definition: winuser.h:2197
unsigned short * PUSHORT
Definition: retypes.h:2
base of all file and directory entries
Definition: entries.h:82
#define RIGHT_ALT_PRESSED
Definition: wincon.h:137