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.

394 lines
12 KiB

  1. /***************************************************************************\
  2. *
  3. * DMMNEM.C -
  4. *
  5. * Copyright (c) 1985 - 1999, Microsoft Corporation
  6. *
  7. * Mnemonic Character Processing Routines
  8. *
  9. * ??-???-???? mikeke Ported from Win 3.0 sources
  10. * 12-Feb-1991 mikeke Added Revalidation code
  11. \***************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. /*
  15. * There are several loops that we could get stuck in that we just forcibly
  16. * break by a max iteration count. Ugly, but its legacy DialogManager
  17. * issues.
  18. */
  19. #define INFINITE_LOOP_CURE 1024
  20. /***************************************************************************\
  21. * FindMnemChar
  22. *
  23. * Returns: 0x00 if no matching char,
  24. * 0x01 if menmonic char is matching,
  25. * 0x80 if first char is matching
  26. *
  27. * History:
  28. * 11-18-90 JimA Created.
  29. \***************************************************************************/
  30. int FindMnemChar(
  31. LPWSTR lpstr,
  32. WCHAR ch,
  33. BOOL fFirst,
  34. BOOL fPrefix)
  35. {
  36. WCHAR chc;
  37. WCHAR chFirst;
  38. while (*lpstr == TEXT(' '))
  39. lpstr++;
  40. ch = (WCHAR)(ULONG_PTR)CharLowerW((LPWSTR)ULongToPtr( (DWORD)(UTCHAR)ch ));
  41. chFirst = (WCHAR)(ULONG_PTR)CharLowerW((LPWSTR)ULongToPtr( (DWORD)(UTCHAR)(*lpstr) ));
  42. if (fPrefix) {
  43. WORD wvch, xvkey;
  44. //
  45. // get OEM-dependent virtual key code
  46. //
  47. if (IS_DBCS_ENABLED() && (wvch = VkKeyScanW(ch)) != -1)
  48. wvch &= 0x00FF;
  49. while (chc = *lpstr++) {
  50. //
  51. // This should think about KOREA & TAIWAN case. But probably OK.
  52. //
  53. if ((chc == CH_PREFIX) || (chc == CH_ENGLISHPREFIX && IS_DBCS_ENABLED())) {
  54. WORD chnext = (WCHAR)(ULONG_PTR)CharLowerW((LPWSTR)ULongToPtr( (DWORD)(UTCHAR)*lpstr ));
  55. if (chnext == CH_PREFIX) {
  56. //
  57. // Two CH_PREFIX in the resrc string results in one "&" in the text displayed
  58. //
  59. lpstr++;
  60. } else {
  61. if (chnext == ch) {
  62. return 0x01;
  63. }
  64. if (IS_DBCS_ENABLED()) {
  65. //
  66. // Compare should be done with virtual key in Kanji menu mode
  67. // in order to accept Digit shortcut key and save English
  68. // windows applications!
  69. //
  70. xvkey = VkKeyScanW(chnext);
  71. if (xvkey != 0xFFFF && ((xvkey & 0x00FF) == wvch)) {
  72. return 0x01;
  73. }
  74. }
  75. return 0x00;
  76. }
  77. }
  78. }
  79. }
  80. #if 0 // the original US code on NT4
  81. if (fPrefix) {
  82. while (chc = *lpstr++) {
  83. if (((WCHAR)CharLower((LPWSTR)(DWORD)(UTCHAR)chc) == CH_PREFIX)) {
  84. chnext = (WCHAR)CharLowerW((LPWSTR)(DWORD)(UTCHAR)*lpstr);
  85. if (chnext == CH_PREFIX)
  86. lpstr++;
  87. else if (chnext == ch)
  88. return 0x01;
  89. else {
  90. return 0x00;
  91. }
  92. }
  93. }
  94. }
  95. #endif // FE_SB
  96. if (fFirst && (ch == chFirst))
  97. return 0x80;
  98. return 0x00;
  99. }
  100. /***************************************************************************\
  101. * xxxFindNextMnem
  102. *
  103. * This function returns NULL if no control with the specified mnemonic
  104. * can be found.
  105. *
  106. * History:
  107. \***************************************************************************/
  108. PWND xxxGNM_FindNextMnem(
  109. PWND pwndDlg,
  110. PWND pwnd,
  111. WCHAR ch)
  112. {
  113. PWND pwndStart;
  114. PWND pwndT;
  115. WCHAR rgchText[256];
  116. int i = 0;
  117. TL tlpwndStart;
  118. TL tlpwnd;
  119. DWORD dwDlgCode;
  120. CheckLock(pwndDlg);
  121. CheckLock(pwnd);
  122. /*
  123. * Check if we are in a group box so we can find local mnemonics.
  124. */
  125. pwndStart = _GetChildControl(pwndDlg, pwnd);
  126. ThreadLock(pwndStart, &tlpwndStart);
  127. while (TRUE) {
  128. pwndT = _GetNextDlgGroupItem(pwndDlg, pwndStart, FALSE);
  129. ThreadUnlock(&tlpwndStart);
  130. i++;
  131. if (pwndT == NULL || pwndT == pwnd || i > INFINITE_LOOP_CURE) {
  132. /*
  133. * If we have returned to our starting window or if we have gone
  134. * through INFINITE_LOOP_CURE iterations, let's exit. There are
  135. * no local mnemonics that match. We have to check for
  136. * INFINITE_LOOP_CURE iterations (or so) because we run into
  137. * problems with WS_GROUP not being properly defined in rc files
  138. * that we never reach this same starting window again....
  139. */
  140. break;
  141. }
  142. pwndStart = pwndT;
  143. /*
  144. * Only check for matching mnemonic if control doesn't want characters
  145. * and control isn't a static control with SS_NOPREFIX
  146. */
  147. ThreadLock(pwndStart, &tlpwndStart);
  148. dwDlgCode = (DWORD)SendMessage(HWq(pwndT), WM_GETDLGCODE, 0, 0L);
  149. if (!(dwDlgCode & DLGC_WANTCHARS) &&
  150. (!(dwDlgCode & DLGC_STATIC) || !(pwndT->style & SS_NOPREFIX))) {
  151. GetWindowText(HWq(pwndT), rgchText, sizeof(rgchText)/sizeof(WCHAR));
  152. if (FindMnemChar(rgchText, ch, FALSE, TRUE) != 0) {
  153. ThreadUnlock(&tlpwndStart);
  154. return pwndT;
  155. }
  156. }
  157. }
  158. pwnd = pwndStart = _GetChildControl(pwndDlg, pwnd);
  159. i = 0;
  160. ThreadLock(pwnd, &tlpwnd);
  161. while (TRUE) {
  162. /*
  163. * Start with next so we see multiples of same mnemonic.
  164. */
  165. pwnd = _NextControl(pwndDlg, pwnd, TRUE);
  166. ThreadUnlock(&tlpwnd);
  167. ThreadLock(pwnd, &tlpwnd);
  168. /*
  169. * Only check for matching mnemonic if control doesn't want characters
  170. * and control isn't a static control with SS_NOPREFIX
  171. */
  172. dwDlgCode = (DWORD)SendMessage(HW(pwnd), WM_GETDLGCODE, 0, 0L);
  173. if (!(dwDlgCode & DLGC_WANTCHARS) &&
  174. (!(dwDlgCode & DLGC_STATIC) || !(pwnd->style & SS_NOPREFIX))) {
  175. GetWindowText(HW(pwnd), rgchText, sizeof(rgchText)/sizeof(WCHAR));
  176. if (FindMnemChar(rgchText, ch, FALSE, TRUE) != 0)
  177. break;
  178. }
  179. i++;
  180. if (pwnd == pwndStart || i > INFINITE_LOOP_CURE) {
  181. pwnd = NULL;
  182. break;
  183. }
  184. }
  185. ThreadUnlock(&tlpwnd);
  186. return pwnd;
  187. }
  188. /***************************************************************************\
  189. * xxxGotoNextMnem
  190. *
  191. * History:
  192. \***************************************************************************/
  193. PWND xxxGotoNextMnem(
  194. PWND pwndDlg,
  195. PWND pwnd,
  196. WCHAR ch)
  197. {
  198. UINT code;
  199. PWND pwndFirstFound = NULL;
  200. int count = 0;
  201. TL tlpwnd;
  202. PWND pwndT;
  203. HWND hwnd;
  204. CheckLock(pwndDlg);
  205. CheckLock(pwnd);
  206. ThreadLock(pwnd, &tlpwnd);
  207. /*
  208. * Loop for a long time but not long enough so we hang...
  209. */
  210. while (count < INFINITE_LOOP_CURE) {
  211. /*
  212. * If the dialog box doesn't has the mnemonic specified, return NULL.
  213. */
  214. if ((pwnd = xxxGNM_FindNextMnem(pwndDlg, pwnd, ch)) == NULL) {
  215. ThreadUnlock(&tlpwnd);
  216. return NULL;
  217. }
  218. hwnd = HWq(pwnd);
  219. ThreadUnlock(&tlpwnd);
  220. ThreadLock(pwnd, &tlpwnd);
  221. code = (UINT)SendMessage(hwnd, WM_GETDLGCODE, 0, 0L);
  222. /*
  223. * If a non-disabled static item, then jump ahead to nearest tabstop.
  224. */
  225. if (code & DLGC_STATIC && !TestWF(pwnd, WFDISABLED)) {
  226. pwndT = _GetNextDlgTabItem(pwndDlg, pwnd, FALSE);
  227. /*
  228. * If there is no other tab item, keep looking
  229. */
  230. if (pwndT == NULL)
  231. continue;
  232. pwnd = pwndT;
  233. hwnd = HWq(pwnd);
  234. ThreadUnlock(&tlpwnd);
  235. ThreadLock(pwnd, &tlpwnd);
  236. /*
  237. * I suppose we should do a getdlgcode here, but who is going to
  238. * label a button with a static control? The setup guys, that's
  239. * who... Also, generally useful for ownerdraw buttons which are
  240. * labeled with a static text item.
  241. */
  242. code = (UINT)SendMessage(hwnd, WM_GETDLGCODE, 0, 0L);
  243. }
  244. if (!TestWF(pwnd, WFDISABLED)) {
  245. /*
  246. * Is it a Pushbutton?
  247. */
  248. if (!(code & DLGC_BUTTON)) {
  249. /*
  250. * No, simply give it the focus.
  251. */
  252. DlgSetFocus(hwnd);
  253. } else {
  254. /*
  255. * Yes, click it, but don't give it the focus.
  256. */
  257. if ((code & DLGC_DEFPUSHBUTTON) || (code & DLGC_UNDEFPUSHBUTTON)) {
  258. /*
  259. * Flash the button.
  260. */
  261. SendMessage(hwnd, BM_SETSTATE, TRUE, 0L);
  262. /*
  263. * Delay
  264. */
  265. #ifdef LATER
  266. // JimA - 2/19/92
  267. // There oughta be a better way of doing this...
  268. for (i = 0; i < 10000; i++)
  269. ;
  270. #else
  271. Sleep(1);
  272. #endif
  273. /*
  274. * Un-Flash it.
  275. */
  276. SendMessage(hwnd, BM_SETSTATE, FALSE, 0L);
  277. /*
  278. * Send the WM_COMMAND message.
  279. */
  280. pwndT = REBASEPWND(pwnd, spwndParent);
  281. SendMessage(HW(pwndT), WM_COMMAND,
  282. MAKELONG(PTR_TO_ID(pwnd->spmenu), BN_CLICKED), (LPARAM)hwnd);
  283. ThreadUnlock(&tlpwnd);
  284. return (PWND)1;
  285. } else {
  286. /*
  287. * Because BM_CLICK processing will result in BN_CLICK msg,
  288. * xxxSetFocus must be prevented from sending the same msg;
  289. * Otherwise, it will notify parent twice!
  290. * Fix for Bug #3024 -- SANKAR -- 09-22-89 --
  291. */
  292. BOOL fIsNTButton;
  293. PBUTN pbutn;
  294. fIsNTButton = IS_BUTTON(pwnd);
  295. if (fIsNTButton) {
  296. pbutn = ((PBUTNWND)pwnd)->pbutn;
  297. BUTTONSTATE(pbutn) |= BST_DONTCLICK;
  298. } else {
  299. RIPMSG0(RIP_WARNING, "xxxGotoNextMnem: fnid != FNID_BUTTON");
  300. }
  301. DlgSetFocus(hwnd);
  302. if (fIsNTButton) {
  303. BUTTONSTATE(pbutn) &= ~BST_DONTCLICK;
  304. }
  305. /*
  306. * Send click message if button has a UNIQUE mnemonic
  307. */
  308. if (xxxGNM_FindNextMnem(pwndDlg, pwnd, ch) == pwnd) {
  309. SendMessage(hwnd, BM_CLICK, TRUE, 0L);
  310. }
  311. }
  312. }
  313. ThreadUnlock(&tlpwnd);
  314. return pwnd;
  315. } else {
  316. /*
  317. * Stop if we've looped back to the first item we checked
  318. */
  319. if (pwnd == pwndFirstFound) {
  320. ThreadUnlock(&tlpwnd);
  321. return NULL;
  322. }
  323. if (pwndFirstFound == NULL)
  324. pwndFirstFound = pwnd;
  325. }
  326. count++;
  327. } /* Loop for a long time */
  328. ThreadUnlock(&tlpwnd);
  329. return NULL;
  330. }