ReactOS  0.4.14-dev-342-gdc047f9
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  for (i = Pos; i < NewSize; i++)
110  {
111  TermWriteStream(Console, ActiveBuffer, &Console->LineBuffer[i], 1, TRUE);
112  }
113  for (; i < Console->LineSize; i++)
114  {
115  TermWriteStream(Console, ActiveBuffer, L" ", 1, TRUE);
116  }
117  Console->LinePos = i;
118  }
119 
120  Console->LineSize = NewSize;
121  LineInputSetPos(Console, Pos + NumToInsert);
122 }
123 
124 static VOID
127  INT Offset)
128 {
129 #if 0
131  UINT Position = 0;
132 
133  if (!Hist || Hist->NumEntries == 0) return;
134 
135  Position = Hist->Position + Offset;
136  Position = min(max(Position, 0), Hist->NumEntries - 1);
137  Hist->Position = Position;
138 
140  LineInputEdit(Console, Console->LineSize,
141  Hist->Entries[Hist->Position].Length / sizeof(WCHAR),
142  Hist->Entries[Hist->Position].Buffer);
143 
144 #else
145 
147 
148  if (!HistoryRecallHistory(Console, ExeName, Offset, &Entry)) return;
149 
151  LineInputEdit(Console, Console->LineSize,
152  Entry.Length / sizeof(WCHAR),
153  Entry.Buffer);
154 #endif
155 }
156 
157 
158 // TESTS!!
160 
164 
165 VOID
168  KEY_EVENT_RECORD *KeyEvent)
169 {
170  UINT Pos = Console->LinePos;
172 
173  /*
174  * First, deal with control keys...
175  */
176 
177  switch (KeyEvent->wVirtualKeyCode)
178  {
179  case VK_ESCAPE:
180  {
181  /* Clear the entire line */
183  LineInputEdit(Console, Console->LineSize, 0, NULL);
184 
185  // TESTS!!
186  if (Popup)
187  {
189  Popup = NULL;
190  }
191  return;
192  }
193 
194  case VK_HOME:
195  {
196  /* Move to start of line. With CTRL, erase everything left of cursor. */
200  return;
201  }
202 
203  case VK_END:
204  {
205  /* Move to end of line. With CTRL, erase everything right of cursor. */
207  LineInputEdit(Console, Console->LineSize - Pos, 0, NULL);
208  else
209  LineInputSetPos(Console, Console->LineSize);
210  return;
211  }
212 
213  case VK_LEFT:
214  {
215  /* Move to the left. With CTRL, move to beginning of previous word. */
217  {
218  while (Pos > 0 && Console->LineBuffer[Pos - 1] == L' ') Pos--;
219  while (Pos > 0 && Console->LineBuffer[Pos - 1] != L' ') Pos--;
220  }
221  else
222  {
223  Pos -= (Pos > 0);
224  }
226  return;
227  }
228 
229  case VK_RIGHT:
230  case VK_F1:
231  {
232  /* Move to the right. With CTRL, move to beginning of next word. */
234  {
235  while (Pos < Console->LineSize && Console->LineBuffer[Pos] != L' ') Pos++;
236  while (Pos < Console->LineSize && Console->LineBuffer[Pos] == L' ') Pos++;
238  }
239  else
240  {
241  /* Recall one character (but don't overwrite current line) */
243  if (Pos < Console->LineSize)
245  else if (Pos * sizeof(WCHAR) < Entry.Length)
246  LineInputEdit(Console, 0, 1, &Entry.Buffer[Pos]);
247  }
248  return;
249  }
250 
251  case VK_INSERT:
252  {
253  /* Toggle between insert and overstrike */
254  Console->LineInsertToggle = !Console->LineInsertToggle;
255  TermSetCursorInfo(Console, Console->ActiveBuffer);
256  return;
257  }
258 
259  case VK_DELETE:
260  {
261  /* Remove one character to right of cursor */
262  if (Pos != Console->LineSize)
263  LineInputEdit(Console, 1, 0, NULL);
264  return;
265  }
266 
267  case VK_PRIOR:
268  {
269  /* Recall the first history entry */
271  return;
272  }
273 
274  case VK_NEXT:
275  {
276  /* Recall the last history entry */
278  return;
279  }
280 
281  case VK_UP:
282  case VK_F5:
283  {
284  /*
285  * Recall the previous history entry. On first time, actually recall
286  * the current (usually last) entry; on subsequent times go back.
287  */
288  LineInputRecallHistory(Console, ExeName, Console->LineUpPressed ? -1 : 0);
289  Console->LineUpPressed = TRUE;
290  return;
291  }
292 
293  case VK_DOWN:
294  {
295  /* Recall the next history entry */
297  return;
298  }
299 
300  case VK_F3:
301  {
302  /* Recall the remainder of the current history entry */
304  if (Pos * sizeof(WCHAR) < Entry.Length)
305  {
306  UINT InsertSize = (Entry.Length / sizeof(WCHAR) - Pos);
307  UINT DeleteSize = min(Console->LineSize - Pos, InsertSize);
308  LineInputEdit(Console, DeleteSize, InsertSize, &Entry.Buffer[Pos]);
309  }
310  return;
311  }
312 
313  case VK_F6:
314  {
315  /* Insert a ^Z character */
316  KeyEvent->uChar.UnicodeChar = 26;
317  break;
318  }
319 
320  case VK_F7:
321  {
324  else
325  {
328  }
329  return;
330  }
331 
332  case VK_F8:
333  {
334  UNICODE_STRING EntryFound;
335 
336  Entry.Length = Console->LinePos * sizeof(WCHAR); // == Pos * sizeof(WCHAR)
337  Entry.Buffer = Console->LineBuffer;
338 
339  if (HistoryFindEntryByPrefix(Console, ExeName, &Entry, &EntryFound))
340  {
341  LineInputEdit(Console, Console->LineSize - Pos,
342  EntryFound.Length / sizeof(WCHAR) - Pos,
343  &EntryFound.Buffer[Pos]);
344  /* Cursor stays where it was */
346  }
347 
348  return;
349  }
350 #if 0
351  {
352  PHISTORY_BUFFER Hist;
353  INT HistPos;
354 
355  /* Search for history entries starting with input */
357  if (!Hist || Hist->NumEntries == 0) return;
358 
359  /*
360  * Like Up/F5, on first time start from current (usually last) entry,
361  * but on subsequent times start at previous entry.
362  */
363  if (Console->LineUpPressed)
364  Hist->Position = (Hist->Position ? Hist->Position : Hist->NumEntries) - 1;
365  Console->LineUpPressed = TRUE;
366 
367  Entry.Length = Console->LinePos * sizeof(WCHAR); // == Pos * sizeof(WCHAR)
368  Entry.Buffer = Console->LineBuffer;
369 
370  /*
371  * Keep going backwards, even wrapping around to the end,
372  * until we get back to starting point.
373  */
374  HistPos = Hist->Position;
375  do
376  {
377  if (RtlPrefixUnicodeString(&Entry, &Hist->Entries[HistPos], FALSE))
378  {
379  Hist->Position = HistPos;
380  LineInputEdit(Console, Console->LineSize - Pos,
381  Hist->Entries[HistPos].Length / sizeof(WCHAR) - Pos,
382  &Hist->Entries[HistPos].Buffer[Pos]);
383  /* Cursor stays where it was */
385  return;
386  }
387  if (--HistPos < 0) HistPos += Hist->NumEntries;
388  } while (HistPos != Hist->Position);
389 
390  return;
391  }
392 #endif
393 
394  return;
395  }
396 
397 
398  /*
399  * OK, we deal with normal keys, we can continue...
400  */
401 
403  {
404  /*
405  * Backspace handling - if processed input enabled then we handle it
406  * here, otherwise we treat it like a normal character.
407  */
408  if (Pos > 0)
409  {
411  LineInputEdit(Console, 1, 0, NULL);
412  }
413  }
414  else if (KeyEvent->uChar.UnicodeChar == L'\r')
415  {
416  /*
417  * Only add a history entry if console echo is enabled. This ensures
418  * that anything sent to the console when echo is disabled (e.g.
419  * binary data, or secrets like passwords...) does not remain stored
420  * in memory.
421  */
423  {
424  Entry.Length = Entry.MaximumLength = Console->LineSize * sizeof(WCHAR);
425  Entry.Buffer = Console->LineBuffer;
427  }
428 
429  /* TODO: Expand aliases */
430  DPRINT1("TODO: Expand aliases\n");
431 
432  LineInputSetPos(Console, Console->LineSize);
433  Console->LineBuffer[Console->LineSize++] = L'\r';
435  {
436  if (GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER)
437  {
438  TermWriteStream(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), L"\r", 1, TRUE);
439  }
440  }
441 
442  /*
443  * Add \n if processed input. There should usually be room for it,
444  * but an exception to the rule exists: the buffer could have been
445  * pre-filled with LineMaxSize - 1 characters.
446  */
448  Console->LineSize < Console->LineMaxSize)
449  {
450  Console->LineBuffer[Console->LineSize++] = L'\n';
452  {
453  if (GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER)
454  {
455  TermWriteStream(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), L"\n", 1, TRUE);
456  }
457  }
458  }
459  Console->LineComplete = TRUE;
460  Console->LinePos = 0;
461  }
462  else if (KeyEvent->uChar.UnicodeChar != L'\0')
463  {
464  if (KeyEvent->uChar.UnicodeChar < 0x20 &&
465  Console->LineWakeupMask & (1 << KeyEvent->uChar.UnicodeChar))
466  {
467  /* Control key client wants to handle itself (e.g. for tab completion) */
468  Console->LineBuffer[Console->LineSize++] = L' ';
469  Console->LineBuffer[Console->LinePos] = KeyEvent->uChar.UnicodeChar;
470  Console->LineComplete = TRUE;
471  Console->LinePos = 0;
472  }
473  else
474  {
475  /* Normal character */
476  BOOL Overstrike = !Console->LineInsertToggle && (Console->LinePos != Console->LineSize);
477  DPRINT("Overstrike = %s\n", Overstrike ? "true" : "false");
478  LineInputEdit(Console, (Overstrike ? 1 : 0), 1, &KeyEvent->uChar.UnicodeChar);
479  }
480  }
481 }
482 
483 
484 /* PUBLIC SERVER APIS *********************************************************/
485 
486 /* 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:230
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:640
ULONG NumEntries
Definition: history.c:22
static COORD Position
Definition: mouse.c:34
ush Pos
Definition: deflate.h:92
DWORD dwControlKeyState
Definition: wincon.h:233
#define VK_LEFT
Definition: winuser.h:2199
union _KEY_EVENT_RECORD::@3175 uChar
#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:54
#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:166
int32_t INT
Definition: typedefs.h:56
#define VK_NEXT
Definition: winuser.h:2196
VOID HistoryDeleteCurrentBuffer(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName)
Definition: history.c:306
WORD wVirtualKeyCode
Definition: wincon.h:227
#define ENABLE_ECHO_INPUT
Definition: wincon.h:77
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:362
void DPRINT(...)
Definition: polytest.cpp:61
Definition: bufpool.h:45
#define VK_DELETE
Definition: winuser.h:2208
#define LEFT_ALT_PRESSED
Definition: wincon.h:132
VOID HistoryGetCurrentEntry(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, PUNICODE_STRING Entry)
Definition: history.c:197
PPOPUP_WINDOW Popup
Definition: lineinput.c:159
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:134
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:75
#define TermSetCursorInfo(Console, ScreenBuffer)
Definition: term.h:24
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:133
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:125
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:131