ReactOS  0.4.15-dev-1171-gab82533
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 
19 BOOLEAN
21  PVOID Source,
22  USHORT SourceLength,
23  // BOOLEAN IsUnicode,
24  PWCHAR* Target,
25  PUSHORT TargetLength);
26 BOOLEAN
28  PVOID Source,
29  USHORT SourceLength,
30  // BOOLEAN IsAnsi,
31  PCHAR/* * */ Target,
32  /*P*/USHORT TargetLength);
33 
34 
35 /* PRIVATE FUNCTIONS **********************************************************/
36 
37 static VOID
39  UINT Pos)
40 {
42  {
43  PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer;
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 
62 static 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 
105 static VOID
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 
145 
146 VOID
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 */
252  return;
253  }
254 
255  case VK_NEXT:
256  {
257  /* Recall the last history entry */
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 */
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 */
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;
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 */
signed char * PCHAR
Definition: retypes.h:7
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define max(a, b)
Definition: svc.c:63
WCHAR UnicodeChar
Definition: wincon.h:245
#define VK_F5
Definition: winuser.h:2234
BOOL HistoryRecallHistory(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, INT Offset, PUNICODE_STRING Entry)
Definition: history.c:254
#define VK_F6
Definition: winuser.h:2235
struct _Entry Entry
Definition: kefuncs.h:627
#define TRUE
Definition: types.h:120
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
static PHISTORY_BUFFER HistoryCurrentBuffer(IN PCONSRV_CONSOLE Console, IN PUNICODE_STRING ExeName)
Definition: history.c:47
#define VK_LEFT
Definition: winuser.h:2199
VOID HistoryGetCurrentEntry(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, PUNICODE_STRING Entry)
Definition: history.c:241
#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:56
#define VK_ESCAPE
Definition: winuser.h:2189
VOID LineInputKeyDown(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, KEY_EVENT_RECORD *KeyEvent)
Definition: lineinput.c:147
int32_t INT
Definition: typedefs.h:58
#define VK_NEXT
Definition: winuser.h:2196
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
#define FALSE
Definition: types.h:117
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:318
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
PPOPUP_WINDOW Popup
Definition: lineinput.c:140
PUNICODE_STRING Entries
Definition: history.c:24
PPOPUP_WINDOW HistoryDisplayCurrentHistory(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName)
Definition: history.c:315
#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
BOOL HistoryFindEntryByPrefix(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, PUNICODE_STRING Prefix, PUNICODE_STRING Entry)
Definition: history.c:273
_Must_inspect_result_ typedef _In_ ULONG _In_ BOOLEAN Target
Definition: iotypes.h:1088
#define VK_F3
Definition: winuser.h:2232
union _KEY_EVENT_RECORD::@3241 uChar
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
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
VOID HistoryDeleteCurrentBuffer(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName)
Definition: history.c:350
#define VK_RIGHT
Definition: winuser.h:2201
#define ENABLE_PROCESSED_INPUT
Definition: wincon.h:78
#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:38
#define VK_F1
Definition: winuser.h:2230
CConsole Console
#define DPRINT1
Definition: precomp.h:8
_In_ UINT _In_ UINT _In_ PNDIS_PACKET Source
Definition: ndis.h:3167
VOID HistoryAddEntry(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, PUNICODE_STRING Entry)
Definition: history.c:185
#define TermWriteStream(Console, ScreenBuffer, Buffer, Length, Attrib)
Definition: term.h:17
#define RIGHT_CTRL_PRESSED
Definition: wincon.h:139
static VOID LineInputEdit(PCONSRV_CONSOLE Console, UINT NumToDelete, UINT NumToInsert, PWCHAR Insertion)
Definition: lineinput.c:63
static VOID LineInputRecallHistory(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, INT Offset)
Definition: lineinput.c:106
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