slw32tty.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /* Copyright (c) 1992, 1999, 2001, 2002, 2003 John E. Davis
  2. * This file is part of the S-Lang library.
  3. *
  4. * You may distribute under the terms of either the GNU General Public
  5. * License or the Perl Artistic License.
  6. */
  7. #include "slinclud.h"
  8. #include <windows.h>
  9. #include <winbase.h>
  10. #include "slang.h"
  11. #include "_slang.h"
  12. #ifdef __cplusplus
  13. # define _DOTS_ ...
  14. #else
  15. # define _DOTS_ void
  16. #endif
  17. static int Process_Mouse_Events;
  18. /*----------------------------------------------------------------------*\
  19. * Function: static void set_ctrl_break (int state);
  20. *
  21. * set the control-break setting
  22. \*----------------------------------------------------------------------*/
  23. static void set_ctrl_break (int state)
  24. {
  25. }
  26. /*----------------------------------------------------------------------*\
  27. * Function: int SLang_init_tty (int abort_char, int no_flow_control,
  28. * int opost);
  29. *
  30. * initialize the keyboard interface and attempt to set-up the interrupt 9
  31. * handler if ABORT_CHAR is non-zero.
  32. * NO_FLOW_CONTROL and OPOST are only for compatiblity and are ignored.
  33. \*----------------------------------------------------------------------*/
  34. HANDLE _SLw32_Hstdin = INVALID_HANDLE_VALUE;
  35. int SLang_init_tty (int abort_char, int no_flow_control, int opost)
  36. {
  37. (void) opost;
  38. (void) no_flow_control;
  39. if (_SLw32_Hstdin != INVALID_HANDLE_VALUE)
  40. return 0;
  41. #if 1
  42. /* stdin may have been redirected. So try this */
  43. _SLw32_Hstdin = CreateFile ("CONIN$", GENERIC_READ|GENERIC_WRITE,
  44. FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
  45. OPEN_EXISTING, 0, NULL);
  46. if (_SLw32_Hstdin == INVALID_HANDLE_VALUE)
  47. return -1;
  48. #else
  49. if (INVALID_HANDLE_VALUE == (_SLw32_Hstdin = GetStdHandle(STD_INPUT_HANDLE)))
  50. return -1;
  51. #endif
  52. if (FALSE == SetConsoleMode(_SLw32_Hstdin, ENABLE_WINDOW_INPUT|ENABLE_MOUSE_INPUT))
  53. {
  54. _SLw32_Hstdin = INVALID_HANDLE_VALUE;
  55. return -1;
  56. }
  57. if (abort_char > 0)
  58. SLang_Abort_Char = abort_char;
  59. return 0;
  60. }
  61. /* SLang_init_tty */
  62. /*----------------------------------------------------------------------*\
  63. * Function: void SLang_reset_tty (void);
  64. *
  65. * reset the tty before exiting
  66. \*----------------------------------------------------------------------*/
  67. void SLang_reset_tty (void)
  68. {
  69. _SLw32_Hstdin = INVALID_HANDLE_VALUE;
  70. set_ctrl_break (1);
  71. }
  72. static int process_mouse_event (MOUSE_EVENT_RECORD *m)
  73. {
  74. char buf [8];
  75. if (Process_Mouse_Events == 0)
  76. return -1;
  77. if (m->dwEventFlags)
  78. return -1; /* double click or movement event */
  79. /* A button was either pressed or released. Now make sure that
  80. * the shift keys were not also pressed.
  81. */
  82. if (m->dwControlKeyState
  83. & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED
  84. |LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED
  85. |SHIFT_PRESSED))
  86. return -1;
  87. /* We have a simple press or release. Encode it as an escape sequence
  88. * and buffer the result. The encoding is:
  89. * 'ESC [ M b x y'
  90. * where b represents the button state, and x,y represent the coordinates.
  91. * The ESC is handled by the calling routine.
  92. */
  93. if (m->dwButtonState & 1) buf[3] = ' ';
  94. else if (m->dwButtonState & 2) buf[3] = ' ' + 2;
  95. else if (m->dwButtonState & 4) buf[3] = ' ' + 1;
  96. else return -1;
  97. buf[0] = 27;
  98. buf[1] = '[';
  99. buf[2] = 'M';
  100. buf[4] = 1 + ' ' + m->dwMousePosition.X;
  101. buf[5] = 1 + ' ' + m->dwMousePosition.Y;
  102. return SLang_buffer_keystring ((unsigned char *)buf, 6);
  103. }
  104. static int process_key_event (KEY_EVENT_RECORD *key)
  105. {
  106. unsigned int key_state = 0;
  107. unsigned int scan;
  108. char c1;
  109. DWORD d = key->dwControlKeyState;
  110. unsigned char buf[4];
  111. if (!key->bKeyDown) return 0;
  112. if (d & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
  113. key_state |= _SLTT_KEY_ALT;
  114. if (d & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
  115. key_state |= _SLTT_KEY_CTRL;
  116. if (d & SHIFT_PRESSED)
  117. key_state |= _SLTT_KEY_SHIFT;
  118. scan = key->wVirtualScanCode;
  119. switch (scan)
  120. {
  121. case 0x00E: /* backspace */
  122. return SLang_buffer_keystring ((unsigned char *)"\x7F", 1);
  123. case 0x003: /* 2 key */
  124. if (key_state & _SLTT_KEY_ALT)
  125. break;
  126. /* Drop */
  127. case 0x039: /* space */
  128. if (key_state & _SLTT_KEY_CTRL)
  129. return SLang_buffer_keystring ((unsigned char *)"\x00\x03", 2);
  130. break;
  131. case 0x007: /* 6 key */
  132. if (_SLTT_KEY_CTRL == (key_state & (_SLTT_KEY_ALT|_SLTT_KEY_CTRL)))
  133. return SLang_buffer_keystring ((unsigned char *)"\x1E", 1); /* Ctrl-^ */
  134. break;
  135. case 0x00C: /* -/_ key */
  136. if (_SLTT_KEY_CTRL == (key_state & (_SLTT_KEY_ALT|_SLTT_KEY_CTRL)))
  137. return SLang_buffer_keystring ((unsigned char *)"\x1F", 1);
  138. break;
  139. case 0x00F: /* TAB */
  140. if (_SLTT_KEY_SHIFT == key_state)
  141. return SLang_buffer_keystring ((unsigned char *)"\x00\x09", 2);
  142. break;
  143. case 0xE02F: /* KEYPAD SLASH */
  144. case 0x037: /* KEYPAD STAR */
  145. case 0x04A: /* KEYPAD MINUS */
  146. case 0x04E: /* KEYPAD PLUS */
  147. if (d & NUMLOCK_ON)
  148. break;
  149. case 0x047: /* KEYPAD HOME */
  150. case 0x048: /* KEYPAD UP */
  151. case 0x049: /* KEYPAD PGUP */
  152. case 0x04B: /* KEYPAD LEFT */
  153. case 0x04C: /* KEYPAD 5 */
  154. case 0x04D: /* KEYPAD RIGHT */
  155. case 0x04F: /* KEYPAD END */
  156. case 0x050: /* KEYPAD DOWN */
  157. case 0x051: /* KEYPAD PGDN */
  158. case 0x052: /* KEYPAD INSERT */
  159. case 0x053: /* KEYPAD DEL */
  160. if (d & ENHANCED_KEY)
  161. scan |= 0xE000;
  162. else
  163. {
  164. if (d & NUMLOCK_ON)
  165. break;
  166. }
  167. (void) _SLpc_convert_scancode (scan, key_state, 0);
  168. return 0;
  169. case 0x3b: /* F1 */
  170. case 0x3c:
  171. case 0x3d:
  172. case 0x3e:
  173. case 0x3f:
  174. case 0x40:
  175. case 0x41:
  176. case 0x42:
  177. case 0x43:
  178. case 0x44:
  179. case 0x57:
  180. case 0x58: /* F12 */
  181. (void) _SLpc_convert_scancode (scan, key_state, 0);
  182. }
  183. c1 = key->uChar.AsciiChar;
  184. if (c1 != 0)
  185. {
  186. if (_SLTT_KEY_ALT == (key_state & (_SLTT_KEY_ALT|_SLTT_KEY_CTRL)))
  187. {
  188. buf[0] = 27;
  189. buf[1] = c1;
  190. return SLang_buffer_keystring (buf, 2);
  191. }
  192. if (c1 == SLang_Abort_Char)
  193. {
  194. if (SLang_Ignore_User_Abort == 0) SLang_Error = USER_BREAK;
  195. SLKeyBoard_Quit = 1;
  196. }
  197. buf[0] = c1;
  198. return SLang_buffer_keystring (buf, 1);
  199. }
  200. return 0;
  201. }
  202. static void process_console_records(void)
  203. {
  204. INPUT_RECORD record;
  205. DWORD bytesRead;
  206. DWORD n = 0;
  207. if (FALSE == GetNumberOfConsoleInputEvents(_SLw32_Hstdin, &n))
  208. return;
  209. while (n > 0)
  210. {
  211. ReadConsoleInput(_SLw32_Hstdin, &record, 1, &bytesRead);
  212. switch (record.EventType)
  213. {
  214. case KEY_EVENT:
  215. (void) process_key_event(&record.Event.KeyEvent);
  216. break;
  217. case MOUSE_EVENT:
  218. process_mouse_event(&record.Event.MouseEvent);
  219. break;
  220. case WINDOW_BUFFER_SIZE_EVENT:
  221. /* process_resize_records(&record.Event.WindowBufferSizeEvent); */
  222. break;
  223. }
  224. n--;
  225. }
  226. }
  227. /*----------------------------------------------------------------------*\
  228. * Function: int _SLsys_input_pending (int tsecs);
  229. *
  230. * sleep for *tsecs tenths of a sec waiting for input
  231. \*----------------------------------------------------------------------*/
  232. int _SLsys_input_pending (int tsecs)
  233. {
  234. long ms;
  235. if (_SLw32_Hstdin == INVALID_HANDLE_VALUE)
  236. return -1;
  237. if (tsecs < 0) ms = -tsecs; /* specifies 1/1000 */
  238. else ms = tsecs * 100L; /* convert 1/10 to 1/1000 secs */
  239. process_console_records ();
  240. while ((ms > 0)
  241. && (SLang_Input_Buffer_Len == 0))
  242. {
  243. long t;
  244. t = GetTickCount ();
  245. (void) WaitForSingleObject (_SLw32_Hstdin, ms);
  246. process_console_records ();
  247. ms -= GetTickCount () - t;
  248. }
  249. return SLang_Input_Buffer_Len;
  250. }
  251. /*----------------------------------------------------------------------*\
  252. * Function: unsigned int _SLsys_getkey (void);
  253. *
  254. * wait for and get the next available keystroke.
  255. * Also re-maps some useful keystrokes.
  256. *
  257. * Backspace (^H) => Del (127)
  258. * Ctrl-Space => ^@ (^@^3 - a pc NUL char)
  259. * extended keys are prefixed by a null character
  260. \*----------------------------------------------------------------------*/
  261. unsigned int _SLsys_getkey (void)
  262. {
  263. /* Check the input buffer because _SLsys_input_pending may have been
  264. * called prior to this to stuff the input buffer.
  265. */
  266. if (SLang_Input_Buffer_Len)
  267. return SLang_getkey ();
  268. if (_SLw32_Hstdin == INVALID_HANDLE_VALUE)
  269. return SLANG_GETKEY_ERROR;
  270. while (1)
  271. {
  272. int status;
  273. if (SLKeyBoard_Quit)
  274. return SLang_Abort_Char;
  275. status = _SLsys_input_pending (600);
  276. if (status == -1)
  277. return SLANG_GETKEY_ERROR;
  278. if (status > 0)
  279. return SLang_getkey ();
  280. }
  281. }
  282. /*----------------------------------------------------------------------*\
  283. * Function: int SLang_set_abort_signal (void (*handler)(int));
  284. \*----------------------------------------------------------------------*/
  285. int SLang_set_abort_signal (void (*handler)(int))
  286. {
  287. if (_SLw32_Hstdin == INVALID_HANDLE_VALUE)
  288. return -1;
  289. return 0;
  290. }
  291. int SLtt_set_mouse_mode (int mode, int force)
  292. {
  293. (void) force;
  294. Process_Mouse_Events = mode;
  295. return 0;
  296. }