Leaked source code of windows server 2003
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.

459 lines
10 KiB

  1. /* File: D:\WACKER\tdll\getchar.c (Created: 30-Nov-1993)
  2. *
  3. * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
  4. * All rights reserved
  5. *
  6. * $Revision: 6 $
  7. * $Date: 3/14/02 3:45p $
  8. */
  9. #include <windows.h>
  10. #pragma hdrstop
  11. //#define DEBUGSTR
  12. #include <time.h>
  13. #include <stdio.h>
  14. #include "stdtyp.h"
  15. #include "globals.h"
  16. #include "session.h"
  17. #include "term.h"
  18. #include "chars.h"
  19. #include "assert.h"
  20. #include "statusbr.h"
  21. #include "cloop.h"
  22. #include "cnct.h"
  23. #include "htchar.h"
  24. #if defined(INCL_KEY_MACROS)
  25. #include "keyutil.h"
  26. #endif
  27. #include <emu\emu.h>
  28. #include <term\res.h>
  29. static BOOL WackerKeys(const KEY_T Key);
  30. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  31. * FUNCTION:
  32. * TranslateToKey
  33. *
  34. * DESCRIPTION:
  35. * Translates a key into our internal format. Waits for the WM_CHAR if
  36. * windows is going to translate the key by checking the message queue.
  37. *
  38. * ARGUMENTS:
  39. * hSession - external session handle
  40. * pmsg - pointer to message
  41. *
  42. * RETURNS:
  43. * Internal key value if translated, otherwise 0.
  44. *
  45. */
  46. KEY_T TranslateToKey(const LPMSG pmsg)
  47. {
  48. KEY_T Key = 0;
  49. switch (pmsg->message)
  50. {
  51. case WM_KEYDOWN:
  52. case WM_SYSKEYDOWN:
  53. switch (pmsg->wParam)
  54. {
  55. case VK_SHIFT:
  56. case VK_CONTROL:
  57. return 0;
  58. case VK_MENU:
  59. return (KEY_T)-1;
  60. default:
  61. Key = (KEY_T)(VIRTUAL_KEY | pmsg->wParam);
  62. if (GetKeyState(VK_MENU) < 0)
  63. Key |= ALT_KEY;
  64. if (GetKeyState(VK_CONTROL) < 0)
  65. Key |= CTRL_KEY;
  66. if (GetKeyState(VK_SHIFT) < 0)
  67. Key |= SHIFT_KEY;
  68. if (pmsg->lParam & 0x01000000) /* Extended, bit 24 */
  69. Key |= EXTENDED_KEY;
  70. break;
  71. }
  72. break;
  73. case WM_CHAR:
  74. case WM_SYSCHAR:
  75. Key = (KEY_T)pmsg->wParam;
  76. if (pmsg->lParam & 0x01000000) /* Extended, bit 24 */
  77. Key |= EXTENDED_KEY;
  78. if (pmsg->lParam & 0x20000000) /* Context, bit 29 */
  79. Key |= ALT_KEY;
  80. if (pmsg->wParam == VK_TAB)
  81. {
  82. if (GetKeyState(VK_SHIFT) < 0)
  83. {
  84. Key |= SHIFT_KEY;
  85. Key |= VIRTUAL_KEY;
  86. }
  87. }
  88. // Believe it or not CTRL+SHIFT+@ gets translated to a
  89. // char of 0 (zero). So virtualize the key if it matches
  90. // the criteria. - mrw
  91. //
  92. if (pmsg->wParam == 0)
  93. {
  94. if (GetKeyState(VK_SHIFT) < 0 && GetKeyState(VK_CONTROL) < 0)
  95. Key |= VIRTUAL_KEY | SHIFT_KEY | CTRL_KEY;
  96. }
  97. break;
  98. default:
  99. break;
  100. }
  101. DbgOutStr("%x %x\r\n", Key, pmsg->message, 0, 0, 0);
  102. return Key;
  103. }
  104. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  105. * FUNCTION:
  106. * WackerKeys
  107. *
  108. * DESCRIPTION:
  109. * Handles our special global keys.
  110. *
  111. * ARGUMENTS:
  112. * Key - key from TranslateToKey()
  113. *
  114. * RETURNS:
  115. * TRUE if this routine acts on it, FALSE if not.
  116. *
  117. */
  118. static BOOL WackerKeys(const KEY_T Key)
  119. {
  120. BYTE pbKeyState[256];
  121. switch (Key)
  122. {
  123. case VIRTUAL_KEY | VK_SCROLL:
  124. case VIRTUAL_KEY | SHIFT_KEY | VK_SCROLL:
  125. case VIRTUAL_KEY | ALT_KEY | VK_SCROLL:
  126. case VIRTUAL_KEY | ALT_KEY | SHIFT_KEY | VK_SCROLL:
  127. // In the case of scroll lock, we want to toggle to the
  128. // previous state. Only when it is destined for the terminal
  129. // window is it processed meaning it doesn't get here.
  130. if(GetKeyboardState(pbKeyState))
  131. {
  132. if (GetKeyState(VK_SCROLL) & 1)
  133. {
  134. pbKeyState[VK_SCROLL] &= ~0x01;
  135. }
  136. else
  137. {
  138. pbKeyState[VK_SCROLL] |= 0x01;
  139. }
  140. SetKeyboardState(pbKeyState);
  141. }
  142. #if TODO // TODO:REV 3/1/2002 Set the ScrollLock key state when GetKeyboardState fails.
  143. else
  144. {
  145. SHORT lScrollKeyState = GetKeyState(VK_SCROLL);
  146. if (lScrollKeyState & 1)
  147. {
  148. lScrollKeyState &= ~0x01;
  149. }
  150. else
  151. {
  152. lScrollKeyState |= 0x01;
  153. }
  154. if (lScrollKeyState)
  155. {
  156. INPUT lInput;
  157. lInput.ki =
  158. SendInput(1, lInput, sizeof(INPUT));
  159. }
  160. }
  161. #endif // TODO:REV 3/1/2002
  162. break;
  163. default:
  164. return FALSE;
  165. }
  166. return TRUE;
  167. }
  168. //******************************************************************************
  169. // Method:
  170. // IsSessionMacroKey
  171. //
  172. // Description:
  173. // Determines if the specified key is a user defined macro key
  174. //
  175. // Arguments:
  176. // hSess - Session handle
  177. // Key - The key to be tested
  178. //
  179. // Returns:
  180. // TRUE if the key is defined as a macro FALSE otherwise
  181. //
  182. // Throws:
  183. // None
  184. //
  185. // Author: Dwayne M. Newsome, 06/10/1998
  186. //
  187. //
  188. static BOOL IsSessionMacroKey(const HSESSION hSess, const KEY_T Key)
  189. {
  190. #if defined INCL_KEY_MACROS
  191. keyMacro lKeyMacro;
  192. lKeyMacro.keyName = Key;
  193. return keysFindMacro( &lKeyMacro ) == -1 ? FALSE : TRUE;
  194. #else
  195. return FALSE;
  196. #endif
  197. }
  198. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  199. * FUNCTION:
  200. * ProcessMessage
  201. *
  202. * DESCRIPTION:
  203. * Despite the apparent simplicity of this function it is any but simple.
  204. * The entire functionality of the keyboard interface rests upon this
  205. * function. Handle with care!
  206. *
  207. * ARGUMENTS:
  208. * pmsg - pointer to message struct returned from GetMessage()
  209. *
  210. * RETURNS:
  211. * void
  212. *
  213. */
  214. void ProcessMessage(MSG *pmsg)
  215. {
  216. #if defined(FAR_EAST)
  217. static KEY_T keyLeadByte = 0;
  218. #endif
  219. KEY_T Key;
  220. HSESSION hSession;
  221. HCNCT hCnct;
  222. TCHAR achClassName[20];
  223. switch (pmsg->message)
  224. {
  225. case WM_CHAR:
  226. #if defined(FAR_EAST)
  227. hSession = (HSESSION)GetWindowLongPtr(pmsg->hwnd, 0);
  228. if ((IsDBCSLeadByte( (BYTE) pmsg->wParam)) && (keyLeadByte == 0))
  229. {
  230. keyLeadByte = (KEY_T)pmsg->wParam;
  231. return ;
  232. }
  233. else
  234. {
  235. if (keyLeadByte != 0)
  236. {
  237. Key = (KEY_T)pmsg->wParam;
  238. CLoopSend(sessQueryCLoopHdl(hSession), &keyLeadByte, 1, CLOOP_KEYS);
  239. CLoopSend(sessQueryCLoopHdl(hSession), &Key, 1, CLOOP_KEYS);
  240. keyLeadByte = 0;
  241. return ;
  242. }
  243. keyLeadByte = 0;
  244. }
  245. #endif
  246. case WM_KEYDOWN:
  247. case WM_SYSKEYDOWN:
  248. case WM_SYSCHAR:
  249. /* --- Translate the key to our format --- */
  250. Key = TranslateToKey(pmsg);
  251. // We need to decide if the window this message is going to is
  252. // a terminal window since that's the only place we do our
  253. // translations. We check if the window class matches our
  254. // terminal class. If so, the session handle is stored in the
  255. // 0 offset of the window's extra data. This way multiple sessions
  256. // can be serviced from this one routine.
  257. if (GetClassName(pmsg->hwnd, achClassName, sizeof(achClassName)) == 0)
  258. break;
  259. if (StrCharCmp(achClassName, TERM_CLASS))
  260. break;
  261. hSession = (HSESSION)GetWindowLongPtr(pmsg->hwnd, 0);
  262. if (hSession == 0)
  263. {
  264. // There are certain keys we want to handle regardless of
  265. // their destination.
  266. if (WackerKeys(Key))
  267. return;
  268. break;
  269. }
  270. // We need to prevent an F1 key event from initiating
  271. // a connection when "emu keys" is turned on.
  272. //
  273. if (Key == (VIRTUAL_KEY | VK_F1))
  274. {
  275. hCnct = sessQueryCnctHdl(hSession);
  276. assert(hCnct);
  277. if((cnctQueryStatus(hCnct) == CNCT_STATUS_TRUE) &&
  278. emuIsEmuKey(sessQueryEmuHdl(hSession), Key))
  279. {
  280. // do nothing - fall through
  281. }
  282. else
  283. {
  284. // eat it
  285. // We handle the F1 key event in the terminal proc
  286. // (to bring up help), so we don't need to here.
  287. return;
  288. }
  289. }
  290. // The order of evaluation is important here. Both IsMacroKey()
  291. // and emuIsEmuKey() know if that the message is bound for the
  292. // terminal. Also emuIsEmuKey() checks if terminal keys are
  293. // enabled. Evaluating messages in this order keeps us from
  294. // having to "disable" accelerators when the user defines macro
  295. // or terminal keys that conflict with accelerator keys.
  296. if ( IsSessionMacroKey(hSession, Key) ||
  297. emuIsEmuKey(sessQueryEmuHdl(hSession), Key))
  298. {
  299. // We need to modify this message to an internal message
  300. // for two reasons.
  301. //
  302. // 1. Menu accelerators get translated in DispatchMessage().
  303. // This seems a little strange but hey, that's windows
  304. // for ya.
  305. //
  306. // 2. It's important to know if the key was an emulator key.
  307. // The emulator's keys take precedence over window's
  308. // accelerators yet the emulator is the last guy to see
  309. // the key. For instance, PageUp can pageup through the
  310. // backscroll execept when it is mapped to an emulator
  311. // key. Unfortuanately, the PageUp key is interperted
  312. // by the client-terminal before being passed to the
  313. // emulator. If we sent this as a WM_KEYDOWN or WM_CHAR
  314. // message, we would have to play it through the emulator
  315. // again to find out if it is an emulator key.
  316. pmsg->message = WM_TERM_KEY;
  317. pmsg->wParam = (WPARAM)Key;
  318. DbgOutStr("Session or Macro key\r\n", 0, 0, 0, 0, 0);
  319. DispatchMessage(pmsg);
  320. if (Key == (VK_NUMLOCK | VIRTUAL_KEY | EXTENDED_KEY))
  321. {
  322. static BYTE abKeyState[256];
  323. if (GetKeyboardState(abKeyState))
  324. {
  325. if ((GetKeyState(VK_NUMLOCK) & 1))
  326. {
  327. abKeyState[VK_NUMLOCK] &= 0xfe;
  328. }
  329. else
  330. {
  331. abKeyState[VK_NUMLOCK] |= 0x01;
  332. }
  333. SetKeyboardState(abKeyState);
  334. }
  335. #if TODO // TODO:REV 3/1/2002 Set the NumLock key state when GetKeyboardState fails.
  336. else
  337. {
  338. SHORT lNumLockKeyState = GetKeyState(VK_NUMLOCK);
  339. if (lNumLockKeyState & 1)
  340. {
  341. lNumLockKeyState &= 0xfe;
  342. }
  343. else
  344. {
  345. lNumLockKeyState |= 0x01;
  346. }
  347. if (lNumLockKeyState)
  348. {
  349. INPUT lInput;
  350. lInput.ki =
  351. SendInput(1, lInput, sizeof(INPUT));
  352. }
  353. }
  354. #endif // TODO:REV 3/1/2002
  355. }
  356. return;
  357. }
  358. else
  359. {
  360. // Win32 got this one right. TranslateMesssage returns TRUE
  361. // only if it translates (ie. produces a WM_CHAR). Win31
  362. // didn't do this. If a WM_CHAR is generated, then we want
  363. // to eat the WM_KEYDOWN and wait for the WM_CHAR event.
  364. // Bug in TranslateMessage(). It returns TRUE on all
  365. // WM_KEYDOWN messages regardless of translation. Reported
  366. // bug 1/5/93
  367. if (!TranslateAccelerator(glblQueryHwndFrame(),
  368. glblQueryAccelHdl(), pmsg))
  369. {
  370. MSG msg;
  371. TranslateMessage(pmsg);
  372. if (PeekMessage(&msg, pmsg->hwnd, WM_CHAR, WM_CHAR,
  373. PM_NOREMOVE) == FALSE)
  374. {
  375. DispatchMessage(pmsg);
  376. }
  377. }
  378. return;
  379. }
  380. default:
  381. break;
  382. }
  383. // Not for the terminal window? Do the normal thing...
  384. if (!TranslateAccelerator(glblQueryHwndFrame(), glblQueryAccelHdl(), pmsg))
  385. {
  386. TranslateMessage(pmsg);
  387. DispatchMessage(pmsg);
  388. }
  389. return;
  390. }