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.

923 lines
28 KiB

  1. /*
  2. * KEY.C
  3. *
  4. * Copyright (C) 1990 Microsoft Corporation.
  5. *
  6. * Edit keymaps dialog box and support functinos.
  7. */
  8. /* Revision history:
  9. March 92 Ported to 16/32 common code by Laurie Griffiths (LaurieGr)
  10. */
  11. /*-=-=-=-=- Include Files -=-=-=-=-*/
  12. #include "preclude.h"
  13. #include <windows.h>
  14. #include <mmsystem.h>
  15. #include <port1632.h>
  16. #include "hack.h"
  17. #include "cphelp.h"
  18. #include "midimap.h"
  19. #include "midi.h"
  20. #include "extern.h"
  21. /*-=-=-=-=- Prototypes -=-=-=-=-*/
  22. static MMAPERR PASCAL MmaperrKeyInit(VOID);
  23. static MMAPERR PASCAL MmaperrKeyInitNew(VOID);
  24. static VOID PASCAL KeySize(BOOL);
  25. static VOID PASCAL KeyPaint(VOID);
  26. static VOID PASCAL KeyArrowScroll(UINT);
  27. static VOID PASCAL KeyWindowScroll(UINT, int);
  28. static VOID PASCAL KeyEditMsg(WORD NotifCode);
  29. static VOID PASCAL KeyButtonDown(LONG);
  30. static VOID PASCAL KeySetFocus(UINT, int);
  31. static VOID PASCAL KeyActiveLine(UINT, UINT);
  32. static int PASCAL KeySave(HWND, BOOL);
  33. /*-=-=-=-=- Global Definitions -=-=-=-=-*/
  34. #define PAL_SHOW 0 // Show active line.
  35. #define PAL_HIDE 1 // Hide active line.
  36. #define PSF_REDRAW 0x0001 // Redraw where line used to be.
  37. #define PSF_SHOWIFHIDDEN 0x0002 // Show line if hidden.
  38. #define DEF_KEY_ROWS 16 // number of default key rows
  39. /*-=-=-=-=- Global Variables -=-=-=-=-*/
  40. static HWND hScroll; // scroll bar control handle
  41. static char * _based(_segname("_CODE")) szNotes [] = { // Note descriptions
  42. "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
  43. };
  44. static SZCODE aszMidiSection[] = "midicpl";
  45. static SZCODE aszMidiKey[] = "keyview";
  46. static SZCODE aszKeyNumFormat[] = "%3d";
  47. static SZCODE aszNoteOctaveFormat[] = " %s %d";
  48. static BOOL fKeyView;
  49. static int xArrowOffset; // key arrow ctrl positional offset
  50. /*-=-=-=-=- Functions -=-=-=-=-*/
  51. /*
  52. * KEYBOX
  53. */
  54. BOOL FAR PASCAL _loadds KeyBox( HWND hDlg,
  55. UINT uMessage,
  56. WPARAM wParam,
  57. LPARAM lParam )
  58. {
  59. int iRet = FALSE;
  60. MMAPERR mmaperr;
  61. switch (uMessage) {
  62. case WM_INITDIALOG :
  63. hWnd = hDlg;
  64. SetFocus(GetDlgItem(hDlg, ID_KEYEDIT));
  65. if ((mmaperr = MmaperrKeyInit()) != MMAPERR_SUCCESS) {
  66. VShowError(hDlg, mmaperr);
  67. EndDialog(hDlg, FALSE);
  68. }
  69. SetScrollRange(hScroll, SB_CTL, 0, iVertMax, FALSE);
  70. SetScrollPos(hScroll, SB_CTL, iVertPos, TRUE);
  71. PlaceWindow(hWnd);
  72. return FALSE;
  73. case WM_COMMAND :
  74. { WORD id = LOWORD(wParam);
  75. #if defined(WIN16)
  76. WORD NotifCode = HIWORD(lParam);
  77. HWND hwnd = LOWORD(lParam);
  78. #else
  79. WORD NotifCode = HIWORD(wParam);
  80. HWND hwnd = (HWND)lParam;
  81. #endif //WIN16
  82. switch (id) {
  83. case IDH_DLG_MIDI_KEYEDIT:
  84. goto DoHelp;
  85. case ID_KEYGHOSTEDITFIRST:
  86. /* assume the user back-tabbed before the first
  87. * control on the current row, so jump to the
  88. * previous row (if iCurPos > 0) or the last row
  89. * (if iCurPos == 0)
  90. */
  91. if (fHidden) //we shouldn't get these messages
  92. break; //when we're hidden -jyg
  93. if (NotifCode != EN_SETFOCUS)
  94. break;
  95. if (iCurPos < 0)
  96. /* do nothing */ ;
  97. else if (iCurPos > 0)
  98. iCurPos--;
  99. else
  100. {
  101. if (iVertPos != 0)
  102. {
  103. /* at top -- scroll up one line */
  104. KeyWindowScroll(SB_LINEUP, 0);
  105. iCurPos = 0;
  106. }
  107. else
  108. {
  109. /* wrap to bottom cell */
  110. KeyWindowScroll(SB_THUMBPOSITION, iVertMax);
  111. iCurPos = nLines - 1;
  112. KeySetFocus(PSF_REDRAW|PSF_SHOWIFHIDDEN, 0);
  113. KeyActiveLine(PAL_SHOW, SWP_SHOWWINDOW);
  114. }
  115. }
  116. KeySetFocus(PSF_REDRAW, 1);
  117. break;
  118. case ID_KEYGHOSTEDITLAST:
  119. /* assume the user forward-tabbed beyond the last
  120. * control on the current row, so jump to the
  121. * next row (if iCurPos < nLines - 1) or the first row
  122. * (if iCurPos == nLines - 1)
  123. */
  124. if (fHidden) //we shouldn't get these messages
  125. break; //when we're hidden -jyg
  126. if (NotifCode != EN_SETFOCUS)
  127. break;
  128. if (iCurPos < 0)
  129. /* do nothing */ ;
  130. else
  131. if (iCurPos < nLines - 1)
  132. iCurPos++;
  133. else
  134. {
  135. if (iVertPos != iVertMax)
  136. {
  137. /* at bottom -- scroll down one line */
  138. KeyWindowScroll(SB_LINEDOWN, 0);
  139. iCurPos = nLines - 1;
  140. }
  141. else
  142. {
  143. /* wrap to top cell */
  144. /* wrap to the top cell */
  145. KeyWindowScroll(SB_THUMBPOSITION,-iVertMax);
  146. iCurPos = 0;
  147. KeySetFocus(PSF_REDRAW|PSF_SHOWIFHIDDEN, 0);
  148. KeyActiveLine(PAL_SHOW, SWP_SHOWWINDOW);
  149. }
  150. }
  151. KeySetFocus(PSF_REDRAW, 1);
  152. break;
  153. case IDOK :
  154. case IDCANCEL :
  155. if (NotifCode != BN_CLICKED)
  156. break;
  157. if (!fReadOnly && (id == IDOK) && (fModified)) {
  158. iRet = KeySave(hDlg, TRUE);
  159. if (iRet == IDCANCEL)
  160. break;
  161. iRet = (iRet == IDYES);
  162. } else
  163. iRet = FALSE;
  164. GlobalFree(hKeyMap);
  165. EndDialog(hDlg, iRet);
  166. break;
  167. case ID_KEYEDIT :
  168. KeyEditMsg(NotifCode);
  169. break;
  170. default :
  171. return FALSE;
  172. }
  173. break;
  174. } /* end of WM_COMMAND */
  175. case WM_PAINT :
  176. KeyPaint();
  177. break;
  178. case WM_LBUTTONDOWN :
  179. KeyButtonDown((LONG)lParam);
  180. break;
  181. case WM_VSCROLL :
  182. #if defined(WIN16)
  183. if ((HWND)HIWORD(lParam) == hScroll)
  184. KeyWindowScroll(LOWORD(wParam), (int)LOWORD(lParam));
  185. #else
  186. if ((HWND)lParam == hScroll)
  187. KeyWindowScroll(LOWORD(wParam), (int)HIWORD(wParam));
  188. #endif //WIN16
  189. else KeyArrowScroll(LOWORD(wParam));
  190. break;
  191. case WM_CLOSE :
  192. PostMessage(hDlg, WM_COMMAND, (WPARAM)IDOK, (LPARAM)0);
  193. break;
  194. default:
  195. if (uMessage == uHelpMessage) {
  196. DoHelp:
  197. WinHelp(hWnd, szMidiHlp, HELP_CONTEXT,
  198. IDH_DLG_MIDI_KEYEDIT);
  199. return TRUE;
  200. }
  201. else
  202. return FALSE;
  203. break;
  204. }
  205. return TRUE;
  206. } /* KeyBox */
  207. /*
  208. * MmaperrKeyInit
  209. */
  210. static MMAPERR PASCAL MmaperrKeyInit(
  211. VOID)
  212. {
  213. LPMIDIKEYMAP lpKey;
  214. LONG lDBU;
  215. MMAPERR mmaperr;
  216. UINT xBU,
  217. yBU,
  218. xWidth, // width of current column
  219. xArrow, // width of arrow control
  220. xEdit, // width of edit controls
  221. yEdit; // height of edit/arrow controls
  222. int i;
  223. char szCaption[80];
  224. char szCaptionFormat[80];
  225. fHidden = FALSE;
  226. iVertPos = 35;
  227. iCurPos = 0;
  228. nLines = 0; // necessary?
  229. hEdit = GetDlgItem(hWnd, ID_KEYEDIT);
  230. hArrow = GetDlgItem(hWnd, ID_KEYARROW);
  231. hScroll = GetDlgItem(hWnd, ID_KEYSCROLL);
  232. if (fReadOnly)
  233. {
  234. EnableWindow(GetDlgItem(hWnd,IDOK),FALSE);
  235. SendMessage(hWnd, DM_SETDEFID, (WPARAM)IDCANCEL, (LPARAM)0);
  236. }
  237. lDBU = GetDialogBaseUnits();
  238. xBU = LOWORD(lDBU);
  239. yBU = HIWORD(lDBU);
  240. xArrow = (10 * xBU) / 4; // about yea big
  241. xEdit = (40 * xBU) / 4; // 10 chars wide
  242. yEdit = (10 * yBU) / 8; // cookie heaven
  243. rcBox.left = (HORZMARGIN * xBU) / 4;
  244. for (i = 0, rcBox.right = rcBox.left; i < 4; i++) {
  245. rgxPos [i] = rcBox.right;
  246. switch (i) {
  247. case 0 :
  248. // width of src key # text (3.5 chars wide)
  249. rcBox.right += xEdit;
  250. break;
  251. case 1 :
  252. // width of src key (percussion) name text
  253. rcBox.right += (64 * xBU) / 4; // 16 chars wide
  254. break;
  255. case 2 :
  256. // width of dst key # edit control
  257. xWidth = xEdit;
  258. SetWindowPos(hEdit, NULL, 0L, 0L,
  259. xWidth, yEdit, SWP_NOZORDER | SWP_NOMOVE);
  260. // set global arrow control offset to proper position
  261. rcBox.right += xArrowOffset = xWidth - 1;
  262. // width of dst key # arrow control
  263. xWidth = xArrow;
  264. SetWindowPos(hArrow, NULL, 0L, 0L,
  265. xWidth, yEdit, SWP_NOZORDER | SWP_NOMOVE);
  266. rcBox.right += xWidth - 1;
  267. break;
  268. case 3 :
  269. break;
  270. }
  271. }
  272. if (!fNew) {
  273. DWORD dwSize;
  274. dwSize = mapGetSize(MMAP_KEY, szCurrent);
  275. if (dwSize < MMAPERR_MAXERROR)
  276. return (MMAPERR)dwSize;
  277. if ((hKeyMap = GlobalAlloc(GHND, dwSize)) == NULL)
  278. return MMAPERR_MEMORY;
  279. lpKey = (LPMIDIKEYMAP)GlobalLock(hKeyMap);
  280. mmaperr = mapRead( MMAP_KEY, szCurrent, (LPVOID)lpKey);
  281. if (mmaperr == MMAPERR_SUCCESS)
  282. if (lstrcmp(lpKey->szDesc, szCurDesc)) {
  283. lstrcpy(lpKey->szDesc, szCurDesc);
  284. fNew = TRUE;
  285. }
  286. GlobalUnlock (hKeyMap);
  287. if (mmaperr != MMAPERR_SUCCESS) {
  288. GlobalFree(hKeyMap);
  289. hKeyMap = NULL;
  290. return mmaperr;
  291. }
  292. } else if ((mmaperr = MmaperrKeyInitNew()) != MMAPERR_SUCCESS)
  293. return mmaperr;
  294. LoadString(hLibInst, IDS_KEYS, szCaptionFormat, sizeof(szCaptionFormat));
  295. wsprintf(szCaption, szCaptionFormat, (LPSTR)szCurrent);
  296. SetWindowText(hWnd, szCaption);
  297. SendMessage(GetDlgItem(hWnd, ID_KEYDESTMNEM),
  298. WM_SETFONT, (WPARAM)hFont, (LPARAM)0);
  299. KeySize(TRUE);
  300. SetWindowPos(GetDlgItem(hWnd, ID_KEYDESTMNEM), NULL,
  301. rgxPos [2], yChar, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER);
  302. Modify(fNew);
  303. fKeyView = GetProfileInt(aszMidiSection, aszMidiKey, 0);
  304. return MMAPERR_SUCCESS;
  305. } /* MmaperrKeyInit */
  306. /*
  307. * MmaperrKeyInitNew
  308. */
  309. static MMAPERR PASCAL MmaperrKeyInitNew(
  310. VOID)
  311. {
  312. LPMIDIKEYMAP lpKey;
  313. int i;
  314. if ((hKeyMap = GlobalAlloc(GHND,
  315. (DWORD)sizeof(MIDIKEYMAP))) == NULL)
  316. return MMAPERR_MEMORY;
  317. lpKey = (LPMIDIKEYMAP)GlobalLock(hKeyMap);
  318. lstrcpy(lpKey->szName, szCurrent);
  319. lstrcpy(lpKey->szDesc, szCurDesc);
  320. for (i = 0; i < MIDIPATCHSIZE; i++)
  321. lpKey->bKMap [i] = (BYTE) i;
  322. GlobalUnlock(hKeyMap);
  323. return MMAPERR_SUCCESS;
  324. } /* MmaperrKeyInitNew */
  325. /*
  326. * KEYSIZE
  327. */
  328. static
  329. VOID PASCAL KeySize(BOOL fMaximize)
  330. {
  331. RECT rcOK,
  332. rcWnd;
  333. LONG lDBU;
  334. UINT xBU,
  335. yBU;
  336. int xButton,
  337. xCenter,
  338. yTopMar,
  339. yBotMar,
  340. yLeftOver,
  341. yBox,
  342. yMiniBotMar;
  343. lDBU = GetDialogBaseUnits();
  344. xBU = LOWORD(lDBU);
  345. yBU = HIWORD(lDBU);
  346. // get the rectangle of the OK button
  347. GetClientRect(GetDlgItem(hWnd, IDOK), &rcOK);
  348. // get x-extent of button
  349. xButton = rcOK.right - rcOK.left;
  350. // top margin is 2 characters
  351. yTopMar = (16 * yBU) / 8 - 6; // cookie land
  352. // bottom margin is 2 * minimum bottom margin dialog units +
  353. // height of button in pixels
  354. yBotMar = (VERTMARGIN * 2 * yBU) / 8 + rcOK.bottom - rcOK.top;
  355. if (fMaximize) {
  356. // maximize the key box
  357. SetWindowPos(hWnd, NULL, 0L, 0L,
  358. rcBox.right - rcBox.left +
  359. (2 * HORZMARGIN * xBU) / 4 +
  360. GetSystemMetrics(SM_CXVSCROLL) +
  361. (GetSystemMetrics(SM_CXDLGFRAME) + 1) * 2,
  362. (DEF_KEY_ROWS * 10 * yBU) / 8 +
  363. yTopMar + yBotMar +
  364. GetSystemMetrics(SM_CYCAPTION) +
  365. GetSystemMetrics(SM_CYDLGFRAME) * 2,
  366. SWP_NOZORDER | SWP_NOMOVE);
  367. }
  368. // get the x and y extents of the client rectangle
  369. GetClientRect(hWnd, &rcWnd);
  370. xClient = rcWnd.right - rcWnd.left;
  371. yClient = rcWnd.bottom - rcWnd.top;
  372. // yChar is the height of one row in pixels - 1
  373. yChar = (10 * yBU) / 8 - 1;
  374. // xChar is the average width of a character
  375. xChar = xBU;
  376. // yBox is the room we actually have to display patchmap rows
  377. yBox = yClient - yTopMar - yBotMar;
  378. // nLines is the number of setup rows we can display
  379. // what is this 16 doing here?
  380. nLines = min(16, yBox / yChar);
  381. // yLeftOver is how many pixels are left over
  382. yLeftOver = yBox - nLines * yChar;
  383. // add half the leftovers to the top margin
  384. yTopMar += yLeftOver / 2;
  385. // rcBox is the box of rows and columns inside the client area
  386. SetRect(
  387. &rcBox,
  388. rcBox.left,
  389. yTopMar,
  390. rcBox.right,
  391. yTopMar + nLines * yChar);
  392. // xCenter is used to center the OK and CANCEL buttons horizontally
  393. xCenter =(rcBox.right - rcBox.left - xButton * 3) / 4;
  394. // yMiniBotMar is the spacing above and below the button
  395. yMiniBotMar = (VERTMARGIN * yBU) / 8 + yLeftOver / 4;
  396. SetWindowPos(
  397. GetDlgItem(hWnd, IDOK),
  398. NULL,
  399. rcBox.left + xCenter,
  400. rcBox.bottom + yMiniBotMar,
  401. 0,
  402. 0,
  403. SWP_NOSIZE | SWP_NOZORDER);
  404. SetWindowPos(
  405. GetDlgItem(hWnd, IDCANCEL),
  406. NULL,
  407. rcBox.left + xButton + xCenter * 2,
  408. rcBox.bottom + yMiniBotMar,
  409. 0,
  410. 0,
  411. SWP_NOSIZE | SWP_NOZORDER);
  412. SetWindowPos(
  413. GetDlgItem(hWnd, IDH_DLG_MIDI_KEYEDIT),
  414. NULL,
  415. rcBox.left + xButton * 2 + xCenter * 3,
  416. rcBox.bottom + yMiniBotMar,
  417. 0,
  418. 0,
  419. SWP_NOSIZE | SWP_NOZORDER);
  420. SetWindowPos(
  421. hScroll,
  422. NULL,
  423. rcBox.right,
  424. rcBox.top,
  425. GetSystemMetrics(SM_CXVSCROLL),
  426. rcBox.bottom - rcBox.top + 1,
  427. SWP_NOZORDER);
  428. iVertMax = max(0, MIDIPATCHSIZE - nLines);
  429. iVertPos = min(iVertMax, iVertPos);
  430. SetScrollRange(hScroll, SB_CTL, 0, iVertMax, FALSE);
  431. SetScrollPos(hScroll, SB_CTL, iVertPos, TRUE);
  432. if (iCurPos >= 0 && iCurPos < nLines)
  433. KeySetFocus(PSF_SHOWIFHIDDEN, 1);
  434. else
  435. KeyActiveLine(PAL_HIDE, SWP_NOREDRAW);
  436. } /* KeySize */
  437. /*
  438. * KEYPAINT
  439. */
  440. static
  441. VOID PASCAL KeyPaint(VOID)
  442. {
  443. HPEN hPen = NULL;
  444. LPMIDIKEYMAP lpKey;
  445. PAINTSTRUCT ps;
  446. int i,
  447. iVert,
  448. iLeft,
  449. nBegin,
  450. nEnd,
  451. iTop,
  452. iBottom,
  453. iOctave,
  454. iNote;
  455. BOOL fSelected = FALSE;
  456. char szBuf [30];
  457. BeginPaint(hWnd, &ps);
  458. if (!ps.rcPaint.bottom)
  459. goto DonePainting;
  460. hPen = SelectObject(ps.hdc, GetStockObject(BLACK_PEN));
  461. hFont = SelectObject(ps.hdc, hFont);
  462. fSelected = TRUE;
  463. SetTextColor(ps.hdc, GetSysColor(COLOR_WINDOWTEXT));
  464. SetBkMode(ps.hdc, TRANSPARENT);
  465. if (ps.rcPaint.top < rcBox.top) {
  466. iVert = yChar; // rcBox.top - (yChar * 2) - 1;
  467. TextOut(ps.hdc, 11, iVert, aszSourceKey, lstrlen(aszSourceKey));
  468. TextOut(ps.hdc, rgxPos [1] + xChar - 10, iVert,
  469. aszSourceKeyName, lstrlen(aszSourceKeyName));
  470. }
  471. // calculate top and bottom y coordinates of invalid area
  472. iTop = max(ps.rcPaint.top, rcBox.top);
  473. // if top is below the box, forget about painting
  474. if (iTop > rcBox.bottom)
  475. goto DonePainting;
  476. iBottom = min(ps.rcPaint.bottom, rcBox.bottom);
  477. // calculate left x coordinate of invalid area
  478. iLeft = max(ps.rcPaint.left, rcBox.left);
  479. // calculate beginning and ending data row to be repainted
  480. nBegin = max(0, (iTop - rcBox.top) / yChar);
  481. nEnd = min(nLines, (iBottom - rcBox.top) / yChar);
  482. for (i = 0; i < 4; i++) {
  483. MMoveTo(ps.hdc, rgxPos [i], iTop);
  484. LineTo(ps.hdc, rgxPos [i], iBottom + 1);
  485. }
  486. // vertical position of first line we have to draw
  487. iVert = rcBox.top + nBegin * yChar;
  488. // lock the map
  489. lpKey = (LPMIDIKEYMAP)GlobalLock(hKeyMap);
  490. iOctave = (iVertPos + nBegin) / 12 - 1;
  491. iNote = (iVertPos + nBegin) % 12;
  492. for (i = nBegin; i <= nEnd; i++, iVert += yChar) {
  493. MMoveTo(ps.hdc, iLeft, iVert);
  494. LineTo(ps.hdc, min(ps.rcPaint.right, rcBox.right), iVert);
  495. if (i == nLines)
  496. break;
  497. if (iLeft < rgxPos [1]) {
  498. wsprintf(szBuf, aszKeyNumFormat, iVertPos + i);
  499. TextOut(ps.hdc, rcBox.left + 2, iVert + 2, szBuf, 3);
  500. }
  501. if (iLeft < rgxPos [2]) {
  502. if (!fKeyView) {
  503. if (!LoadString(hLibInst, IDS_KEYMAP_BASE +
  504. iVertPos + i, szBuf, sizeof(szBuf)))
  505. LoadString(hLibInst, IDS_RESERVED, szBuf, sizeof(szBuf));
  506. }
  507. else wsprintf(szBuf, aszNoteOctaveFormat,
  508. (LPSTR)szNotes [iNote], iOctave);
  509. TextOut(ps.hdc, rgxPos [1] + 2, iVert + 2, szBuf,
  510. lstrlen(szBuf));
  511. }
  512. if (iLeft < rgxPos [3] && i != iCurPos) {
  513. wsprintf(szBuf, aszKeyNumFormat, lpKey->bKMap [iVertPos + i]);
  514. TextOut(ps.hdc, rgxPos [2] + 2, iVert + 2, szBuf, 3);
  515. }
  516. if (++iNote > 11) {
  517. iNote = 0;
  518. iOctave++;
  519. }
  520. }
  521. GlobalUnlock(hKeyMap);
  522. DonePainting:
  523. if (fSelected) {
  524. hFont = SelectObject(ps.hdc, hFont);
  525. hPen = SelectObject(ps.hdc, hPen);
  526. }
  527. EndPaint(hWnd, &ps);
  528. } /* KeyPaint */
  529. /*
  530. * KEYARROWSCROLL
  531. *
  532. * Interpret a scroll message for the arrow control and modify
  533. * the value in corresponding Keymap array.
  534. */
  535. static
  536. VOID PASCAL KeyArrowScroll(UINT wParam)
  537. {
  538. LPMIDIKEYMAP lpKey;
  539. BYTE bKey;
  540. lpKey = (LPMIDIKEYMAP)GlobalLock(hKeyMap);
  541. bKey = lpKey->bKMap [iVertPos + iCurPos];
  542. GlobalUnlock(hKeyMap);
  543. switch (wParam) {
  544. case SB_LINEDOWN :
  545. if (!bKey--)
  546. bKey = 127;
  547. break;
  548. case SB_LINEUP :
  549. if (++bKey > 127)
  550. bKey = 0;
  551. break;
  552. default:
  553. break;
  554. }
  555. SetDlgItemInt(hWnd, ID_KEYEDIT, bKey, FALSE);
  556. } /* KeyArrowScroll */
  557. /*
  558. * KEYWINDOWSCROLL
  559. */
  560. static
  561. VOID PASCAL KeyWindowScroll( UINT wParam,
  562. int iPos )
  563. {
  564. HDC hDC;
  565. RECT rc;
  566. int iVertInc;
  567. BOOL fWillBeVisible; // will active line be visible?
  568. switch (wParam) {
  569. case SB_LINEUP :
  570. iVertInc = -1;
  571. break;
  572. case SB_LINEDOWN :
  573. iVertInc = 1;
  574. break;
  575. case SB_PAGEUP :
  576. iVertInc = min(-1, -nLines);
  577. break;
  578. case SB_PAGEDOWN :
  579. iVertInc = max(1, nLines);
  580. break;
  581. case SB_THUMBTRACK :
  582. case SB_THUMBPOSITION :
  583. iVertInc = iPos - iVertPos;
  584. break;
  585. default :
  586. iVertInc = 0;
  587. }
  588. iVertInc = max (-iVertPos, min(iVertInc, iVertMax - iVertPos));
  589. if (iVertInc != 0)
  590. {
  591. iVertPos += iVertInc;
  592. iCurPos -= iVertInc;
  593. if (iCurPos < 0 || iCurPos >= nLines) {
  594. SetFocus(NULL);
  595. fWillBeVisible = FALSE;
  596. }
  597. else
  598. fWillBeVisible = TRUE;
  599. SetScrollPos(hScroll, SB_CTL, iVertPos, TRUE);
  600. hDC = GetDC(hWnd);
  601. ScrollDC(hDC, 0L, -yChar * iVertInc, &rcBox, &rcBox, NULL,
  602. &rc);
  603. ReleaseDC(hWnd, hDC);
  604. if (!fHidden)
  605. KeyActiveLine(PAL_HIDE, SWP_NOREDRAW);
  606. if (fWillBeVisible) {
  607. KeySetFocus(0, 0);
  608. KeyActiveLine(PAL_SHOW, SWP_NOREDRAW);
  609. }
  610. InvalidateRect(hWnd, &rc, TRUE);
  611. UpdateWindow(hWnd);
  612. }
  613. } /* KeyWindowScroll */
  614. /*
  615. * KEYEDITMSG
  616. *
  617. * This function deals with EN_UPDATE and EN_ACTIVATE messages sent
  618. * to the key number edit control through the WM_COMMAND message.
  619. */
  620. static
  621. VOID PASCAL KeyEditMsg(WORD NotifCode)
  622. {
  623. LPMIDIKEYMAP lpKey;
  624. LPBYTE lpbKey;
  625. UINT uVal;
  626. BOOL bTranslate;
  627. if (NotifCode != EN_UPDATE && NotifCode != EN_ACTIVATE)
  628. return;
  629. lpKey = (LPMIDIKEYMAP)GlobalLock(hKeyMap);
  630. switch (NotifCode) {
  631. case EN_UPDATE :
  632. lpbKey = &lpKey->bKMap [iVertPos + iCurPos];
  633. uVal = (UINT)GetDlgItemInt(hWnd, ID_KEYEDIT, &bTranslate, FALSE);
  634. if (uVal <= 127) {
  635. if (*lpbKey != (BYTE) uVal) {
  636. *lpbKey = (BYTE)uVal;
  637. Modify(TRUE);
  638. }
  639. }
  640. else SetDlgItemInt(hWnd, ID_KEYEDIT, *lpbKey, FALSE);
  641. break;
  642. case EN_ACTIVATE :
  643. SetDlgItemInt(hWnd, ID_KEYEDIT, lpKey->bKMap [iVertPos +
  644. iCurPos], FALSE);
  645. break;
  646. default :
  647. break;
  648. }
  649. GlobalUnlock(hKeyMap);
  650. } /* KeyEditMsg */
  651. /*
  652. * KEYBUTTONDOWN
  653. */
  654. static
  655. VOID PASCAL KeyButtonDown(LONG lParam)
  656. {
  657. int x = LOWORD(lParam),
  658. y = HIWORD(lParam),
  659. iPos;
  660. UINT uFlags;
  661. if (x < rcBox.left || x > rcBox.right)
  662. return;
  663. if (y < rcBox.top || y > rcBox.bottom)
  664. return;
  665. iPos = min(nLines - 1, (y - rcBox.top) / yChar);
  666. if (iPos == iCurPos)
  667. return;
  668. if (iCurPos >= 0 && iCurPos < nLines) {
  669. uFlags = PSF_REDRAW;
  670. UpdateWindow(hWnd);
  671. }
  672. else uFlags = PSF_SHOWIFHIDDEN;
  673. iCurPos = iPos;
  674. KeySetFocus(uFlags, x);
  675. } /* KeyButtonDown */
  676. /*
  677. * KEYSETFOCUS
  678. */
  679. static
  680. VOID PASCAL KeySetFocus( UINT uFlags,
  681. int xPos )
  682. {
  683. RECT rc;
  684. int yPos = rcBox.top + iCurPos * yChar;
  685. KeyEditMsg(EN_ACTIVATE);
  686. GetWindowRect(hEdit, &rc);
  687. /* on NT this returns a BOOL success indicator. So what? */
  688. SetWindowPos(hEdit, NULL, rgxPos [2], yPos, 0L, 0L,
  689. SWP_NOZORDER | SWP_NOSIZE);
  690. SetWindowPos(hArrow, NULL, rgxPos [2] + xArrowOffset, yPos, 0,
  691. 0L, SWP_NOZORDER | SWP_NOSIZE);
  692. if (fHidden && uFlags & PSF_SHOWIFHIDDEN) {
  693. KeyActiveLine(PAL_SHOW, 0L);
  694. UpdateWindow(hEdit);
  695. UpdateWindow(hArrow);
  696. }
  697. if (uFlags & PSF_REDRAW && rc.right) {
  698. ScreenToClient(hWnd, (LPPOINT)&rc);
  699. ScreenToClient(hWnd, (LPPOINT)&rc + 1);
  700. rc.right = rcBox.right + 1;
  701. InvalidateRect(hWnd, &rc, FALSE);
  702. UpdateWindow(hWnd);
  703. }
  704. if (!fHidden)
  705. SetFocus(hEdit);
  706. #if defined(WIN16)
  707. SendMessage(hEdit, EM_SETSEL, (WPARAM)NULL, MAKELPARAM(0, 32767));
  708. #else
  709. SendMessage(hEdit, EM_SETSEL, (WPARAM)NULL, (LPARAM)-1);
  710. #endif //WIN16
  711. } /* KeySetFocus */
  712. /*
  713. * KEYACTIVELINE
  714. */
  715. static
  716. VOID PASCAL KeyActiveLine( UINT uCase,
  717. UINT uFlags )
  718. {
  719. static const UINT uDefFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
  720. switch (uCase) {
  721. case PAL_SHOW :
  722. if (!fHidden)
  723. return;
  724. uFlags |= SWP_SHOWWINDOW;
  725. fHidden = FALSE;
  726. break;
  727. case PAL_HIDE :
  728. if (fHidden)
  729. return;
  730. uFlags |= SWP_HIDEWINDOW;
  731. fHidden = TRUE;
  732. break;
  733. default :
  734. break;
  735. }
  736. uFlags |= uDefFlags;
  737. SetWindowPos(hEdit, NULL, 0L, 0L, 0L, 0L, uFlags);
  738. SetWindowPos(hArrow, NULL, 0L, 0L, 0L, 0L, uFlags);
  739. if (uCase == PAL_SHOW && !fHidden)
  740. SetFocus(hEdit);
  741. } /* KeyActiveLine */
  742. /*
  743. * KEYSAVE
  744. */
  745. static int PASCAL KeySave(
  746. HWND hdlg,
  747. BOOL bQuery)
  748. {
  749. LPMIDIKEYMAP lpKey;
  750. MMAPERR mmaperr;
  751. int iRet = 0; // Should be a value which is NOT IDCANCEL or IDYES
  752. if (bQuery) {
  753. iRet = QuerySave();
  754. if (iRet != IDYES)
  755. return iRet;
  756. }
  757. lpKey = (LPMIDIKEYMAP)GlobalLock(hKeyMap);
  758. mmaperr = mapWrite(MMAP_KEY, (LPVOID)lpKey);
  759. GlobalUnlock(hKeyMap);
  760. if (mmaperr != MMAPERR_SUCCESS) {
  761. VShowError(hdlg, mmaperr);
  762. return IDCANCEL;
  763. }
  764. Modify(FALSE);
  765. if (fNew)
  766. fNew = FALSE;
  767. return iRet;
  768. } /* KeySave */