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.

535 lines
14 KiB

  1. /*****************************************************************************
  2. *
  3. * mapps.c - Property sheet handler
  4. *
  5. *****************************************************************************/
  6. #include "map.h"
  7. /*****************************************************************************
  8. *
  9. * The sqiffle for this file.
  10. *
  11. *****************************************************************************/
  12. #define sqfl sqflPs
  13. /*****************************************************************************
  14. *
  15. * Strings.
  16. *
  17. * The Scancode map registry value looks like this:
  18. *
  19. * DWORD dwVersion; // Must be zero
  20. * DWORD dwFlags; // Must be zero
  21. * DWORD dwNumRemaps; // Number of remaps, including terminating 0
  22. * REMAPENTRY rgRemap[...]; // dwNumRemaps remap entries
  23. *
  24. * The last remap entry must be all-zero.
  25. *
  26. *
  27. * Each remap entry looks like this:
  28. *
  29. * WORD wTo;
  30. * WORD wFrom;
  31. *
  32. * where wFrom is the source scancode and wTo is the target scancode.
  33. * If the key being remapped is an extended key, then the high word
  34. * of the scancode is 0xE0. Otherwise, the high word is zero.
  35. *
  36. * NOTE! When we load the scancode map into memory, we make
  37. * dwNumRemaps *not* include the terminating zero. When we write
  38. * it out, we re-adjust it back. This is to avoid off-by-one errors
  39. * in the code.
  40. *
  41. *****************************************************************************/
  42. typedef union REMAPENTRY {
  43. union {
  44. DWORD dw; /* Accessed as a dword */
  45. };
  46. struct {
  47. WORD wTo; /* Accessed as two words */
  48. WORD wFrom;
  49. };
  50. } REMAPENTRY, *PREMAPENTRY;
  51. #define MAX_REMAPENTRY (IDS_NUMKEYS+1)
  52. typedef struct SCANCODEMAP {
  53. DWORD dwVersion;
  54. DWORD dwFlags;
  55. DWORD dwNumRemaps;
  56. REMAPENTRY rgRemap[MAX_REMAPENTRY];
  57. } SCANCODEMAP, *PSCANCODEMAP;
  58. #pragma BEGIN_CONST_DATA
  59. TCHAR c_tszKeyboard[] = TEXT("SYSTEM\\CurrentControlSet\\Control\\")
  60. TEXT("Keyboard Layout");
  61. TCHAR c_tszMapping[] = TEXT("Scancode Map");
  62. #pragma END_CONST_DATA
  63. /*****************************************************************************
  64. *
  65. * rgwRemap
  66. *
  67. * Maps each key to its scancode. This must match the list of strings.
  68. *
  69. *****************************************************************************/
  70. #pragma BEGIN_CONST_DATA
  71. WORD rgwRemap[] = {
  72. 0x003A, // IDS_CAPSLOCK
  73. 0x001D, // IDS_LCTRL
  74. 0xE01D, // IDS_RCTRL
  75. 0x0038, // IDS_LALT
  76. 0xE038, // IDS_RALT
  77. 0x002A, // IDS_LSHIFT
  78. 0x0036, // IDS_RSHIFT
  79. 0xE05B, // IDS_LWIN
  80. 0xE05C, // IDS_RWIN
  81. 0xE05D, // IDS_APPS
  82. };
  83. #pragma END_CONST_DATA
  84. /*****************************************************************************
  85. *
  86. * KEYMAPDATA
  87. *
  88. * Instance data for the property sheet.
  89. *
  90. *****************************************************************************/
  91. typedef struct KEYMAPDATA {
  92. SCANCODEMAP map; /* The mapping to apply */
  93. int ilbFrom; /* What's in ID_FROM? */
  94. int ilbTo; /* What's in ID_TO? */
  95. } KMD, *PKMD;
  96. #define pkmdHdlg(hdlg) (PKMD)GetWindowPointer(hdlg, DWLP_USER)
  97. /*****************************************************************************
  98. *
  99. * MapPs_GetLbCurSel
  100. *
  101. * Get the current selection from a listbox.
  102. *
  103. *****************************************************************************/
  104. int PASCAL
  105. MapPs_GetLbCurSel(HWND hdlg, UINT idc)
  106. {
  107. return (int)SendDlgItemMessage(hdlg, idc, LB_GETCURSEL, 0, 0);
  108. }
  109. /*****************************************************************************
  110. *
  111. * MapPs_FindEntry
  112. *
  113. * Locate a mapping table entry, or -1 if not found.
  114. *
  115. *****************************************************************************/
  116. int PASCAL
  117. MapPs_FindEntry(PKMD pkmd, WORD wFrom)
  118. {
  119. DWORD iMap;
  120. for (iMap = 0; iMap < pkmd->map.dwNumRemaps; iMap++) {
  121. if (pkmd->map.rgRemap[iMap].wFrom == wFrom) {
  122. return (int)iMap;
  123. }
  124. }
  125. return -1;
  126. }
  127. /*****************************************************************************
  128. *
  129. * MapPs_WordToIndex
  130. *
  131. * Given a mapping in the form of a word (rgwRemap), convert it back
  132. * to the index that it came from. This is the reverse of the rgwRemap
  133. * array.
  134. *
  135. *****************************************************************************/
  136. int PASCAL
  137. MapPs_WordToIndex(WORD w)
  138. {
  139. int i;
  140. for (i = 0; i < IDS_NUMKEYS; i++) {
  141. if (rgwRemap[i] == w) {
  142. return i;
  143. }
  144. }
  145. return -1;
  146. }
  147. /*****************************************************************************
  148. *
  149. * MapPs_SaveCurSel
  150. *
  151. * Stash what's in the current selection.
  152. *
  153. *****************************************************************************/
  154. void PASCAL
  155. MapPs_SaveCurSel(HWND hdlg, PKMD pkmd)
  156. {
  157. int iTo = MapPs_GetLbCurSel(hdlg, IDC_TO);
  158. int iMap;
  159. WORD wFrom = rgwRemap[pkmd->ilbFrom];
  160. WORD wTo = rgwRemap[iTo];
  161. iMap = MapPs_FindEntry(pkmd, wFrom);
  162. if (iMap < 0) {
  163. /*
  164. * Not found; must allocate. Note that we check against
  165. * MAX_REMAPENTRY-1 because the trailing null eats one slot.
  166. */
  167. if (pkmd->map.dwNumRemaps < MAX_REMAPENTRY - 1) {
  168. iMap = (int)pkmd->map.dwNumRemaps++;
  169. } else {
  170. /*
  171. * No room in the table. Oh well.
  172. */
  173. return;
  174. }
  175. }
  176. /*
  177. * If the item is mapping to itself, then delete it entirely.
  178. */
  179. if (wFrom == wTo) {
  180. pkmd->map.dwNumRemaps--;
  181. pkmd->map.rgRemap[iMap].dw =
  182. pkmd->map.rgRemap[pkmd->map.dwNumRemaps].dw;
  183. } else {
  184. pkmd->map.rgRemap[iMap].wFrom = wFrom;
  185. pkmd->map.rgRemap[iMap].wTo = wTo;
  186. }
  187. }
  188. /*****************************************************************************
  189. *
  190. * MapPs_TrackSel
  191. *
  192. * Select the corresponding item in idcTo given what's in idcFrom.
  193. *
  194. *****************************************************************************/
  195. void PASCAL
  196. MapPs_TrackSel(HWND hdlg, PKMD pkmd)
  197. {
  198. int iFrom = pkmd->ilbFrom;
  199. int iMap, iTo;
  200. iMap = MapPs_FindEntry(pkmd, rgwRemap[iFrom]);
  201. if (iMap >= 0) {
  202. iTo = MapPs_WordToIndex(pkmd->map.rgRemap[iMap].wTo);
  203. if (iTo < 0) {
  204. /*
  205. * Target not recognized; just map it to itself.
  206. */
  207. iTo = iFrom;
  208. }
  209. } else {
  210. /*
  211. * Key not mapped. Therefore, it maps to itself.
  212. */
  213. iTo = iFrom;
  214. }
  215. pkmd->ilbTo = iTo;
  216. SendDlgItemMessage(hdlg, IDC_TO, LB_SETCURSEL, iTo, 0);
  217. }
  218. /*****************************************************************************
  219. *
  220. * MapPs_OnInitDialog
  221. *
  222. * Read the current scancode mapping and fill in the dialog box.
  223. *
  224. *****************************************************************************/
  225. BOOL NEAR PASCAL
  226. MapPs_OnInitDialog(HWND hdlg)
  227. {
  228. PKMD pkmd = LocalAlloc(LPTR, cbX(KMD));
  229. HKEY hk;
  230. LONG lRc;
  231. DWORD dwDisp;
  232. SetWindowPointer(hdlg, DWLP_USER, pkmd);
  233. lRc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, c_tszKeyboard, 0,
  234. TEXT(""), REG_OPTION_NON_VOLATILE,
  235. KEY_QUERY_VALUE | KEY_SET_VALUE,
  236. NULL, &hk, &dwDisp);
  237. if (lRc == ERROR_SUCCESS) {
  238. DWORD dwType;
  239. DWORD cb;
  240. int dids;
  241. cb = sizeof(pkmd->map);
  242. lRc = RegQueryValueEx(hk, c_tszMapping, NULL, &dwType,
  243. (LPBYTE)&pkmd->map, &cb);
  244. RegCloseKey(hk);
  245. /*
  246. * Note that ERROR_MORE_DATA is an error here.
  247. * But ERROR_FILE_NOT_FOUND is okay.
  248. */
  249. if (lRc == ERROR_SUCCESS) {
  250. /*
  251. * Sanity-check all the data.
  252. */
  253. if (
  254. /* Must be binary data */
  255. dwType == REG_BINARY &&
  256. /* Version zero */
  257. pkmd->map.dwVersion == 0 &&
  258. /* No flags */
  259. pkmd->map.dwFlags == 0 &&
  260. /* Sane number of remaps */
  261. pkmd->map.dwNumRemaps > 0 &&
  262. pkmd->map.dwNumRemaps <= MAX_REMAPENTRY &&
  263. /* Structure is the correct size */
  264. cb == (DWORD)FIELD_OFFSET(SCANCODEMAP,
  265. rgRemap[pkmd->map.dwNumRemaps]) &&
  266. /* Last remap must be zero */
  267. pkmd->map.rgRemap[pkmd->map.dwNumRemaps - 1].dw == 0
  268. ) {
  269. } else {
  270. goto fail;
  271. }
  272. pkmd->map.dwNumRemaps--; /* Don't count the trailing null */
  273. } else if (lRc == ERROR_FILE_NOT_FOUND) {
  274. /*
  275. * Set it up for a null mapping.
  276. */
  277. ZeroMemory(&pkmd->map, sizeof(pkmd->map));
  278. } else {
  279. goto fail;
  280. }
  281. /*
  282. * Now init the dialog items.
  283. */
  284. for (dids = 0; dids < IDS_NUMKEYS; dids++) {
  285. TCHAR tsz[256];
  286. LoadString(g_hinst, IDS_KEYFIRST + dids, tsz, cA(tsz));
  287. SendDlgItemMessage(hdlg, IDC_FROM,
  288. LB_ADDSTRING, 0, (LPARAM)tsz);
  289. SendDlgItemMessage(hdlg, IDC_TO,
  290. LB_ADDSTRING, 0, (LPARAM)tsz);
  291. }
  292. } else {
  293. fail:;
  294. /*
  295. * User does not have permission to remap keys, or the key
  296. * contents aren't something we like. Gray the controls.
  297. */
  298. EnableWindow(GetDlgItem(hdlg, IDC_TO), FALSE);
  299. }
  300. SendDlgItemMessage(hdlg, IDC_FROM, LB_SETCURSEL, 0, 0);
  301. MapPs_TrackSel(hdlg, pkmd);
  302. return 1;
  303. }
  304. /*****************************************************************************
  305. *
  306. * MapPs_OnSelChange
  307. *
  308. * Somebody changed a selection. Save the selection and set
  309. * the new one.
  310. *
  311. *****************************************************************************/
  312. void PASCAL
  313. MapPs_OnSelChange(HWND hdlg, PKMD pkmd)
  314. {
  315. MapPs_SaveCurSel(hdlg, pkmd); /* Save it */
  316. pkmd->ilbFrom = MapPs_GetLbCurSel(hdlg, IDC_FROM);
  317. MapPs_TrackSel(hdlg, pkmd); /* And update for the new one */
  318. }
  319. /*****************************************************************************
  320. *
  321. * MapPs_OnCommand
  322. *
  323. * Ooh, we got a command.
  324. *
  325. *****************************************************************************/
  326. BOOL PASCAL
  327. MapPs_OnCommand(HWND hdlg, int id, UINT codeNotify)
  328. {
  329. PKMD pkmd = pkmdHdlg(hdlg);
  330. switch (id) {
  331. case IDC_FROM:
  332. switch (codeNotify) {
  333. case LBN_SELCHANGE:
  334. MapPs_OnSelChange(hdlg, pkmd);
  335. break;
  336. }
  337. break;
  338. case IDC_TO:
  339. switch (codeNotify) {
  340. case LBN_SELCHANGE:
  341. if (MapPs_GetLbCurSel(hdlg, IDC_TO) != pkmd->ilbTo) {
  342. PropSheet_Changed(GetParent(hdlg), hdlg);
  343. }
  344. break;
  345. }
  346. break;
  347. }
  348. return 0;
  349. }
  350. /*****************************************************************************
  351. *
  352. * MapPs_Apply
  353. *
  354. * Write the changes to the registry and nudge the VxD. We might have
  355. * to load the VxD if the user is playing with KeyRemap immediately
  356. * after installing, without rebooting in the interim.
  357. *
  358. *****************************************************************************/
  359. BOOL PASCAL
  360. MapPs_Apply(HWND hdlg)
  361. {
  362. PKMD pkmd = pkmdHdlg(hdlg);
  363. MapPs_SaveCurSel(hdlg, pkmd);
  364. if (IsWindowEnabled(GetDlgItem(hdlg, IDC_TO))) {
  365. LONG lRc;
  366. HKEY hk;
  367. lRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_tszKeyboard, 0,
  368. KEY_SET_VALUE, &hk);
  369. if (lRc == ERROR_SUCCESS) {
  370. DWORD cb;
  371. /*
  372. * Count the trailing null again. And make sure
  373. * it's a trailing null!
  374. */
  375. pkmd->map.rgRemap[pkmd->map.dwNumRemaps].dw = 0;
  376. pkmd->map.dwNumRemaps++;
  377. cb = (DWORD)FIELD_OFFSET(SCANCODEMAP,
  378. rgRemap[pkmd->map.dwNumRemaps]);
  379. lRc = RegSetValueEx(hk, c_tszMapping, 0, REG_BINARY,
  380. (LPBYTE)&pkmd->map, cb);
  381. pkmd->map.dwNumRemaps--;
  382. RegCloseKey(hk);
  383. }
  384. if (lRc == ERROR_SUCCESS) {
  385. PropSheet_RebootSystem(GetParent(hdlg));
  386. }
  387. }
  388. return 1;
  389. }
  390. /*****************************************************************************
  391. *
  392. * MapPs_OnNotify
  393. *
  394. * Ooh, we got a notification.
  395. *
  396. *****************************************************************************/
  397. BOOL PASCAL
  398. MapPs_OnNotify(HWND hdlg, NMHDR FAR *pnm)
  399. {
  400. switch (pnm->code) {
  401. case PSN_APPLY:
  402. MapPs_Apply(hdlg);
  403. break;
  404. }
  405. return 0;
  406. }
  407. /*****************************************************************************
  408. *
  409. * MapPs_OnDestroy
  410. *
  411. * Clean up.
  412. *
  413. *****************************************************************************/
  414. BOOL PASCAL
  415. MapPs_OnDestroy(HWND hdlg)
  416. {
  417. PKMD pkmd = pkmdHdlg(hdlg);
  418. FreePv(pkmd);
  419. return 1;
  420. }
  421. /*****************************************************************************
  422. *
  423. * MapPs_DlgProc
  424. *
  425. * Our property sheet dialog procedure.
  426. *
  427. *****************************************************************************/
  428. INT_PTR CALLBACK
  429. MapPs_DlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam)
  430. {
  431. switch (wm) {
  432. case WM_INITDIALOG:
  433. return MapPs_OnInitDialog(hdlg);
  434. case WM_COMMAND:
  435. return MapPs_OnCommand(hdlg,
  436. (int)GET_WM_COMMAND_ID(wParam, lParam),
  437. (UINT)GET_WM_COMMAND_CMD(wParam, lParam));
  438. case WM_NOTIFY:
  439. return MapPs_OnNotify(hdlg, (NMHDR FAR *)lParam);
  440. case WM_DESTROY:
  441. return MapPs_OnDestroy(hdlg);
  442. default: return 0; /* Unhandled */
  443. }
  444. return 1; /* Handled */
  445. }