Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

717 lines
16 KiB

  1. #define WIN32_ONLY
  2. #include "psxses.h"
  3. #include "ansiio.h"
  4. #include <posix/sys/types.h>
  5. #include <posix/termios.h>
  6. #include <io.h>
  7. #include <stdio.h>
  8. #define _POSIX_
  9. #include <posix/unistd.h> // for _POSIX_VDISABLE
  10. #include <posix/sys/errno.h> // for EAGAIN
  11. /* Keyboard Input Buffering Support */
  12. #define KBD_BUFFER_SIZE 512 // XXX.mjb: should use {MAX_INPUT}
  13. #define INPUT_EVENT_CLUSTER 1
  14. #define CR 0x0d // carriage return
  15. #define NL 0x0a // newline (aka line feed)
  16. //
  17. // We keep an array of screen positions of tab characters. These
  18. // are used when backspacing over tabs to know where to position
  19. // the cursor. NumTabs is the number of markers in use.
  20. //
  21. #define NUM_TAB_MARKERS (KBD_BUFFER_SIZE)
  22. /*STATIC*/ int TabMarkers[NUM_TAB_MARKERS];
  23. /*STATIC*/ int NumTabs;
  24. extern DWORD InputModeFlags; // console input mode
  25. extern DWORD OutputModeFlags; // Console Output Mode
  26. extern unsigned char AnsiNewMode;
  27. extern struct termios SavedTermios; // saved tty settings
  28. extern HANDLE
  29. hIoEvent,
  30. hStopEvent,
  31. hCanonEvent;
  32. extern CRITICAL_SECTION StopMutex;
  33. /*STATIC*/ int InputEOF; // input at EOF.
  34. /*STATIC*/ INT DelKbdBuffer(CHAR *CharBuf, DWORD CharCnt);
  35. //
  36. // SignalInterrupt is also protected by KbdBufMutex; when set,
  37. // indicates that EINTR should be returned from read.
  38. //
  39. /*STATIC*/ int SignalInterrupt = FALSE;
  40. extern CRITICAL_SECTION KbdBufMutex;
  41. //
  42. // XXX.mjb: Should implement a dynamic structure so there is no
  43. // limitation on input (if buffer is full, cannot terminate process
  44. // with ^C or other interrupt character
  45. //
  46. CHAR KbdBuffer[KBD_BUFFER_SIZE];
  47. DWORD KbdBufferHead = 0, // position of queue head
  48. KbdBufferTail = 0, // position of queue tail
  49. KbdBufferCount = 0, // chars in queue
  50. LineCount = 0; // lines in queue
  51. //
  52. // TermInput -- get input from kbd buffer and return to user.
  53. //
  54. // Return number of bytes retrieved; -1 indicates EINTR
  55. // should occur.
  56. //
  57. ssize_t
  58. TermInput(
  59. IN HANDLE cs,
  60. OUT LPSTR DestStr,
  61. IN DWORD cnt,
  62. IN int flags,
  63. OUT int *pError
  64. )
  65. {
  66. DWORD BytesRead = 0;
  67. BOOL bSuccess;
  68. BOOL StopInput = FALSE;
  69. CHAR *PDestStr = (CHAR *)DestStr;
  70. CHAR AsciiChar;
  71. //
  72. // Deal with non-blocking input. If canonical mode is set,
  73. // we return EAGAIN unless an entire line is available. If
  74. // canonical mode is not set, we return EAGAIN unless at least
  75. // one character is available.
  76. //
  77. if (flags & PSXSES_NONBLOCK) {
  78. if (SavedTermios.c_lflag & ICANON) {
  79. if (0 == LineCount) {
  80. *pError = EAGAIN;
  81. return -1;
  82. }
  83. } else {
  84. if (0 == KbdBufferCount) {
  85. *pError = EAGAIN;
  86. return -1;
  87. }
  88. }
  89. }
  90. //
  91. // Handle canonical input on consumer side: don't return until
  92. // an entire line is ready to return. We don't wait around to
  93. // accumulate a line if EOF has occured on input.
  94. //
  95. if ((SavedTermios.c_lflag & ICANON) && !InputEOF) {
  96. WaitForSingleObject(hCanonEvent, INFINITE);
  97. }
  98. if (SignalInterrupt) {
  99. EnterCriticalSection(&KbdBufMutex);
  100. if (SignalInterrupt) {
  101. SignalInterrupt = FALSE;
  102. LeaveCriticalSection(&KbdBufMutex);
  103. ResetEvent(hCanonEvent);
  104. *pError = EINTR;
  105. return -1;
  106. }
  107. LeaveCriticalSection(&KbdBufMutex);
  108. }
  109. if (0 == KbdBufferCount && InputEOF) {
  110. ResetEvent(hCanonEvent);
  111. ResetEvent(hIoEvent);
  112. InputEOF = FALSE;
  113. EnterCriticalSection(&KbdBufMutex);
  114. LineCount = 0;
  115. LeaveCriticalSection(&KbdBufMutex);
  116. *pError = 0;
  117. return 0;
  118. }
  119. while (BytesRead < cnt && !StopInput) {
  120. if (0 == KbdBufferCount && InputEOF) {
  121. ResetEvent(hCanonEvent);
  122. ResetEvent(hIoEvent);
  123. EnterCriticalSection(&KbdBufMutex);
  124. LeaveCriticalSection(&KbdBufMutex);
  125. *pError = 0;
  126. return BytesRead;
  127. }
  128. //
  129. // Wait for input queue to be non-empty
  130. //
  131. WaitForSingleObject(hIoEvent, INFINITE);
  132. EnterCriticalSection(&KbdBufMutex);
  133. DelKbdBuffer(&AsciiChar, 1);
  134. LeaveCriticalSection(&KbdBufMutex);
  135. if ((SavedTermios.c_lflag & ICANON) && '\n' == AsciiChar) {
  136. StopInput = TRUE;
  137. EnterCriticalSection(&KbdBufMutex);
  138. //
  139. // Only reset canonical processing event when there are NO
  140. // lines in input queue.
  141. //
  142. if (--LineCount == 0) {
  143. bSuccess = ResetEvent(hCanonEvent);
  144. ASSERT(bSuccess);
  145. }
  146. LeaveCriticalSection(&KbdBufMutex);
  147. }
  148. *PDestStr++ = AsciiChar;
  149. BytesRead++;
  150. //
  151. // XXX.mjb: In noncanonical mode, return even one character. This is a
  152. // fudge on the POSIX standard. Should consider MIN and TIME later.
  153. //
  154. // XXX.mjb: What if a character is removed from the buffer (by
  155. // backspace) between the time we check to see if there is one
  156. // and the time we call DelKbdBuffer? Could we end up waiting
  157. // on hIoEvent in non-canonical mode after characters have been
  158. // read?
  159. //
  160. if (!(SavedTermios.c_lflag & ICANON) && 0 == KbdBufferCount) {
  161. *pError = 0;
  162. return BytesRead;
  163. }
  164. }
  165. *pError = 0;
  166. return BytesRead;
  167. }
  168. //
  169. // BkspcKbdBuffer - do a backspace, removing a character from the
  170. // input buffer. Arrange for the character to be removed from
  171. // the display, if bEcho is set.
  172. //
  173. // bEcho - echo the character?
  174. //
  175. // Returns:
  176. //
  177. // TRUE if a character was removed from the buffer.
  178. // FALSE otherwise (maybe no chars left in line).
  179. //
  180. BOOL
  181. BkspcKbdBuffer(
  182. BOOLEAN bEcho
  183. )
  184. {
  185. char *kill_char;
  186. int prev_pos, i;
  187. if (bEcho) {
  188. kill_char = "\010 \010";
  189. } else {
  190. kill_char = "\010";
  191. }
  192. if (0 == KbdBufferCount) {
  193. /* Empty buffer */
  194. return FALSE;
  195. }
  196. if ('\n' == KbdBuffer[KbdBufferTail - 1]) {
  197. // bkspc should not erase beyond start of line.
  198. return FALSE;
  199. }
  200. KbdBufferCount--;
  201. if (KbdBufferTail == 0)
  202. KbdBufferTail = KBD_BUFFER_SIZE - 1;
  203. else
  204. KbdBufferTail--;
  205. if ('\t' == KbdBuffer[KbdBufferTail]) {
  206. int dif;
  207. --NumTabs;
  208. dif = TrackedCoord.X - TabMarkers[NumTabs];
  209. if (1 == TrackedCoord.X) {
  210. char buf[10];
  211. ULONG save;
  212. // bkspc over tab causes reverse wrap.
  213. save = OutputModeFlags;
  214. OutputModeFlags &= ~ENABLE_WRAP_AT_EOL_OUTPUT;
  215. sprintf(buf, "\x1b[%d;%dH", TrackedCoord.Y - 1,
  216. TabMarkers[NumTabs]);
  217. TermOutput(hConsoleOutput, buf, strlen(buf));
  218. OutputModeFlags = save;
  219. return TRUE;
  220. }
  221. for (i = 0; i < dif; ++i) {
  222. TermOutput(hConsoleOutput, "\010", 1);
  223. }
  224. return TRUE;
  225. }
  226. if (1 == TrackedCoord.X) {
  227. // remove a character that will cause a reverse wrap.
  228. char buf[10];
  229. ULONG save;
  230. // Disable wrap to make cursor positioning right.
  231. save = OutputModeFlags;
  232. OutputModeFlags &= ~ENABLE_WRAP_AT_EOL_OUTPUT;
  233. sprintf(buf, "\x1b[%d;%dH", TrackedCoord.Y - 1,
  234. ScreenColNum + 1);
  235. if (bEcho) {
  236. strcat(buf, " ");
  237. }
  238. TermOutput(hConsoleOutput, buf, strlen(buf));
  239. OutputModeFlags = save;
  240. return TRUE;
  241. }
  242. //
  243. // Remove an ordinary character.
  244. //
  245. TermOutput(hConsoleOutput, kill_char, 3);
  246. return TRUE;
  247. }
  248. //
  249. // KillKbdBuffer - execute a line-kill, removing the last line
  250. // from the input buffer. Arrange for the killed characters
  251. // to be removed from the display.
  252. //
  253. // Returns:
  254. //
  255. // TRUE if some characters were killed.
  256. // FALSE otherwise.
  257. //
  258. BOOL
  259. KillKbdBuffer(
  260. VOID
  261. )
  262. {
  263. BOOLEAN bEchoK;
  264. if (0 == KbdBufferCount) {
  265. /* Empty buffer */
  266. return FALSE;
  267. }
  268. if ('\n' == KbdBuffer[KbdBufferTail - 1]) {
  269. // kill should not erase beyond start of line.
  270. return FALSE;
  271. }
  272. bEchoK = ((SavedTermios.c_lflag & ECHOK) == ECHOK);
  273. while (BkspcKbdBuffer(bEchoK))
  274. ;
  275. return TRUE;
  276. }
  277. //
  278. // AddKbdBuffer -- add a character to the input queue.
  279. //
  280. // Characters have been typed, and they should be added to the
  281. // input queue.
  282. //
  283. //
  284. BOOL
  285. AddKbdBuffer(
  286. PCHAR Buf,
  287. int Cnt
  288. )
  289. {
  290. CHAR *pc, *pcLast;
  291. char *kill_char = "\010 \010";
  292. int prev_pos, i;
  293. for (pc = Buf, pcLast = Buf + Cnt; pc < pcLast; pc++) {
  294. if (KbdBufferCount == KBD_BUFFER_SIZE) {
  295. KdPrint(("PSXSES: keyboard buffer overflowed\n"));
  296. return FALSE;
  297. }
  298. KbdBuffer[KbdBufferTail] = *pc;
  299. KbdBufferCount++;
  300. if ('\t' == *pc) {
  301. //
  302. // The user has input a tab. We save the screen position
  303. // of the character
  304. //
  305. TabMarkers[NumTabs++] = TrackedCoord.X;
  306. }
  307. if (++KbdBufferTail == KBD_BUFFER_SIZE)
  308. KbdBufferTail = 0;
  309. if (KbdBufferCount == 1 && !SetEvent(hIoEvent)) {
  310. KdPrint(("PSXSES: failed to set input synch event: 0x%x\n",
  311. GetLastError()));
  312. }
  313. }
  314. return TRUE;
  315. }
  316. INT
  317. DelKbdBuffer(CHAR *CharBuf, DWORD CharCnt)
  318. {
  319. CHAR *AsciiChar, *LastChar;
  320. for ( AsciiChar = CharBuf, LastChar = (CharBuf + CharCnt);
  321. AsciiChar < LastChar; AsciiChar++ ) {
  322. if ( !KbdBufferCount ) { /* Empty buffer */
  323. return (FALSE);
  324. }
  325. *AsciiChar = KbdBuffer[KbdBufferHead];
  326. KbdBufferCount--;
  327. if ( ++KbdBufferHead == KBD_BUFFER_SIZE )
  328. KbdBufferHead = 0;
  329. /* Buffer becomes empty */
  330. if ( !KbdBufferCount && !ResetEvent(hIoEvent) ) {
  331. KdPrint(("PSXSES: failed to reset input synch event\n"));
  332. }
  333. } /* for */
  334. return (TRUE);
  335. }
  336. //
  337. // ServeKbdInput --
  338. //
  339. // Run as a separate thread for asynchronous console input.
  340. // Get keydown events from the console window and fill the keyboard
  341. // buffer structure with ASCII values
  342. //
  343. VOID
  344. ServeKbdInput(LPVOID Unused)
  345. {
  346. BOOL bSuccess;
  347. BOOL BackSpaceFound = FALSE;
  348. BOOL LineKillFound = FALSE;
  349. BOOL bSignalInterrupt = FALSE;
  350. INPUT_RECORD inputBuffer[INPUT_EVENT_CLUSTER];
  351. PKEY_EVENT_RECORD pKeyEvent;
  352. DWORD dwEventsRead; /* number of events actually read */
  353. UCHAR LocalBuf[10], AsciiChar;
  354. int LocalCnt;
  355. LPDWORD count;
  356. DWORD i;
  357. for (;;) {
  358. bSuccess = ReadConsoleInput(hConsoleInput, inputBuffer,
  359. INPUT_EVENT_CLUSTER, &dwEventsRead);
  360. if (!bSuccess) {
  361. KdPrint(("posix: ReadConsoleInput: 0x%x\n", GetLastError()));
  362. ExitThread(1);
  363. }
  364. for (i = 0; i < dwEventsRead; i++) {
  365. LocalCnt = 0;
  366. BackSpaceFound = FALSE;
  367. LineKillFound = FALSE;
  368. if (inputBuffer[i].EventType != KEY_EVENT) {
  369. continue;
  370. }
  371. pKeyEvent = &inputBuffer[i].Event.KeyEvent;
  372. if (!pKeyEvent->bKeyDown) {
  373. //
  374. // Only interested in key-down events.
  375. //
  376. continue;
  377. }
  378. //
  379. // Map a Key event to one or more ASCII characters,
  380. // in local buffer. AsciiChar should be maintained
  381. // as last char typed.
  382. //
  383. AsciiChar = pKeyEvent->uChar.AsciiChar;
  384. // pKeyEvent->wRepeatCount
  385. switch (pKeyEvent->wVirtualKeyCode) {
  386. case VK_SHIFT:
  387. case VK_CONTROL:
  388. case VK_MENU:
  389. case VK_CAPITAL:
  390. case VK_NUMLOCK:
  391. case VK_SCROLL:
  392. //
  393. // We're not interested in the fact that one
  394. // of these keys has been pressed; we'll deal
  395. // with them later as a modifier on a normal
  396. // key press.
  397. //
  398. continue;
  399. case VK_DELETE:
  400. AsciiChar = CTRL('?');
  401. break;
  402. case VK_F1:
  403. LocalBuf[LocalCnt++] = (UCHAR)'\200';
  404. AsciiChar = '\073';
  405. break;
  406. case VK_F2:
  407. LocalBuf[LocalCnt++] = (UCHAR)'\200';
  408. AsciiChar = '\074';
  409. break;
  410. case VK_F3:
  411. LocalBuf[LocalCnt++] = (UCHAR)'\200';
  412. AsciiChar = '\075';
  413. break;
  414. case VK_F4:
  415. LocalBuf[LocalCnt++] = (UCHAR)'\200';
  416. AsciiChar = '\076';
  417. break;
  418. case VK_F5:
  419. LocalBuf[LocalCnt++] = (UCHAR)'\200';
  420. AsciiChar = '\077';
  421. break;
  422. case VK_F6:
  423. LocalBuf[LocalCnt++] = (UCHAR)'\200';
  424. AsciiChar = '\100';
  425. break;
  426. case VK_F7:
  427. LocalBuf[LocalCnt++] = (UCHAR)'\200';
  428. AsciiChar = '\101';
  429. break;
  430. case VK_F8:
  431. LocalBuf[LocalCnt++] = (UCHAR)'\200';
  432. AsciiChar = '\102';
  433. break;
  434. case VK_F9:
  435. LocalBuf[LocalCnt++] = (UCHAR)'\200';
  436. AsciiChar = '\103';
  437. break;
  438. case VK_F10:
  439. LocalBuf[LocalCnt++] = (UCHAR)'\200';
  440. AsciiChar = '\104';
  441. break;
  442. case VK_LEFT:
  443. LocalBuf[LocalCnt++] = ANSI_ESC;
  444. LocalBuf[LocalCnt++] = '[';
  445. AsciiChar = 'D';
  446. break;
  447. case VK_UP:
  448. LocalBuf[LocalCnt++] = ANSI_ESC;
  449. LocalBuf[LocalCnt++] = '[';
  450. AsciiChar = 'A';
  451. break;
  452. case VK_RIGHT:
  453. LocalBuf[LocalCnt++] = ANSI_ESC;
  454. LocalBuf[LocalCnt++] = '[';
  455. AsciiChar = 'C';
  456. break;
  457. case VK_DOWN:
  458. LocalBuf[LocalCnt++] = ANSI_ESC;
  459. LocalBuf[LocalCnt++] = '[';
  460. AsciiChar = 'B';
  461. break;
  462. default:
  463. break;
  464. }
  465. if (pKeyEvent->dwControlKeyState &
  466. (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
  467. //
  468. // Convert Control + key to ^key.
  469. //
  470. AsciiChar = CTRL(AsciiChar);
  471. }
  472. if (SavedTermios.c_iflag & ISTRIP) {
  473. //
  474. // XXX.mjb: not sure if we should strip here or after
  475. // special character processing.
  476. //
  477. AsciiChar &= 0x7F;
  478. }
  479. if ((SavedTermios.c_iflag & IXOFF) ||
  480. (SavedTermios.c_iflag & IXON)) {
  481. if (AsciiChar == SavedTermios.c_cc[VSTOP]) {
  482. EnterCriticalSection(&StopMutex);
  483. bStop = TRUE;
  484. ResetEvent(hStopEvent);
  485. LeaveCriticalSection(&StopMutex);
  486. goto discard;
  487. }
  488. if (AsciiChar == SavedTermios.c_cc[VSTART]) {
  489. EnterCriticalSection(&StopMutex);
  490. bStop = FALSE;
  491. SetEvent(hStopEvent);
  492. LeaveCriticalSection(&StopMutex);
  493. goto discard;
  494. }
  495. }
  496. if (SavedTermios.c_lflag & ISIG) {
  497. if (AsciiChar == SavedTermios.c_cc[VINTR] &&
  498. SavedTermios.c_cc[VINTR] != _POSIX_VDISABLE) {
  499. //
  500. // Send an interrupt to all processes in the
  501. // foreground process group
  502. //
  503. bSignalInterrupt = TRUE;
  504. SignalSession(PSX_SIGINT);
  505. goto discard;
  506. }
  507. if (AsciiChar == SavedTermios.c_cc[VSUSP] &&
  508. SavedTermios.c_cc[VSUSP] != _POSIX_VDISABLE) {
  509. SignalSession(PSX_SIGTSTP);
  510. bSignalInterrupt = TRUE;
  511. goto discard;
  512. }
  513. if (AsciiChar == SavedTermios.c_cc[VQUIT] &&
  514. SavedTermios.c_cc[VQUIT] != _POSIX_VDISABLE) {
  515. SignalSession(PSX_SIGQUIT);
  516. bSignalInterrupt = TRUE;
  517. goto discard;
  518. }
  519. }
  520. if (SavedTermios.c_lflag & ICANON) {
  521. if (AsciiChar == CR) {
  522. if ((SavedTermios.c_iflag & ICRNL) &&
  523. !(SavedTermios.c_iflag & IGNCR)) {
  524. AsciiChar = NL;
  525. }
  526. }
  527. if (AsciiChar == NL) {
  528. if (SavedTermios.c_iflag & INLCR) {
  529. AsciiChar = CR;
  530. //XXX.mjb: process this CR?
  531. }
  532. }
  533. if (AsciiChar == SavedTermios.c_cc[VKILL] &&
  534. SavedTermios.c_cc[VKILL] != _POSIX_VDISABLE) {
  535. LineKillFound = TRUE;
  536. goto discard;
  537. }
  538. if (AsciiChar == SavedTermios.c_cc[VERASE] &&
  539. SavedTermios.c_cc[VERASE] != _POSIX_VDISABLE) {
  540. // character erase
  541. BackSpaceFound = TRUE;
  542. goto discard;
  543. }
  544. if (AsciiChar == SavedTermios.c_cc[VEOF] &&
  545. SavedTermios.c_cc[VEOF] != _POSIX_VDISABLE) {
  546. // End of file.
  547. AsciiChar = '\n'; // force end-of-line
  548. InputEOF = TRUE;
  549. goto discard;
  550. }
  551. if (AsciiChar == SavedTermios.c_cc[VEOL] &&
  552. SavedTermios.c_cc[VEOL] != _POSIX_VDISABLE) {
  553. // End of line.
  554. AsciiChar = '\n'; // force end-of-line
  555. }
  556. }
  557. LocalBuf[LocalCnt++] = AsciiChar;
  558. discard:
  559. EnterCriticalSection(&KbdBufMutex);
  560. if (BackSpaceFound) {
  561. BOOLEAN bEchoE = ((SavedTermios.c_lflag & ECHOE) == ECHOE);
  562. BkspcKbdBuffer(bEchoE);
  563. } else if (LineKillFound) {
  564. KillKbdBuffer();
  565. } else {
  566. AddKbdBuffer(LocalBuf, LocalCnt);
  567. }
  568. if (SavedTermios.c_lflag & ECHO) {
  569. TermOutput(hConsoleOutput, LocalBuf, LocalCnt);
  570. }
  571. if (bSignalInterrupt || InputEOF) {
  572. //
  573. // Blocked reads should be unblocked, to return
  574. // either the data that has been accumulated (EOF)
  575. // or EINTR (Signal)
  576. //
  577. SignalInterrupt = bSignalInterrupt;
  578. bSuccess = SetEvent(hCanonEvent);
  579. ASSERT(bSuccess);
  580. bSuccess = SetEvent(hIoEvent);
  581. ASSERT(bSuccess);
  582. bSignalInterrupt = FALSE;
  583. }
  584. if (AsciiChar == '\n' && (SavedTermios.c_lflag & ICANON)
  585. && ++LineCount == 1) {
  586. //
  587. // If we've just finished a new line, signal any
  588. // readers who were waiting on a complete line.
  589. //
  590. bSuccess = SetEvent(hCanonEvent);
  591. ASSERT(bSuccess);
  592. // Reset the keeping-track of tabs.
  593. NumTabs = 0;
  594. }
  595. LeaveCriticalSection(&KbdBufMutex);
  596. }
  597. }
  598. }