/*++ Copyright (c) 1991-1997, Microsoft Corporation All rights reserved. Module Name: charmap.c Abstract: This module contains the main routines for the Charmap utility, an interface for selecting special characters. Revision History: --*/ // // Include Files. // #define WIN31 #include "windows.h" #include #include "charmap.h" #include "stdlib.h" #include "tchar.h" #ifdef UNICODE #include "wchar.h" #else #include "stdio.h" #endif #include "commctrl.h" #include // // Macros. // #define FMagData(psycm) ((psycm)->xpMagCurr != 0) #define abs(x) (((x) >= 0) ? (x) : (-(x))) // // Constant Declarations. // #define STATUSPOINTSIZE 8 // point size of status bar font #define FE_STATUSPOINTSIZE 10 // FE point size of status bar font #define DX_BITMAP 20 // width of TT bitmap #define DY_BITMAP 12 // height of TT bitmap #define BACKGROUND 0x000000FF // bright blue #define BACKGROUNDSEL 0x00FF00FF // bright purple #define BUTTONFACE 0x00C0C0C0 // bright grey #define BUTTONSHADOW 0x00808080 // dark grey #define TOOLBARPOINTSIZE 21 // height of toolbar in points // Font types #define PS_OPENTYPE_FONT 0x0001 #define TT_OPENTYPE_FONT 0x0002 #define TRUETYPE_FONT 0x0004 #define TYPE1_FONT 0x0008 // // Debug Print Code. // #if 0 TCHAR szDOUT[3] = TEXT("A\n"); TCHAR szDbgBuf[256]; #define DOUTL(p) OutputDebugString(TEXT(p)) #define DOUTCHN(ch) if(0){}else {szDOUT[0] = ch; OutputDebugString(szDOUT);} #define DPRINT(p) if(0){}else {wsprintf p; OutputDebugString(szDbgBuf);} #else #define DOUTL(p) #define DOUTCHN(ch) #define DPRINT(p) #endif // // Global Variables. // HANDLE hInst; INT cchSymRow = 32; // number of characters across the character grid INT cchSymCol = 8; // number of rows in the character grid UTCHAR chSymFirst = 32; UTCHAR chSymLast = 255; UTCHAR chRangeFirst = 32; UTCHAR chRangeLast = 255; SYCM sycm; // tons of data need to do char grid painting WORD wCFRichText = 0; // private clipboard format, rich text format HFONT hFontClipboard = NULL; // tells us which font is in the clipboard HANDLE hstrClipboard = NULL; // contains the string which is in the clipboard BOOL fDelClipboardFont = FALSE; // the clipboard font needs to be deleted INT iControl = ID_CHARGRID; // index indicating which control has focus HBITMAP hbmFont = NULL; // TT bitmap drawn before font facenames in combo LONG lEditSel = 0; // contains the selection range of the EC HBRUSH hStaticBrush; // used for static controls during WM_CTLCOLOR // // Currently there is no defined interface for querying what character // ranges a Unicode font supports. For now, this table only has the subsets // that contain characters supported by the Lucida Sans Unicode font // uncommented. When we get an API that allows querying the font driver for // ranges of Unicode characters supported (and whether or not a font is a // Unicode font!) then all entries can be uncommented. // USUBSET aSubsetData[] = { { 0x0020, 0x00ff, IDS_WINDOWS }, { 0x0020, 0x00ff, IDS_LATIN1 }, { 0x0100, 0x017f, IDS_LATINEXA }, { 0x0180, 0x024f, IDS_LATINEXB }, { 0x0250, 0x02af, IDS_IPAEX }, { 0x02b0, 0x02ff, IDS_SPACINGMODIFIERS }, { 0x0300, 0x036f, IDS_COMBININGDIACRITICS }, { 0x0370, 0x03cf, IDS_BASICGREEK }, { 0x03d0, 0x03ff, IDS_GREEKSYMBOLS }, { 0x0400, 0x04ff, IDS_CYRILLIC }, { 0x0530, 0x058f, IDS_ARMENIAN }, { 0x0590, 0x05ff, IDS_HEBREW }, { 0x0600, 0x0652, IDS_BASICARABIC }, { 0x0653, 0x06ff, IDS_ARABICEX }, { 0x0900, 0x097f, IDS_DEVANAGARI }, { 0x0980, 0x09ff, IDS_BENGALI }, { 0x0a00, 0x0a7f, IDS_GURMUKHI }, { 0x0a80, 0x0aff, IDS_GUJARATI }, { 0x0b00, 0x0b7f, IDS_ORIYA }, { 0x0b80, 0x0bff, IDS_TAMIL }, { 0x0c00, 0x0c7f, IDS_TELUGU }, { 0x0c80, 0x0cff, IDS_KANNADA }, { 0x0d00, 0x0d7f, IDS_MALAYALAM }, { 0x0e00, 0x0e7f, IDS_THAI }, { 0x0e80, 0x0eff, IDS_LAO }, { 0x10d0, 0x10ff, IDS_BASICGEORGIAN }, { 0x10a0, 0x10cf, IDS_GEORGIANEX }, { 0x1100, 0x11ff, IDS_HANGULJAMO }, { 0x1e00, 0x1eff, IDS_LATINEXADDITIONAL }, { 0x1f00, 0x1fff, IDS_GREEKEX }, { 0x2000, 0x206f, IDS_GENERALPUNCTUATION }, { 0x2070, 0x209f, IDS_SUPERANDSUBSCRIPTS }, { 0x20a0, 0x20cf, IDS_CURRENCYSYMBOLS }, { 0x20d0, 0x20ff, IDS_COMBININGDIACRITICSFORSYMBOLS }, { 0x2100, 0x214f, IDS_LETTERLIKESYMBOLS }, { 0x2150, 0x218f, IDS_NUMBERFORMS }, { 0x2190, 0x21ff, IDS_ARROWS }, { 0x2200, 0x22ff, IDS_MATHEMATICALOPS }, { 0x2300, 0x23ff, IDS_MISCTECHNICAL }, { 0x2400, 0x243f, IDS_CONTROLPICTURES }, { 0x2440, 0x245f, IDS_OPTICALCHAR }, { 0x2460, 0x24ff, IDS_ENCLOSEDALPHANUM }, { 0x2500, 0x257f, IDS_BOXDRAWING }, { 0x2580, 0x259f, IDS_BLOCKELEMENTS }, { 0x25a0, 0x25ff, IDS_GEOMETRICSHAPES }, { 0x2600, 0x26ff, IDS_MISCDINGBATS }, { 0x2700, 0x27bf, IDS_DINGBATS }, { 0x3000, 0x303f, IDS_CJKSYMBOLSANDPUNC }, { 0x3040, 0x309f, IDS_HIRAGANA }, { 0x30a0, 0x30ff, IDS_KATAKANA }, { 0x3100, 0x312f, IDS_BOPOMOFO }, { 0x3130, 0x318f, IDS_HANGULCOMPATIBILITYJAMO }, { 0x3190, 0x319f, IDS_CJKMISC }, { 0x3200, 0x32ff, IDS_ENCLOSEDCJKLETTERSANDMONTHS }, { 0x3300, 0x33ff, IDS_CJKCOMPATIBILITY }, { 0x4e00, 0x9fff, IDS_CJKUNIFIEDIDEOGRAPHS }, { 0xac00, 0xd7a3, IDS_HANGUL }, { 0xe000, 0xf8ff, IDS_PRIVATEUSEAREA }, { 0xf900, 0xfaff, IDS_CJKCOMPATIBILITYIDEOGRAPHS }, { 0xfb00, 0xfb4f, IDS_ALPAHPRESENTATIONFORMS }, { 0xfb50, 0xfdff, IDS_ARABICPRESENTATIONFORMSA }, { 0xfe30, 0xfe4f, IDS_CJKCOMPFORMS }, { 0xfe50, 0xfe6f, IDS_SMALLFORMVARIANTS }, { 0xfe70, 0xfefe, IDS_ARABICPRESENTATIONFORMSB }, { 0xff00, 0xffef, IDS_HALFANDFULLWIDTHFORMS }, { 0xfff0, 0xfffd, IDS_SPECIALS } }; INT cSubsets = sizeof(aSubsetData) / sizeof(USUBSET); INT iCurSubset = 0; // index of current Unicode subset - default to Latin-1 // // Useful window handles. // HWND hwndDialog; HWND hwndCharGrid; // // Data used to draw the status bar. // RECT rcStatusLine; // bounding rect for status bar RECT rcToolbar[2]; // bounding rects for toolbars INT dyStatus; // height of status bar INT dyToolbar[2]; // height of tool bars INT dxHelpField; // width of help window INT dxKeystrokeField; // width of keystroke window TCHAR szKeystrokeText[MAX_PATH]; // buffer for keystroke text TCHAR szKeystrokeLabel[30]; // buffer for keystroke label TCHAR szSpace[15]; // strings for keystroke description TCHAR szCtrl[15]; TCHAR szCtrlAlt[25]; TCHAR szShiftCtrlAlt[25]; TCHAR szAlt[15]; TCHAR szUnicodeLabel[23]; // buffer for Unicode label INT iKeystrokeTextStart; // place to start appending text to above INT iUnicodeLabelStart; // place to start appending text to above HFONT hfontStatus; // font used for text of status bar //////////////////////////////////////////////////////////////////////////// // // WinMain // // Calls initialization function, processes message loop, cleanup. // //////////////////////////////////////////////////////////////////////////// INT WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; if (!InitApplication(hInstance)) { return (FALSE); } // // Perform initialization for this instance. // if (!InitInstance(hInstance, nCmdShow)) { return (FALSE); } while (GetMessage(&msg, NULL, 0, 0)) { // // Filter for possible tabs now to implement context sensitive help. // if (msg.message == WM_KEYDOWN) { if (!UpdateHelpText(&msg, NULL)) { continue; } } // // Main message loop. // if (!IsDialogMessage(hwndDialog, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } // // Free up some stuff. // if (hfontStatus) { DeleteObject(hfontStatus); } if (hbmFont) { DeleteObject(hbmFont); } return (msg.wParam); } //////////////////////////////////////////////////////////////////////////// // // InitApplication // // Initializes window data and registers window class. // //////////////////////////////////////////////////////////////////////////// BOOL InitApplication( HANDLE hInstance) { WNDCLASS wc; // // Register a window class that we will use to draw the character // grid into. // wc.style = CS_DBLCLKS; wc.lpfnWndProc = CharGridWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = TEXT("CharGridWClass"); if (!RegisterClass(&wc)) { return (FALSE); } wc.style = 0; wc.lpfnWndProc = DefDlgProc; wc.cbClsExtra = 0; wc.cbWndExtra = DLGWINDOWEXTRA; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDIC_CHARMAP)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = TEXT("MyDlgClass"); if (!RegisterClass(&wc)) { return (FALSE); } } //////////////////////////////////////////////////////////////////////////// // // InitInstance // // Does some initialization and creates main window which is a dialog. // //////////////////////////////////////////////////////////////////////////// BOOL InitInstance( HANDLE hInstance, INT nCmdShow) { INT i; CHARSETINFO csi; DWORD dw = GetACP(); LANGID PrimaryLangId = (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale()))); BOOL bFE = ((PrimaryLangId == LANG_JAPANESE) || (PrimaryLangId == LANG_KOREAN) || (PrimaryLangId == LANG_CHINESE)); // // Save the instance handle in a global variable. // hInst = hInstance; // // This font will be used to paint the status line. // if (!TranslateCharsetInfo((DWORD*)dw, &csi, TCI_SRCCODEPAGE)) { csi.ciCharset = ANSI_CHARSET; } hfontStatus = CreateFont( -PointsToHeight(bFE ? FE_STATUSPOINTSIZE : STATUSPOINTSIZE), 0, 0, 0, 400, 0, 0, 0, csi.ciCharset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH, TEXT("MS Shell Dlg") ); dyStatus = 2 * PointsToHeight(STATUSPOINTSIZE); dyToolbar[0] = PointsToHeight(TOOLBARPOINTSIZE); dyToolbar[1] = PointsToHeight(TOOLBARPOINTSIZE); // // Load the Unicode subset names before initializing the main window. // for (i = 0; i < cSubsets; i++) { if (!LoadString( hInst, aSubsetData[i].StringResId, (LPTSTR)aSubsetData[i].Name, LF_SUBSETSIZE)) { return (FALSE); } } // // Create a main window for this application instance. // if (!(hwndDialog = CreateDialog( hInstance, TEXT("CharMap"), NULL, CharMapDlgProc ))) { return (FALSE); } // // Initialize some strings used for the Keystroke status bar field. // For international purposes, this string could be length 0. // LoadString( hInst, IDS_KEYSTROKE, (LPTSTR)szKeystrokeLabel, BTOC(sizeof(szKeystrokeLabel)) ); if (!LoadString( hInst, IDS_UNICODELABEL, (LPTSTR)szUnicodeLabel, BTOC(sizeof(szUnicodeLabel)) )) { if (!LoadString( hInst, IDS_SPACE, (LPTSTR)szSpace, BTOC(sizeof(szSpace)) )) { return (FALSE); } } if (!LoadString( hInst, IDS_CTRL, (LPTSTR)szCtrl, BTOC(sizeof(szCtrl)) )) { return (FALSE); } if (!LoadString( hInst, IDS_CTRLALT, (LPTSTR)szCtrlAlt, BTOC(sizeof(szCtrlAlt)) )) { return (FALSE); } if (!LoadString( hInst, IDS_SHIFTCTRLALT, (LPTSTR)szShiftCtrlAlt, BTOC(sizeof(szShiftCtrlAlt)) )) { return (FALSE); } if (!LoadString( hInst, IDS_ALT, (LPTSTR)szAlt, BTOC(sizeof(szAlt)) )) { return (FALSE); } // // Store the index to where we start adding status line text changes. // iKeystrokeTextStart = lstrlen(szKeystrokeLabel); iUnicodeLabelStart = lstrlen(szUnicodeLabel); // // Initialize keystroke text, make the window visible, // update its client area, and return "success". // UpdateKeystrokeText(NULL, sycm.fAnsiFont, sycm.chCurr, FALSE); ShowWindow(hwndDialog, nCmdShow); UpdateWindow(hwndDialog); return (TRUE); } //////////////////////////////////////////////////////////////////////////// // // ConvertANSIFontToUnicode // //////////////////////////////////////////////////////////////////////////// WCHAR ConvertANSIFontToUnicode( HWND hwnd, HFONT hFont, CHAR ch) { WORD cp = CP_ACP; WCHAR wch; HDC hdc; hdc = GetDC(hwnd); if (hdc != NULL) { HFONT hfOld; TEXTMETRIC tm; CHARSETINFO csi; DWORD cs; hfOld = SelectObject(hdc, hFont); if (GetTextMetrics(hdc, &tm)) { cs = MAKELONG(tm.tmCharSet, 0); if (TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET)) { cp = csi.ciACP; } else { DPRINT(( szDbgBuf, TEXT("CvtAtoW: TranslateCharsetInfo(cset=%d) returned 0! (GetLastErr=%d), using CP_ACP\n"), cs, GetLastError() )); } } SelectObject(hdc, hfOld); ReleaseDC(hwnd, hdc); } if (MultiByteToWideChar(cp, 0, &ch, 1, &wch, 1) != 1) { if (MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1) != 1) { wch = (WCHAR)(BYTE)ch; } } DPRINT(( szDbgBuf, TEXT("CvtAtoW: 0x%02x '%c' (CP:%d) -> U'%04X'\n"), (DWORD)(BYTE)ch, ch, cp, (DWORD)wch )); return (wch); } //////////////////////////////////////////////////////////////////////////// // // EnumChildProc // // Gets called during init for each child window. // //////////////////////////////////////////////////////////////////////////// BOOL CALLBACK EnumChildProc( HWND hwnd, LPARAM lParam) { LONG st; TCHAR szClass[MAX_PATH]; // // Get control class. // GetClassName(hwnd, szClass, MAX_PATH); if (lstrcmpi(szClass, TEXT("button")) == 0 ) { // // If it is a button, set the ex style to NOTIFYPARENT. // st = GetWindowLong(hwnd, GWL_EXSTYLE); st = st & ~WS_EX_NOPARENTNOTIFY; SetWindowLong(hwnd, GWL_EXSTYLE, st); } return (TRUE); } //////////////////////////////////////////////////////////////////////////// // // CharMapDlgProc // // Processes messages for the main window. This window is a dialog box. // //////////////////////////////////////////////////////////////////////////// INT_PTR APIENTRY CharMapDlgProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case ( WM_CTLCOLORSTATIC ) : { POINT point; SetBkColor((HDC)wParam, GetSysColor(COLOR_BTNFACE)); UnrealizeObject(hStaticBrush); point.x = point.y = 0; ClientToScreen(hWnd, &point); return ((INT_PTR)hStaticBrush); break; } case ( WM_INITDIALOG ) : { RECT rectParent, rectTopRightControl, rect; POINT pt; INT iSubset; HWND hwndCMSB; // // Set buttons to send WM_PARENTNOTIFY. // EnumChildWindows(hWnd, EnumChildProc, (LPARAM)NULL ); // // Create the character grid with dimensions which just fit // inside the space allowed in the dialog. When it processes // the WM_CREATE message it will be sized and centered more // accurately. // GetClientRect(hWnd, &rectParent); GetWindowRect(GetDlgItem(hWnd, ID_CLOSE), &rectTopRightControl); ScreenToClient(hWnd, (LPPOINT)&(rectTopRightControl.left)); ScreenToClient(hWnd, (LPPOINT)&(rectTopRightControl.right)); if (!(hwndCharGrid = CreateWindow( TEXT("CharGridWClass"), NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 1, rectParent.top + dyToolbar[0] + dyToolbar[1], rectParent.right - 1, rectParent.bottom - rectParent.top - dyStatus - dyToolbar[0] - dyToolbar[1] - 1, hWnd, (HMENU)ID_CHARGRID, hInst, NULL ))) { DestroyWindow(hWnd); break; } GetWindowRect(hwndCharGrid, &rect); pt.x = rect.right; pt.y = rect.top; ScreenToClient(hWnd, &pt); hwndCMSB = CreateWindowEx( 0L, TEXT("SCROLLBAR"), NULL, WS_CHILD | SBS_VERT | WS_VISIBLE | WS_TABSTOP, pt.x + 1, pt.y + 1, sycm.dxpBox, sycm.dypCM, hWnd, (HMENU)ID_MAPSCROLL, hInst, NULL ); hStaticBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); // // Initialize the status line data. // dxHelpField = 21 * rectParent.right / 32; dxKeystrokeField = 9 * rectParent.right / 32; rcStatusLine = rectParent; rcStatusLine.top = rcStatusLine.bottom - dyStatus; // // Initialize the toolbars. // rcToolbar[0] = rectParent; rcToolbar[0].bottom = rcToolbar[0].top + dyToolbar[0]; rcToolbar[1] = rcToolbar[0]; rcToolbar[1].top = rcToolbar[0].bottom + GetSystemMetrics(SM_CYBORDER); rcToolbar[1].bottom = rcToolbar[1].top + dyToolbar[1]; // // Disable Copy button. // EnableWindow(GetDlgItem(hWnd, ID_COPY), FALSE); // // Fill "Subset" list box. // for (iSubset = 0; iSubset < cSubsets; iSubset++) { SendDlgItemMessage( hWnd, ID_UNICODESUBSET, CB_ADDSTRING, 0, (DWORD)aSubsetData[iSubset].Name ); } iCurSubset = SelectInitialSubset(hWnd); // // Fall through to WM_FONTCHANGE... // } case ( WM_FONTCHANGE ) : { HDC hdc = GetDC(hWnd); // // Get the fonts from the system and put them in the font // selection combo box. // if (message == WM_FONTCHANGE) { SaveCurrentFont(hWnd); SendDlgItemMessage(hWnd, ID_FONT, CB_RESETCONTENT, 0, 0L); } EnumFontFamilies(hdc, NULL, (FONTENUMPROC)FontLoadProc, (LPARAM)hWnd); ReleaseDC(hWnd, hdc); // // Setup character dimensions and select this font. // RecalcCharMap( hWnd, &sycm, SelectInitialFont(hWnd), (message == WM_FONTCHANGE) ); SetEditCtlFont(hWnd, ID_STRING, sycm.hFont); if (message == WM_INITDIALOG) { SetFocus(hwndCharGrid); // // Fall through to WM_SYSCOLORCHANGE... // } else { break; } } case ( WM_SYSCOLORCHANGE ) : { if (hbmFont) { DeleteObject(hbmFont); } hbmFont = LoadBitmaps(IDBM_TT); DeleteObject(hStaticBrush); hStaticBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); break; } case ( WM_PARENTNOTIFY ) : { POINTS points; DWORD dwMsgPos; POINT point; DPRINT(( szDbgBuf, TEXT("WM_PARENTNOTIFY: lParam:0x%08lX, wParam:0x%08lX\n"), (DWORD)lParam, (DWORD)wParam )); // // We process this message to implement the context sensitive // help. Downclicks to controls are found here, the help // message is updated in the status bar. // // The parameters with this message are unreliable! // if (LOWORD(wParam) == WM_LBUTTONDOWN) { dwMsgPos = GetMessagePos(); points = MAKEPOINTS(dwMsgPos); point.x = points.x; point.y = points.y; UpdateHelpText(NULL, WindowFromPoint(point)); } break; } case ( WM_VSCROLL ) : { ProcessScrollMsg(hWnd, LOWORD(wParam), HIWORD(wParam)); break; } case ( WM_PAINT ) : { HBRUSH hBrush; RECT rcTemp, rectNextButton; INT dyBorder, dxBorder; PAINTSTRUCT ps; HDC hdc; // // This code implements painting of the status bar. // hdc = BeginPaint(hWnd, &ps); rcTemp = rcStatusLine; dyBorder = GetSystemMetrics(SM_CYBORDER); dxBorder = GetSystemMetrics(SM_CXBORDER); // // Make the whole thing grey. // if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE))) { FillRect(hdc, &rcTemp, hBrush); rcTemp.left = rcToolbar[0].left; rcTemp.top = rcToolbar[0].top; rcTemp.right = rcToolbar[1].right; rcTemp.bottom = rcToolbar[1].bottom; FillRect(hdc, &rcTemp, hBrush); DeleteObject(hBrush); } GetWindowRect(GetDlgItem(hWnd, ID_TOPLEFT), &rectNextButton); ScreenToClient(hWnd, (LPPOINT)&(rectNextButton.left)); ScreenToClient(hWnd, (LPPOINT)&(rectNextButton.right)); // // Solid black line across bottom of toolbar. // if (hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME))) { #ifdef USE_MIRRORING DWORD dwLayout; GetProcessDefaultLayout(&dwLayout); if(dwLayout & LAYOUT_RTL) { // // Interchange the right and left values. // int tmp = rectNextButton.left; rectNextButton.left = rectNextButton.right; rectNextButton.right = tmp; } #endif rcTemp = rcToolbar[0]; rcTemp.top = rcTemp.bottom; rcTemp.bottom += dyBorder; rcTemp.left = rectNextButton.left - 2 - dxBorder; FillRect(hdc, &rcTemp, hBrush); rcTemp = rcToolbar[1]; rcTemp.top = rcTemp.bottom; rcTemp.bottom += dyBorder; FillRect(hdc, &rcTemp, hBrush); // // Vertical line. // rcTemp.top = rcToolbar[0].top; rcTemp.bottom = rcToolbar[1].bottom; rcTemp.left = rectNextButton.left - 2 - dxBorder; rcTemp.right = rectNextButton.left - 2; FillRect(hdc, &rcTemp, hBrush); DeleteObject(hBrush); } if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW))) { // // Status line top. // rcTemp.left = 8 * dyBorder; rcTemp.right = rcTemp.left + dxHelpField; rcTemp.top = rcStatusLine.top + dyBorder * 2; rcTemp.bottom = rcTemp.top + dyBorder; FillRect(hdc, &rcTemp, hBrush); // // Keystroke line top. // rcTemp.right = rcStatusLine.right - 8 * dyBorder; rcTemp.left = rcTemp.right - dxKeystrokeField; FillRect(hdc, &rcTemp, hBrush); // // Status line left side. // rcTemp = rcStatusLine; rcTemp.left = 8 * dyBorder; rcTemp.right = rcTemp.left + dyBorder; rcTemp.top += dyBorder * 2; rcTemp.bottom -= dyBorder * 2; FillRect(hdc, &rcTemp, hBrush); // // Keystroke line left side. // rcTemp.left = rcStatusLine.right - 9 * dyBorder - dxKeystrokeField; rcTemp.right = rcTemp.left + dyBorder; FillRect(hdc, &rcTemp, hBrush); DeleteObject(hBrush); } if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT))) { // // Status line bottom. // rcTemp.left = 8 * dyBorder; rcTemp.right = rcTemp.left + dxHelpField; rcTemp.top = rcStatusLine.bottom - 3 * dyBorder; rcTemp.bottom = rcTemp.top + dyBorder; FillRect(hdc, &rcTemp, hBrush); // // Keystroke line bottom. // rcTemp.right = rcStatusLine.right - 8 * dyBorder; rcTemp.left = rcTemp.right - dxKeystrokeField; FillRect(hdc, &rcTemp, hBrush); // // Status line right side. // rcTemp = rcStatusLine; rcTemp.left = 8 * dyBorder + dxHelpField; rcTemp.right = rcTemp.left + dyBorder; rcTemp.top += dyBorder * 2; rcTemp.bottom -= dyBorder * 2; FillRect(hdc, &rcTemp, hBrush); // // Keystroke line right side. // rcTemp.left = rcStatusLine.right - 8 * dyBorder; rcTemp.right = rcTemp.left + dyBorder; FillRect(hdc, &rcTemp, hBrush); DeleteObject(hBrush); } // // Solid black line across top. // if (hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME))) { rcTemp = rcStatusLine; rcTemp.bottom = rcTemp.top; rcTemp.top -= dyBorder; FillRect(hdc, &rcTemp, hBrush); DeleteObject(hBrush); } PaintStatusLine(hdc, TRUE, TRUE); EndPaint(hWnd, &ps); return (TRUE); } case ( WM_MEASUREITEM ) : { HDC hDC; HFONT hFont; TEXTMETRIC tm; hDC = GetDC(NULL); hFont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0L); if (hFont) { hFont = SelectObject(hDC, hFont); } GetTextMetrics(hDC, &tm); if (hFont) { SelectObject(hDC, hFont); } ReleaseDC(NULL, hDC); ((LPMEASUREITEMSTRUCT)lParam)->itemHeight = max(tm.tmHeight, DY_BITMAP); break; } case ( WM_DRAWITEM ) : { if (((LPDRAWITEMSTRUCT)lParam)->itemID != -1) { DrawFamilyComboItem((LPDRAWITEMSTRUCT)lParam); } break; } case ( WM_ASKCBFORMATNAME ) : { LoadString(hInst, IDS_RTF, (LPTSTR)lParam, wParam); return (TRUE); } case ( WM_PAINTCLIPBOARD ) : { LPPAINTSTRUCT lpPS; HANDLE hFont; LPTSTR lpstrText; if (hstrClipboard) { // // Setup. // lpPS = (LPPAINTSTRUCT)GlobalLock((HANDLE)lParam); lpstrText = (LPTSTR)GlobalLock(hstrClipboard); // // Paint. // hFont = SelectObject(lpPS->hdc, hFontClipboard); TextOut(lpPS->hdc, 0, 0, lpstrText, lstrlen(lpstrText)); SelectObject(lpPS->hdc, hFont); // // Cleanup. // GlobalUnlock(hstrClipboard); GlobalUnlock((HANDLE)lParam); } return (TRUE); } case ( WM_CLOSE ) : { DestroyWindow(hWnd); return (TRUE); } case ( WM_COMMAND ) : { switch (GET_WM_COMMAND_ID(wParam, lParam)) { case ( IDCANCEL ) : case ( ID_CLOSE ) : { DestroyWindow(hWnd); return (TRUE); break; } case ( ID_SELECT ) : { WCHAR wch = sycm.chCurr; if (sycm.fAnsiFont) { wch = ConvertANSIFontToUnicode( hWnd, sycm.hFont, (char)wch ); } SendDlgItemMessage(hWnd, ID_STRING, WM_CHAR, (WPARAM)wch, 0L); break; } case ( ID_COPY ) : { CopyString(hWnd); return (TRUE); break; } case ( ID_FONT ) : { if (HIWORD(wParam) == CBN_SELCHANGE) { RecalcCharMap( hWnd, &sycm, (INT)SendDlgItemMessage( hWnd, ID_FONT, CB_GETCURSEL, 0, 0L ), TRUE ); SetEditCtlFont(hWnd, ID_STRING, sycm.hFont); } else if (HIWORD(wParam) == CBN_SETFOCUS) { // // Necessary if hotkey is used to get to the CB. // UpdateHelpText(NULL, (HWND)lParam); } return (TRUE); break; } case ( ID_UNICODESUBSET ) : { if (HIWORD(wParam) == CBN_SELCHANGE) { INT iSubset; INT cEntries; iSubset = (INT)SendDlgItemMessage( hWnd, ID_UNICODESUBSET, CB_GETCURSEL, 0, 0 ); SubSetChanged( hWnd, iSubset, aSubsetData[iSubset].BeginRange, aSubsetData[iSubset].EndRange ); cEntries = (INT)SendDlgItemMessage( hWnd, ID_UNICODESUBSET, CB_GETCOUNT, 0, 0 ) - 1; EnableWindow( GetDlgItem(hWnd, ID_PREVSUBSET), iSubset > 0 ); EnableWindow( GetDlgItem(hWnd, ID_NEXTSUBSET), iSubset < cEntries ); } else if (HIWORD(wParam) == CBN_SETFOCUS) { // // Necessary if hotkey is used to get to the CB. // UpdateHelpText(NULL, (HWND)lParam); } return (0L); break; } case ( ID_NEXTSUBSET ) : { INT iCurSelection, iNumEntries; iCurSelection = (INT)SendDlgItemMessage( hWnd, ID_UNICODESUBSET, CB_GETCURSEL, 0, 0 ); if (iCurSelection == CB_ERR) { return (0L); } iNumEntries = (INT)SendDlgItemMessage( hWnd, ID_UNICODESUBSET, CB_GETCOUNT, 0, 0 ); if (iNumEntries == CB_ERR) { return (0L); } if (iCurSelection++ < (iNumEntries - 1)) { if (iCurSelection == 1) { // // Enable Previous button. // EnableWindow(GetDlgItem(hWnd, ID_PREVSUBSET), TRUE); } SendDlgItemMessage( hWnd, ID_UNICODESUBSET, CB_SETCURSEL, iCurSelection, 0 ); SubSetChanged( hWnd, iCurSelection, aSubsetData[iCurSelection].BeginRange, aSubsetData[iCurSelection].EndRange ); if (iCurSelection == (iNumEntries - 1)) { HWND hwndButton; EnableWindow(GetDlgItem(hWnd, ID_NEXTSUBSET), FALSE); // // Only reset the button style and focus if // the "Next" button currently has it. // if (iControl == ID_NEXTSUBSET) { SendDlgItemMessage( hwndDialog, ID_PREVSUBSET, BM_SETSTYLE, BS_DEFPUSHBUTTON, 1 ); SendDlgItemMessage( hwndDialog, ID_NEXTSUBSET, BM_SETSTYLE, BS_PUSHBUTTON, 1 ); hwndButton = GetDlgItem(hWnd, ID_PREVSUBSET); SetFocus(hwndButton); UpdateHelpText(NULL, hwndButton); } } } return (0L); break; } case ( ID_PREVSUBSET ) : { INT iCurSelection; iCurSelection = (INT)SendDlgItemMessage( hWnd, ID_UNICODESUBSET, CB_GETCURSEL, 0, 0 ); if (iCurSelection == CB_ERR) { return (0L); } if (iCurSelection > 0) { iCurSelection--; if (iCurSelection == (cSubsets - 2)) { // // Enable Next button. // EnableWindow(GetDlgItem(hWnd, ID_NEXTSUBSET), TRUE); } SendDlgItemMessage( hWnd, ID_UNICODESUBSET, CB_SETCURSEL, iCurSelection, 0 ); SubSetChanged( hWnd, iCurSelection, aSubsetData[iCurSelection].BeginRange, aSubsetData[iCurSelection].EndRange ); if (iCurSelection == 0) { HWND hwndButton; EnableWindow(GetDlgItem(hWnd, ID_PREVSUBSET), FALSE); // // Only reset the button style and focus if // the "Previous" button currently has it. // if (iControl == ID_PREVSUBSET) { SendDlgItemMessage( hwndDialog, ID_NEXTSUBSET, BM_SETSTYLE, BS_DEFPUSHBUTTON, 1 ); SendDlgItemMessage( hwndDialog, ID_PREVSUBSET, BM_SETSTYLE, BS_PUSHBUTTON, 1 ); hwndButton = GetDlgItem(hWnd, ID_NEXTSUBSET); SetFocus(hwndButton); UpdateHelpText(NULL, hwndButton); } } } return (0L); break; } case ( ID_STRING ) : { if (HIWORD(wParam) == EN_SETFOCUS) { // // Necessary if hotkey is used to get to the EC. // UpdateHelpText(NULL, (HWND)lParam); } else if (HIWORD(wParam) == EN_CHANGE) { // // Disable Copy button if there are no chars in EC. // INT iLength; iLength = GetWindowTextLength((HWND)lParam); EnableWindow(GetDlgItem(hWnd, ID_COPY), (BOOL)iLength); } break; } case ( ID_HELP ) : { DoHelp(hWnd, TRUE); break; } } break; } case ( WM_DESTROY ) : { SaveCurrentFont(hWnd); SaveCurrentSubset(hWnd); DoHelp(hWnd, FALSE); DeleteObject(hStaticBrush); PostQuitMessage(0); break; } case ( WM_ACTIVATEAPP ) : { if (wParam) { SendDlgItemMessage( hWnd, ID_STRING, EM_SETSEL, LOWORD(lEditSel), HIWORD(lEditSel) ); } else { lEditSel = SendDlgItemMessage(hWnd, ID_STRING, EM_GETSEL, 0, 0L); SendDlgItemMessage(hWnd, ID_STRING, EM_SETSEL, 0, 0L); } break; } } return (0L); } //////////////////////////////////////////////////////////////////////////// // // CharGridWndProc // // Processes messages for the character grid window. // //////////////////////////////////////////////////////////////////////////// LRESULT APIENTRY CharGridWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case ( WM_CREATE ) : { RECT rect; HDC hdcScrn; POINT point1, point2; // // Setup global. // hwndCharGrid = hWnd; GetClientRect(hWnd, &rect); // // Calculate metrics for the character grid and the // magnify window. // sycm.dxpBox = (rect.right - 1) / (cchSymRow + 2); sycm.dypBox = (rect.bottom - 2) / (cchSymCol + 1); sycm.dxpCM = sycm.dxpBox * cchSymRow + 1; sycm.dypCM = sycm.dypBox * cchSymCol + 1; // space inside for border if ((PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) == LANG_CHINESE)) { sycm.dxpMag = sycm.dxpBox * 3 + 5; } else { sycm.dxpMag = sycm.dxpBox * 2 + 4; // twice the size + 2 bit border } sycm.dypMag = sycm.dypBox * 2 + 4; sycm.chCurr = chSymFirst; sycm.hFontMag = NULL; sycm.hFont = NULL; sycm.hdcMag = NULL; sycm.hbmMag = NULL; sycm.ypDest = 0; sycm.fFocusState = sycm.fMouseDn = sycm.fCursorOff = FALSE; // // Size the window precisely so the grid fits and is centered. // MoveWindow( hWnd, (rect.right - sycm.dxpCM + 1) / 2, (rect.bottom - sycm.dypCM + 1) / 2 + ((LPCREATESTRUCT)lParam)->y - 2, sycm.dxpCM + 2, sycm.dypCM + 2, FALSE ); // // Figure out what the offsets are between the dialog // and the character grid window. // point1.x = point1.y = point2.x = point2.y = 0; ClientToScreen(hWnd, &point1); ClientToScreen(((LPCREATESTRUCT)lParam)->hwndParent, &point2); #ifdef USE_MIRRORING sycm.xpCM = (abs(point1.x - point2.x)) - (sycm.dxpMag - sycm.dxpBox) / 2; #else sycm.xpCM = (point1.x - point2.x) - (sycm.dxpMag - sycm.dxpBox) / 2; #endif sycm.ypCM = (point1.y - point2.y) - (sycm.dypMag - sycm.dypBox) / 2; // // Create dc and bitmap for the magnify window. // if ((hdcScrn = GetWindowDC(hWnd)) != NULL) { if ((sycm.hdcMag = CreateCompatibleDC(hdcScrn)) != NULL) { SetTextColor( sycm.hdcMag, GetSysColor(COLOR_WINDOWTEXT) ); SetBkColor( sycm.hdcMag, GetSysColor(COLOR_WINDOW) ); SetBkMode(sycm.hdcMag, OPAQUE); if ((sycm.hbmMag = CreateCompatibleBitmap( hdcScrn, sycm.dxpMag, sycm.dypMag * 2 )) == NULL) { DeleteObject(sycm.hdcMag); } else { SelectObject(sycm.hdcMag, sycm.hbmMag); } } ReleaseDC(hWnd, hdcScrn); } break; } case ( WM_DESTROY ) : { if (sycm.fMouseDn) { ExitMagnify(hWnd, &sycm); } if (fDelClipboardFont) { DeleteObject(hFontClipboard); } if (sycm.hFont != NULL) { DeleteObject(sycm.hFont); } if (sycm.hFontMag != NULL) { DeleteObject(sycm.hFontMag); } if (sycm.hdcMag != NULL) { DeleteDC(sycm.hdcMag); } if (sycm.hbmMag != NULL) { DeleteObject(sycm.hbmMag); } break; } case ( WM_SETFOCUS ) : case ( WM_KILLFOCUS ) : { RestoreSymMag(&sycm); DrawSymChOutlineHwnd( &sycm, hWnd, sycm.chCurr, TRUE, message == WM_SETFOCUS ); break; } case ( WM_LBUTTONDOWN ) : { RECT rect; DOUTL("WM_LBUTTONDOWN: In\n"); // // Don't draw anything if there's an update region pending. // if (GetUpdateRect(hWnd, (LPRECT)&rect, FALSE) != 0) { DOUTL("WM_LBUTTONDOWN: No upd rect\n"); break; } SetFocus(hWnd); SetCapture(hWnd); sycm.fMouseDn = TRUE; if (!FMagData(&sycm)) { DOUTL("WM_LBUTTONDOWN: Drawing sym outline\n"); DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE); } // // Fall through to WM_MOUSEMOVE... // } case ( WM_MOUSEMOVE ) : { DOUTL("WM_MOUSEMOVE: In\n"); if (sycm.fMouseDn) { POINT pt; UINT chMouseSymbol; DOUTL("WM_MOUSEMOVE: mouse is down\n"); pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); ClientToScreen(hWnd, (LPPOINT)&pt); if (WindowFromPoint(pt) == hWnd) { ScreenToClient(hWnd, (LPPOINT)&pt); // // Convert back to a 'points'-like thing. // lParam = MAKELONG((WORD)pt.x, (WORD)pt.y); chMouseSymbol = (UINT)ChFromSymLParam(&sycm, lParam); if (chMouseSymbol > (UINT)chSymLast) { // // We're outside of current character range (but // still within the grid). Restore cursor and // leave magnified character. // if (sycm.fCursorOff) { sycm.fCursorOff = FALSE; ShowCursor(TRUE); } } else { // // We're in the grid and within the range of currently // displayed characters, display magnified character. // DOUTL("WM_MOUSEMOVE: in grid and subrange\n"); if (!sycm.fCursorOff) { sycm.fCursorOff = TRUE; ShowCursor(FALSE); } DOUTL("WM_MOUSEMOVE: movsymsel "); DOUTCHN( (UTCHAR)chMouseSymbol ); MoveSymbolSel(&sycm, (UTCHAR)chMouseSymbol); } } else { // // Left grid, leave magnified character and restore // cursor. // if (sycm.fCursorOff) { sycm.fCursorOff = FALSE; ShowCursor(TRUE); } } } DOUTL("WM_MOUSEMOVE: Leaving\n"); break; } case ( WM_CANCELMODE ) : case ( WM_LBUTTONUP ) : { if (sycm.fMouseDn) { ExitMagnify(hWnd, &sycm); } break; } case ( WM_LBUTTONDBLCLK ) : { WCHAR wch = sycm.chCurr; // // Send this character to the entry field. // if (sycm.fAnsiFont) { wch = ConvertANSIFontToUnicode(hWnd, sycm.hFont, (char)wch); } SendDlgItemMessage(hwndDialog, ID_STRING, WM_CHAR, (WPARAM)wch, 0L); break; } case ( WM_GETDLGCODE ) : { // // Necessary to obtain arrow and tab messages. // return (DLGC_WANTARROWS | DLGC_WANTCHARS); break; } case ( WM_KEYDOWN ) : { UTCHAR chNew = sycm.chCurr; INT cchMoved; if (sycm.fMouseDn) { break; } switch (wParam) { case ( VK_LEFT ) : { if (--chNew < chSymFirst) { return (0L); } break; } case ( VK_UP ) : { if ((chNew -= cchSymRow) < chSymFirst) { if (!ScrollMap(GetParent(hWnd), -cchSymRow, TRUE)) { return (0L); } RestoreSymMag(&sycm); } break; } case ( VK_RIGHT ) : { if (++chNew > chSymLast) { return (0L); } break; } case ( VK_DOWN ) : { if ((chNew += cchSymRow) > chSymLast) { if (!ScrollMap(GetParent(hWnd), cchSymRow, TRUE)) { return (0L); } RestoreSymMag(&sycm); } break; } case ( VK_NEXT ) : { if ((cchMoved = ScrollMapPage(GetParent(hWnd), FALSE, TRUE)) == 0) { return (0L); } // // We scrolled the map! Bump the char so it is // still in the window. // RestoreSymMag(&sycm); chNew += cchMoved; break; } case ( VK_PRIOR ) : { if ((cchMoved = ScrollMapPage( GetParent(hWnd), TRUE, TRUE )) == 0) { return (0L); } // // We scrolled the map! Bump the char so it is // still in the window. // RestoreSymMag(&sycm); chNew += cchMoved; break; } default : { return (0L); } } if (!FMagData(&sycm)) { DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE); } MoveSymbolSel(&sycm, (UTCHAR)chNew); break; } case ( WM_CHAR ) : { WCHAR wch = (WCHAR)wParam; char ch; if (sycm.fMouseDn) { break; } if (sycm.fAnsiFont) { if (WideCharToMultiByte( CP_ACP, 0, &wch, 1, &ch, 1, NULL, NULL ) != 1) { break; } wch = (WCHAR)(BYTE)ch; } if ((wch >= chSymFirst) && (wch <= chSymLast)) { if (!FMagData(&sycm)) { DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE); } MoveSymbolSel(&sycm, (UTCHAR)wch); SendDlgItemMessage(hwndDialog, ID_STRING, WM_CHAR, wParam, 0L); } break; } case ( WM_PAINT ) : { HDC hdc; PAINTSTRUCT ps; DOUTL("WM_PAINT: In\n"); hdc = BeginPaint(hWnd, &ps); DOUTL("WM_PAINT: drawing map\n"); DrawSymbolMap(&sycm, hdc); EndPaint(hWnd, &ps); DOUTL("WM_PAINT: Leaving\n"); return (TRUE); } default : { return (DefWindowProc(hWnd, message, wParam, lParam)); } } return (0L); } //////////////////////////////////////////////////////////////////////////// // // ProcessScrollMsg // //////////////////////////////////////////////////////////////////////////// VOID ProcessScrollMsg( HWND hwndDlg, int nCode, int nPos) { UTCHAR chNew = sycm.chCurr; HWND hwndGrid = GetDlgItem(hwndDlg, ID_CHARGRID); int cchScroll; switch( nCode ) { case ( SB_LINEUP ) : { cchScroll = -cchSymRow; break; } case ( SB_LINEDOWN ) : { cchScroll = cchSymRow; break; } case ( SB_PAGEUP ) : { cchScroll = (int)TRUE; break; } case ( SB_PAGEDOWN ) : { cchScroll = (int)FALSE; break; } case ( SB_THUMBTRACK ) : case ( SB_THUMBPOSITION ) : { cchScroll = (nPos * cchSymRow + chRangeFirst) - chSymFirst; break; } default : { return; } } if (nCode == SB_PAGEUP || nCode == SB_PAGEDOWN) { if (!ScrollMapPage(hwndDlg, (BOOL)cchScroll, FALSE)) { return; } // // ScrollMapPage will do the right thing to sycm.chCurr. // chNew = sycm.chCurr; } else { if (cchScroll == 0 || !ScrollMap(hwndDlg, cchScroll, FALSE)) { return; } // // Keep the current symbol inside the window. // while (chNew > chSymLast) { chNew -= cchSymRow; } while (chNew < chSymFirst) { chNew += cchSymRow; } } #if 0 if (!FMagData(&sycm)) { DrawSymChOutlineHwnd(&sycm, hwndGrid, sycm.chCurr, FALSE, FALSE); } MoveSymbolSel(&sycm, (UTCHAR)chNew); #else sycm.chCurr = chNew; InvalidateRect(hwndGrid, NULL, TRUE); #endif } //////////////////////////////////////////////////////////////////////////// // // ScrollMapPage // // Scrolls the map up or down by a page. See ScrollMap(). // //////////////////////////////////////////////////////////////////////////// INT ScrollMapPage( HWND hwndDlg, BOOL fUp, BOOL fRePaint) { INT cchScroll = cchFullMap; if (fUp) { cchScroll = -cchScroll; } if ((chSymFirst + cchScroll) < chRangeFirst) { cchScroll = (chRangeFirst - chSymFirst); } else if ((chSymLast + cchScroll) > chRangeLast) { cchScroll = (chRangeLast - chSymLast); } return (ScrollMap(hwndDlg, cchScroll, fRePaint) ? cchScroll : 0); } //////////////////////////////////////////////////////////////////////////// // // ScrollMap // // Scrolls the map up or down if there are too many chars to fit in the // chargrid. // //////////////////////////////////////////////////////////////////////////// BOOL ScrollMap( HWND hwndDlg, INT cchScroll, BOOL fRePaint) { HWND hwndSB, hwndCharGrid; INT chFirst = chSymFirst + cchScroll; INT chLast = chSymLast + cchScroll; HDC hdc; if ((chFirst < chRangeFirst) || (chLast > chRangeLast)) { return (FALSE); } hwndCharGrid = GetDlgItem(hwndDlg, ID_CHARGRID); hwndSB = GetDlgItem(hwndDlg, ID_MAPSCROLL); SetScrollPos(hwndSB, SB_CTL, (chFirst - chRangeFirst) / cchSymRow, TRUE); UpdateSymbolRange(hwndDlg, chFirst, chLast); if ((hwndDlg != NULL) && ((hdc = GetDC(hwndDlg)) != NULL)) { LPINT lpdxp; HFONT hFont; UINT ch; hFont = SelectObject(hdc, sycm.hFont); lpdxp = (LPINT)sycm.rgdxp; if (sycm.fAnsiFont) { GetCharWidth32A(hdc, chSymFirst, chSymLast, lpdxp); } else { GetCharWidth32(hdc, chSymFirst, chSymLast, lpdxp); } SelectObject(hdc, hFont); for (ch = (UINT) chSymFirst; ch <= (UINT) chSymLast; ch++, lpdxp++) { *lpdxp = (sycm.dxpBox - *lpdxp) / 2 - 1; } ReleaseDC(hwndDlg, hdc); } if (fRePaint) { InvalidateRect(hwndCharGrid, NULL, TRUE); } return (TRUE); } //////////////////////////////////////////////////////////////////////////// // // ChFromSymLParam // // Determines the character to select from the mouse position (lParam). // //////////////////////////////////////////////////////////////////////////// INT ChFromSymLParam( PSYCM psycm, LPARAM lParam) { return (min( cchSymRow - 1, max(0, ((INT)LOWORD(lParam) - 1) / psycm->dxpBox) ) + min( cchSymCol - 1, max(0, ((INT)HIWORD(lParam) - 1) / psycm->dypBox) ) * cchSymRow + chSymFirst); } //////////////////////////////////////////////////////////////////////////// // // DrawSymChOutlineHwnd // // Gets a DC for hwnd, calls DrawSymChOutline. // //////////////////////////////////////////////////////////////////////////// VOID DrawSymChOutlineHwnd( PSYCM psycm, HWND hwnd, UTCHAR ch, BOOL fVisible, BOOL fFocus) { HDC hdc = GetDC(hwnd); DrawSymChOutline(psycm, hdc, ch, fVisible, fFocus); ReleaseDC(hwnd, hdc); } //////////////////////////////////////////////////////////////////////////// // // RecalcCharMap // // Recalculates fixed character map data (font info, sizes, etc.). // //////////////////////////////////////////////////////////////////////////// VOID RecalcCharMap( HWND hwndDlg, PSYCM psycm, INT iCombo, BOOL fRedraw) { HDC hdc; TEXTMETRIC tm; UINT ch; LPINT lpdxp; HFONT hFont; LOGFONT LogFont; ITEMDATA ItemData; LONG iCurSel; // // Get rid of the old font handles. // if (hFontClipboard && (hFontClipboard == psycm->hFont)) { fDelClipboardFont = TRUE; } if (psycm->hFont && (hFontClipboard != psycm->hFont)) { DeleteObject(psycm->hFont); } if (psycm->hFontMag) { DeleteObject(psycm->hFontMag); } hdc = GetDC(hwndCharGrid); // // Set up the LogFont structure. // Make sure it fits in the grid. // if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) == LANG_CHINESE) { LogFont.lfHeight = 16; } else { LogFont.lfHeight = psycm->dypBox - 3; // Allow for whitespace. } // // Set these to zero. // LogFont.lfWidth = LogFont.lfEscapement = LogFont.lfOrientation = LogFont.lfWeight = 0; LogFont.lfItalic = LogFont.lfUnderline = LogFont.lfStrikeOut = LogFont.lfOutPrecision = LogFont.lfClipPrecision = LogFont.lfQuality = LogFont.lfPitchAndFamily = 0; // // Let the facename and size define the font. // // LogFont.lfCharSet = DEFAULT_CHARSET; // Work around the GDI bug that assumes the font's default charset // is always the system default locale. // *(DWORD *)&ItemData = SendDlgItemMessage( hwndDlg, ID_FONT, CB_GETITEMDATA, iCombo, 0L ); LogFont.lfCharSet = ItemData.CharSet; // // Get the facename from the combo box. // SendDlgItemMessage( hwndDlg, ID_FONT, CB_GETLBTEXT, iCombo, (LONG)(LPTSTR)LogFont.lfFaceName ); // // Enable Block listbox and set defaults appropriately. // EnableWindow(GetDlgItem(hwndDlg, ID_UNICODESUBSET), TRUE); iCurSel = SendDlgItemMessage( hwndDlg, ID_UNICODESUBSET, CB_GETCURSEL, 0, 0L ); UpdateSymbolSelection( hwndDlg, aSubsetData[iCurSel].BeginRange, aSubsetData[iCurSel].EndRange ); // // Enable Previous button if not on first subset. // if (iCurSel > 0) { EnableWindow(GetDlgItem(hwndDlg, ID_PREVSUBSET), TRUE); } else { EnableWindow(GetDlgItem(hwndDlg, ID_PREVSUBSET), FALSE); } // // Enable Next button if not on last subset. // if (iCurSel < (cSubsets - 1)) { EnableWindow(GetDlgItem(hwndDlg, ID_NEXTSUBSET), TRUE); } else { EnableWindow(GetDlgItem(hwndDlg, ID_NEXTSUBSET), FALSE); } // // The first sub sel is the ANSI code page. // psycm->fAnsiFont = (iCurSel == 0); // // Create the font. // psycm->hFont = CreateFontIndirect(&LogFont); hFont = SelectObject(hdc, psycm->hFont); // // Create the magnify font. // LogFont.lfHeight = psycm->dypMag - 5; // Allow for whitespace. psycm->hFontMag = CreateFontIndirect(&LogFont); // // Calculate new values and place in window data structure. // GetTextMetrics(hdc, &tm); psycm->xpCh = 2; psycm->ypCh = (4 + psycm->dypBox - tm.tmHeight) / 2; lpdxp = (LPINT)psycm->rgdxp; if (psycm->fAnsiFont) { GetCharWidth32A(hdc, chSymFirst, chSymLast, lpdxp); } else { GetCharWidth32(hdc, chSymFirst, chSymLast, lpdxp); } SelectObject(hdc, hFont); for (ch = (UINT) chSymFirst; ch <= (UINT) chSymLast; ch++, lpdxp++) { *lpdxp = (psycm->dxpBox - *lpdxp) / 2 - 1; } ReleaseDC(hwndCharGrid, hdc); psycm->xpMagCurr = 0; // No magnification data if (fRedraw) { InvalidateRect(hwndCharGrid, NULL, TRUE); } } //////////////////////////////////////////////////////////////////////////// // // DrawSymbolMap // // Draws all of the pieces of the symbol character map. // //////////////////////////////////////////////////////////////////////////// VOID DrawSymbolMap( PSYCM psycm, HDC hdc) { BOOL fFocus; DrawSymbolGrid(psycm, hdc); DrawSymbolChars(psycm, hdc); // // We need to force the focus rect to paint if we have the focus // since the old focus rect has been drawn over already. // if (fFocus = psycm->fFocusState) { psycm->fFocusState = FALSE; } DrawSymChOutline(psycm, hdc, psycm->chCurr, TRUE, fFocus); } //////////////////////////////////////////////////////////////////////////// // // DrawSymbolGrid // // Draws the symbol character map grid. // //////////////////////////////////////////////////////////////////////////// VOID DrawSymbolGrid( PSYCM psycm, HDC hdc) { INT cli; // count of lines INT xp, yp; INT dxpBox = psycm->dxpBox; INT dypBox = psycm->dypBox; HPEN hpenOld; hpenOld = SelectObject(hdc, CreatePen( PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME) )); // // Draw horizontal lines. // xp = psycm->dxpCM + 1; yp = 1; cli = cchSymCol+1; while (cli--) { MoveToEx(hdc, 1, yp, NULL); LineTo(hdc, xp, yp); yp += dypBox; } // // Draw vertical lines. // yp = psycm->dypCM; xp = 1; cli = cchSymRow+1; while (cli--) { MoveToEx(hdc, xp, 1, NULL); LineTo(hdc, xp, yp); xp += dxpBox; } DeleteObject(SelectObject(hdc, hpenOld)); } //////////////////////////////////////////////////////////////////////////// // // DrawSymbolChars // // Draws the symbol character map. // //////////////////////////////////////////////////////////////////////////// VOID DrawSymbolChars( PSYCM psycm, HDC hdc) { INT dxpBox = psycm->dxpBox; INT dypBox = psycm->dypBox; INT cch; INT x, y; INT yp; TCHAR ch; HFONT hFontOld; RECT rect; LPRECT lprect = (LPRECT)▭ LPINT lpdxp; // // Setup the font and colors. // hFontOld = (HFONT)SelectObject(hdc, psycm->hFont); SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); SetBkColor(hdc, GetSysColor(COLOR_WINDOW)); SetBkMode(hdc, OPAQUE); // // Draw characters. // cch = 1; ch = chSymFirst; lpdxp = (LPINT)psycm->rgdxp; rect.top = 2; yp = psycm->ypCh; rect.bottom = rect.top + dypBox - 1; for (y = 0; y++ < cchSymCol;) { rect.left = psycm->xpCh; rect.right = rect.left + dxpBox - 1; for (x = 0; (x++ < cchSymRow) && (ch <= chSymLast);) { if (psycm->fAnsiFont) { ExtTextOutA( hdc, rect.left + (*lpdxp++), yp, ETO_OPAQUE | ETO_CLIPPED, lprect, &(CHAR)ch, 1, NULL ); } else { ExtTextOutW( hdc, rect.left + (*lpdxp++), yp, ETO_OPAQUE | ETO_CLIPPED, lprect, &ch, 1, NULL ); } ch++; rect.left += dxpBox; rect.right += dxpBox; } yp += dypBox; rect.top += dypBox; rect.bottom += dypBox; } SelectObject(hdc, hFontOld); } //////////////////////////////////////////////////////////////////////////// // // DrawSymChOutline // // Draws an outline around the symbol in the character map. If fVisible, // then it draws the outline, otherwise it erases it. // //////////////////////////////////////////////////////////////////////////// VOID DrawSymChOutline( PSYCM psycm, HDC hdc, UTCHAR ch, BOOL fVisible, BOOL fFocus) { HBRUSH hbrOld; RECT rc; INT dxpBox = psycm->dxpBox; INT dypBox = psycm->dypBox; hbrOld = SelectObject( hdc, CreateSolidBrush(GetSysColor( fVisible ? COLOR_WINDOWFRAME : COLOR_WINDOW )) ); ch -= chSymFirst; rc.left = (ch % cchSymRow) * dxpBox + 2; rc.right = rc.left + dxpBox - 1; rc.top = (ch / cchSymRow) * dypBox + 2; rc.bottom = rc.top + dypBox - 1; // // Draw selection rectangle. // PatBlt(hdc, rc.left, rc.top - 2, dxpBox - 1, 1, PATCOPY); PatBlt(hdc, rc.left, rc.bottom + 1, dxpBox - 1, 1, PATCOPY); PatBlt(hdc, rc.left - 2, rc.top, 1, dypBox - 1, PATCOPY); PatBlt(hdc, rc.right + 1, rc.top, 1, dypBox - 1, PATCOPY); DeleteObject(SelectObject(hdc, GetStockObject(NULL_BRUSH))); // // Deal with the focus rectangle. // if (fFocus != psycm->fFocusState) { DrawFocusRect(hdc, &rc); psycm->fFocusState = fFocus; } SelectObject(hdc, hbrOld); } //////////////////////////////////////////////////////////////////////////// // // MoveSymbolSel // // Changes the current symbol selection. Handles drawing of magnified // characters. // //////////////////////////////////////////////////////////////////////////// VOID MoveSymbolSel( PSYCM psycm, UTCHAR chNew) { HDC hdc; HDC hdcMag = psycm->hdcMag; RECT rc; HFONT hFontOld; HFONT hFontMag; // old font in memory dc HPEN hpenOld; UTCHAR chNorm = chNew - chSymFirst + 32; INT dxpMag = psycm->dxpMag; // for quick reference INT dypMag = psycm->dypMag; INT ypMemSrc = psycm->ypDest; INT ypMemDest = ypMemSrc ^ dypMag; INT xpCurr = psycm->xpMagCurr; INT ypCurr = psycm->ypMagCurr; INT xpNew = psycm->xpCM + (psycm->dxpBox * (chNorm % cchSymRow)); INT ypNew = psycm->ypCM + (psycm->dypBox * ((chNorm / cchSymRow) - 1)); INT dxpCh; // width of extra character space (used to center char in box) INT dypCh; SIZE sz; DOUTL("MoveSymbolSel: In\n"); if (((chNew == (UTCHAR)psycm->chCurr) && FMagData(psycm))) { DOUTL("MoveSymbolSel: ch == cur && fMag... exiting\n"); return; } // // Don't draw a magnified character if the char grid has an update // region or is not visible. // if (!IsWindowVisible(hwndCharGrid) || GetUpdateRect(hwndCharGrid, &rc, FALSE)) { DOUTL("MoveSymbolSel: not vis or upd rect... exiting\n"); return; } hdc = GetDC(hwndDialog); // // Setup the magnified font character. // hFontMag = SelectObject(hdcMag, psycm->hFontMag); if (psycm->fAnsiFont) { char chANSINew = (char)chNew; GetTextExtentPointA(hdcMag, &chANSINew, 1, &sz); } else { GetTextExtentPointW(hdcMag, &chNew, 1, &sz); } if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) == LANG_CHINESE) { dxpCh = (dxpMag - (INT)sz.cx) / 2 - 2; dypCh = (dypMag - (INT)sz.cy) / 2 - 2; } else { dxpCh = (dxpMag - (INT)sz.cx) / 2 - 1; dypCh = (dypMag - (INT)sz.cy) / 2 - 1; } hpenOld = SelectObject(hdc, CreatePen( PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME) )); hFontOld = SelectObject(hdc, psycm->hFontMag); // // Copy screen data to offscreen bitmap. // BitBlt(hdcMag, 0, ypMemDest, dxpMag, dypMag, hdc, xpNew, ypNew, SRCCOPY); // // Setup DC. // SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); SetBkColor(hdc, GetSysColor(COLOR_WINDOW)); SetBkMode(hdc, OPAQUE); if (FMagData(psycm)) { INT xpT = xpNew - xpCurr; // point of overlap in offscreen data INT ypT = ypNew - ypCurr; INT dxpT = dxpMag - abs(xpT); // size of overlap INT dypT = dypMag - abs(ypT); DOUTL("MoveSymbolSel: FMagData\n"); if ((dxpT > 0) && (dypT > 0)) { INT xpTmax, ypTmax; // max(0, xpT); INT xpTmin, ypTmin; // min(0, xpT); INT xpTnmin, ypTnmin; // min(0, -xpT); DOUTL("MoveSymbolSel: dxpT > 0 && dypT > 0\n"); if (xpT < 0) { xpTnmin = - (xpTmin = xpT); xpTmax = 0; } else { xpTmax = xpT; xpTnmin = xpTmin = 0; } if (ypT < 0) { ypTnmin = - (ypTmin = ypT); ypTmax = 0; } else { ypTmax = ypT; ypTnmin = ypTmin = 0; } rc.left = xpTmax; rc.right = xpTmin + dxpMag; rc.top = ypTmax + ypMemSrc; rc.bottom= ypTmin + dypMag + ypMemSrc; // // Copy overlapping offscreen data. // BitBlt( hdcMag, xpTnmin, ypTnmin + ypMemDest, dxpT, dypT, hdcMag, xpTmax, ypTmax + ypMemSrc, SRCCOPY ); // // Print part of char over old screen data. // if (psycm->fAnsiFont) { ExtTextOutA( hdcMag, xpT + dxpCh, ypT + dypCh + ypMemSrc, ETO_OPAQUE | ETO_CLIPPED, (LPRECT)&rc, &(CHAR)chNew, 1, NULL ); } else { ExtTextOutW( hdcMag, xpT + dxpCh, ypT + dypCh + ypMemSrc, ETO_OPAQUE | ETO_CLIPPED, (LPRECT)&rc, &chNew, 1, NULL ); } } // // Restore old screen data. // BitBlt(hdc, xpCurr, ypCurr, dxpMag, dypMag, hdcMag, 0, ypMemSrc, SRCCOPY); } rc.right = (psycm->xpMagCurr = rc.left = xpNew) + dxpMag - 2; rc.bottom = (psycm->ypMagCurr = rc.top = ypNew) + dypMag - 2; // // The rectangle. // MoveToEx(hdc, rc.left, rc.top, NULL); LineTo(hdc, rc.left, rc.bottom - 1); LineTo(hdc, rc.right - 1, rc.bottom - 1); LineTo(hdc, rc.right - 1, rc.top); LineTo(hdc, rc.left, rc.top); // // The shadow. // MoveToEx(hdc, rc.right, rc.top + 1, NULL); LineTo(hdc, rc.right, rc.bottom); LineTo(hdc, rc.left, rc.bottom); MoveToEx(hdc, rc.right + 1, rc.top + 2, NULL); LineTo(hdc, rc.right + 1, rc.bottom + 1); LineTo(hdc, rc.left + 1, rc.bottom + 1); rc.left++; rc.top++; rc.right--; rc.bottom--; // // Draw magnified character on screen. // if (psycm->fAnsiFont) { ExtTextOutA( hdc, xpNew + dxpCh, ypNew + dypCh, ETO_OPAQUE | ETO_CLIPPED, (LPRECT)&rc, &(CHAR)chNew, 1, NULL ); } else { ExtTextOutW( hdc, xpNew + dxpCh, ypNew + dypCh, ETO_OPAQUE | ETO_CLIPPED, (LPRECT)&rc, &chNew, 1, NULL ); } psycm->ypDest = ypMemDest; DeleteObject(SelectObject(hdc, hpenOld)); SelectObject(hdc, hFontOld); SelectObject(hdcMag, hFontMag); UpdateKeystrokeText(hdc, psycm->fAnsiFont, chNew, TRUE); ReleaseDC(hwndDialog, hdc); psycm->chCurr = chNew; DOUTL("MoveSymbolSel: Leaving\n"); } //////////////////////////////////////////////////////////////////////////// // // RestoreSymMag // // Restores the screen data under the magnifier. // //////////////////////////////////////////////////////////////////////////// VOID RestoreSymMag( PSYCM psycm) { if (FMagData(psycm)) { HDC hdc = GetDC(hwndDialog); BitBlt( hdc, psycm->xpMagCurr, psycm->ypMagCurr, psycm->dxpMag, psycm->dypMag, psycm->hdcMag, 0, psycm->ypDest, SRCCOPY ); ReleaseDC(hwndDialog, hdc); psycm->xpMagCurr = 0; // flag - no data offscreen (see FMagData) } } //////////////////////////////////////////////////////////////////////////// // // FontLoadProc // // Used by EnumFonts to load our combo box with all the fonts installed // in the system. // //////////////////////////////////////////////////////////////////////////// INT APIENTRY FontLoadProc( LPLOGFONT lpLogFont, NEWTEXTMETRICEX* lpTextMetric, DWORD nFontType, LPARAM lpData) { INT iPos; TCHAR szFace[LF_FACESIZE]; // // Check for duplicates. // iPos = (INT)SendDlgItemMessage( (HWND)lpData, ID_FONT, CB_FINDSTRING, (WPARAM)-1, (DWORD)&lpLogFont->lfFaceName ); if (iPos == CB_ERR) { NotInListYet: // // Doesn't exist, insert the facename into the combo box. // iPos = (INT)SendDlgItemMessage( (HWND)lpData, ID_FONT, CB_ADDSTRING, 0, (DWORD)&lpLogFont->lfFaceName ); } else { // // Make sure it is not just a substring (want a full match). // SendDlgItemMessage( (HWND)lpData, ID_FONT, CB_GETLBTEXT, iPos, (LONG)(LPTSTR)szFace ); if (lstrcmpi(szFace, lpLogFont->lfFaceName)) { goto NotInListYet; } // // Already exists, blow out now if this is not a true type font. // if (!(nFontType & TRUETYPE_FONTTYPE)) { return (1); } } // // Store the pertinant font information in the combo item data. // if ((iPos != CB_ERR) && (iPos != CB_ERRSPACE)) { ITEMDATA ItemData; DWORD ntmFlags = lpTextMetric->ntmTm.ntmFlags; SHORT sFontType = 0; if (ntmFlags & NTM_PS_OPENTYPE) { sFontType = PS_OPENTYPE_FONT; } else if (ntmFlags & NTM_TYPE1) { sFontType = TYPE1_FONT; } else if (nFontType & TRUETYPE_FONTTYPE) { if (ntmFlags & NTM_TT_OPENTYPE) sFontType = TT_OPENTYPE_FONT; else sFontType = TRUETYPE_FONT; } ItemData.FontType = sFontType; ItemData.CharSet = lpLogFont->lfCharSet; ItemData.PitchAndFamily = lpLogFont->lfPitchAndFamily; SendDlgItemMessage( (HWND)lpData, ID_FONT, CB_SETITEMDATA, iPos, *(DWORD *)&ItemData ); } // // Continue enumeration. // return (1); } //////////////////////////////////////////////////////////////////////////// // // GetEditText // // Returns HANDLE containing the text in the edit control. // // NOTE: Caller is responsible for freeing this handle! // //////////////////////////////////////////////////////////////////////////// HANDLE GetEditText( HWND hwndDlg) { INT cchText; HWND hwndEditCtl; HANDLE hmem; LPTSTR lpstrText; DWORD dwSel; hwndEditCtl = GetDlgItem(hwndDlg, ID_STRING); cchText = GetWindowTextLength(hwndEditCtl); hmem = GlobalAlloc(0, CTOB((cchText + 1))); lpstrText = (LPTSTR)GlobalLock(hmem); cchText = GetWindowText(hwndEditCtl, lpstrText, cchText+1); dwSel = SendMessage(hwndEditCtl, EM_GETSEL, 0, 0L); if (LOWORD(dwSel) != HIWORD(dwSel)) { // // If there is a selection, then only get the selected text. // *(lpstrText + HIWORD(dwSel)) = TEXT('\0'); lstrcpy(lpstrText, lpstrText + LOWORD(dwSel)); } GlobalUnlock(hmem); if (cchText == 0) { hmem = GlobalFree(hmem); } return (hmem); } //////////////////////////////////////////////////////////////////////////// // // CopyString // // Implements the copy function. // //////////////////////////////////////////////////////////////////////////// VOID CopyString( HWND hwndDlg) { HANDLE hmem; LPTSTR lpstrText; if (hmem = GetEditText(hwndDlg)) { lpstrText = (LPTSTR)GlobalLock(hmem); // // Copying string to clipboard. // if (OpenClipboard(hwndDlg)) { EmptyClipboard(); SendRTFToClip(hwndDlg, lpstrText); #ifdef UNICODE SetClipboardData(CF_UNICODETEXT, hmem); #else SetClipboardData(CF_TEXT, hmem); #endif CloseClipboard(); } else { // // If we couldn't open the clipboard, then we need to free memory. // GlobalUnlock(hmem); GlobalFree(hmem); } } } //////////////////////////////////////////////////////////////////////////// // // SendRTFToClip // // Puts the string in the clipboard using Rich Text Format. This assumes // that the clipboard has already been opened. // //////////////////////////////////////////////////////////////////////////// VOID SendRTFToClip( HWND hwndDlg, LPTSTR lpstrText) { INT iCurrFont; ITEMDATA ItemData; TCHAR szFaceName[LF_FACESIZE]; HANDLE hmemRTF, hmemClip; LPTSTR lpstrClipString; TCHAR achHeaderTmpl[] = TEXT("{\\rtf1\\ansi\\ansicpg%d {\\fonttbl{\\f0\\"); TCHAR achHeader[sizeof(achHeaderTmpl) / sizeof(TCHAR) + 20]; TCHAR achMiddle[] = TEXT(";}}\\sectd\\pard\\plain\\f0 "); INT cchUC; #ifndef UNICODE_RTF LPWSTR pszRTFW; #endif #define MAXLENGTHFONTFAMILY 8 #define ALITTLEEXTRA 10 // covers extra characters + length of font size iCurrFont = (INT)SendDlgItemMessage(hwndDlg, ID_FONT, CB_GETCURSEL, 0, 0L); // // Get the item data - contains fonttype, charset, and pitchandfamily. // *(DWORD *)&ItemData = SendDlgItemMessage( hwndDlg, ID_FONT, CB_GETITEMDATA, iCurrFont, 0L ); // // Get the facename from the combo box. // SendDlgItemMessage( hwndDlg, ID_FONT, CB_GETLBTEXT, iCurrFont, (LPARAM)(LPTSTR)szFaceName ); wsprintf(achHeader, achHeaderTmpl, (INT)(SHORT)GetACP()); // // 16 times in case they're all > 7 bits (each chr -> \uc1\uddddddd\'xx) // and room for the second byte of DBCS. // hmemRTF = GlobalAlloc( 0, CTOB(lstrlen((LPTSTR)achHeader) + MAXLENGTHFONTFAMILY + lstrlen(szFaceName) + lstrlen((LPTSTR)achMiddle) + 2 * 16 * lstrlen(lpstrText) + ALITTLEEXTRA) ); if (hmemRTF == NULL) { return; } // // Allocate memory for local storage of clipboard string for owner draw. // if (hmemClip = GlobalAlloc(0, CTOB(lstrlen(lpstrText) + 1))) { // // Get rid of old ones. // if (hstrClipboard) { GlobalFree(hstrClipboard); } if (fDelClipboardFont) { fDelClipboardFont = FALSE; DeleteObject(hFontClipboard); } // // Save this stuff away for owner drawing in a clipboard viewer. // hFontClipboard = sycm.hFont; hstrClipboard = hmemClip; lstrcpy(GlobalLock(hstrClipboard), lpstrText); GlobalUnlock(hstrClipboard); } else { GlobalFree(hmemRTF); return; } lpstrClipString = GlobalLock(hmemRTF); #ifndef UNICODE_RTF pszRTFW = lpstrClipString; #endif lstrcpy(lpstrClipString, achHeader); if (ItemData.CharSet == SYMBOL_CHARSET) { lstrcat(lpstrClipString, (LPTSTR)TEXT("ftech ")); } else { // // Top four bits specify family. // switch (ItemData.PitchAndFamily & 0xf0) { case ( FF_DECORATIVE ) : { lstrcat(lpstrClipString, (LPTSTR)TEXT("fdecor ")); break; } case ( FF_MODERN ) : { lstrcat(lpstrClipString, (LPTSTR)TEXT("fmodern ")); break; } case ( FF_ROMAN ) : { lstrcat(lpstrClipString, (LPTSTR)TEXT("froman ")); break; } case ( FF_SCRIPT ) : { lstrcat(lpstrClipString, (LPTSTR)TEXT("fscript ")); break; } case ( FF_SWISS ) : { lstrcat(lpstrClipString, (LPTSTR)TEXT("fswiss ")); break; } default : { break; } } } lstrcat(lpstrClipString, szFaceName); lstrcat(lpstrClipString, (LPTSTR)achMiddle); // // We need to do the text character by character, making sure // that we output a special sequence \'hh for characters bigger // than 7 bits long! // lpstrClipString = (LPTSTR)(lpstrClipString + lstrlen(lpstrClipString)); cchUC = 0; while (*lpstrText) { if ((UTCHAR)*lpstrText < 128) { if (*lpstrText == TEXT('\\') || *lpstrText == TEXT('{') || *lpstrText == TEXT('}')) { // // Need to preface these symbols with a '\' since they are // special control characters for RTF. // *lpstrClipString++ = TEXT('\\'); } *lpstrClipString++ = *lpstrText++; } else { unsigned char achTmp[2]; unsigned char *pTmp = achTmp; int cch; cch = WideCharToMultiByte( CP_ACP, 0, lpstrText, 1, pTmp, 2, NULL, NULL ); // // Put in a \uc# to tell Unicode reader how many bytes to skip // and the \uN code to indicate the real unicode value. // if (cch != cchUC ) { cchUC = cch; lpstrClipString += wsprintf( lpstrClipString, TEXT("\\uc%d"), (INT)(SHORT)cchUC ); } lpstrClipString += wsprintf( lpstrClipString, TEXT("\\u%d"), (INT)(SHORT)*lpstrText ); // // Now put the \'xx string in to indicate the actual character. // lpstrText++; while (cch--) { *lpstrClipString++ = TEXT('\\'); *lpstrClipString++ = TEXT('\''); wsprintf(achMiddle, TEXT("%x"), (INT)*pTmp++); *lpstrClipString++ = achMiddle[0]; *lpstrClipString++ = achMiddle[1]; } } } *lpstrClipString++ = TEXT('}'); *lpstrClipString++ = TEXT('\0'); if (!wCFRichText) { TCHAR szRTF[80]; LoadString(hInst, IDS_RTF, szRTF, BTOC(sizeof(szRTF)) - 1); wCFRichText = RegisterClipboardFormat(szRTF); } #ifndef UNICODE_RTF { // // RTF is only defined for ANSI, not for Unicode, therefore // we need to convert the buffer before we put it on the // clipboard. Eventually, we should add autoconversion code // to USER to handle this for us. // int cch; HANDLE hmemRTFA; LPSTR pszRTFA; cch = WideCharToMultiByte( CP_ACP, 0, pszRTFW, lpstrClipString - pszRTFW, NULL, 0, NULL, NULL ); if (cch != 0 && (hmemRTFA = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,cch)) != NULL) { pszRTFA = GlobalLock(hmemRTFA); WideCharToMultiByte( CP_ACP, 0, pszRTFW, lpstrClipString - pszRTFW, pszRTFA, cch, NULL, NULL ); GlobalUnlock(hmemRTFA); GlobalUnlock(hmemRTF); GlobalFree(hmemRTF); hmemRTF = hmemRTFA; } } #endif // // Put RTF and OwnerDisplay formats in the clipboard. // SetClipboardData(wCFRichText, hmemRTF); SetClipboardData(CF_OWNERDISPLAY, NULL); } //////////////////////////////////////////////////////////////////////////// // // PointsToHeight // // Calculates the height in pixels of the specified point size for the // current display. // //////////////////////////////////////////////////////////////////////////// INT PointsToHeight( INT iPoints) { HDC hdc; INT iHeight; hdc = GetDC(HWND_DESKTOP); iHeight = MulDiv(iPoints, GetDeviceCaps(hdc, LOGPIXELSY), 72); ReleaseDC(HWND_DESKTOP, hdc); return (iHeight); } //////////////////////////////////////////////////////////////////////////// // // UpdateKeystrokeText // // Calculates and updates the text string displayed in the Keystroke // field of the status bar. It repaints the status field if fRedraw is // TRUE. // //////////////////////////////////////////////////////////////////////////// VOID UpdateKeystrokeText( HDC hdc, BOOL fANSI, UTCHAR chNew, BOOL fRedraw) { TCHAR szUnshifted[CCH_KEYNAME]; INT vkRes; LONG lParam; if (!fANSI) { lstrcpy(szKeystrokeText, szUnicodeLabel); wsprintf( (LPTSTR)(szKeystrokeText + iUnicodeLabelStart), TEXT("%04x"), chNew ); } else { lstrcpy(szKeystrokeText, szKeystrokeLabel); vkRes = VkKeyScan(chNew); // // Map the virtual key code into an unshifted character value. // lParam = MapVirtualKey(LOBYTE(vkRes), 0) << 16; GetKeyNameText(lParam, szUnshifted, CCH_KEYNAME - 1); switch (HIBYTE(vkRes)) { case ( 0 ) : // unshifted char case ( 1 ) : // character is shifted, just display the shifted char { if (chNew != TEXT(' ')) { szKeystrokeText[iKeystrokeTextStart] = chNew; szKeystrokeText[iKeystrokeTextStart + 1] = TEXT('\0'); } else { lstrcat(szKeystrokeText, szUnshifted); } break; } case ( 2 ) : // character is control character { lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szCtrl); lstrcat(szKeystrokeText, (LPTSTR)szUnshifted); break; } case ( 6 ) : // character is CONTROL+ALT { lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szCtrlAlt); lstrcat(szKeystrokeText, (LPTSTR)szUnshifted); break; } case ( 7 ) : // character is SHIFT+CONTROL+ALT { lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szShiftCtrlAlt); lstrcat(szKeystrokeText, (LPTSTR)szUnshifted); break; } default : // Character created via Alt + Numpad { lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szAlt); wsprintf( (LPTSTR)(szKeystrokeText + lstrlen(szKeystrokeText)), TEXT("%d"), chNew ); break; } } } if (fRedraw) { PaintStatusLine(hdc, FALSE, TRUE); } } //////////////////////////////////////////////////////////////////////////// // // UpdateHelpText // // Calculates if the Help string needs to be updated, and does so if // necessary. // // If hwndCtrl is not NULL, then it specifies the window handle of the // control gaining focus, and lpmsg is ignored. // // If hwndCtrl is NULL, then lpmsg must point to a valid message structure. // If it is a tab character, then we calculate what the next control is // that will receive the focus. // //////////////////////////////////////////////////////////////////////////// BOOL UpdateHelpText( LPMSG lpmsg, HWND hwndCtrl) { HDC hdc; BOOL fPaintStatus = FALSE; BOOL fRet = TRUE; DPRINT((szDbgBuf, TEXT("UpdHlpTxt: lpmsg:0x%08lX, hwnd:0x%08lX\n"), (DWORD)lpmsg, (DWORD)hwndCtrl)); if (hwndCtrl != NULL) { fPaintStatus = TRUE; iControl = GetDlgCtrlID(hwndCtrl); } else if (lpmsg->message == WM_KEYDOWN) { if (lpmsg->wParam == VK_TAB) { fPaintStatus = TRUE; hwndCtrl = GetNextDlgTabItem( hwndDialog, GetDlgItem(hwndDialog, iControl), (BOOL)(GetKeyState(VK_SHIFT) & 0x8000) ); iControl = GetDlgCtrlID(hwndCtrl); if (iControl == ID_STRING) { // // Do this ourselves, otherwise default action will select // the whole edit control. // SetFocus(hwndCtrl); fRet = FALSE; } if (iControl == ID_CHARGRID) { // // Set the default button back to "Select". The default // might have changed to the "Next" or "Previous" button. // SendMessage(hwndDialog, DM_SETDEFID, ID_SELECT, 0); } } else if (lpmsg->wParam == VK_F1) { PostMessage(hwndDialog, WM_COMMAND, ID_HELP, 0L); } } if (fPaintStatus) { hdc = GetDC(hwndDialog); PaintStatusLine(hdc, TRUE, FALSE); ReleaseDC(hwndDialog, hdc); } return (fRet); } //////////////////////////////////////////////////////////////////////////// // // SubSetChanged // // Sets the ANSI bit if appropriate and then calls UpdateSymbolSelection // and then repaints the window. // // Repaints Keystroke field if HWND != NULL. // Sets sycm->fAnsiFont if 'Windows Chars' is the subset. // Redraws the char grid. // //////////////////////////////////////////////////////////////////////////// VOID SubSetChanged( HWND hwnd, INT iSubSet, INT ichFirst, INT ichLast) { HDC hdc; BOOL fANSI = (iSubSet == 0); if (fANSI != sycm.fAnsiFont) { sycm.fAnsiFont = fANSI; } UpdateSymbolSelection(hwnd, ichFirst, ichLast); if ((hwnd != NULL) && ((hdc = GetDC(hwnd)) != NULL)) { LPINT lpdxp; HFONT hFont; UINT ch; hFont = SelectObject(hdc, sycm.hFont); lpdxp = (LPINT)sycm.rgdxp; if (iSubSet == 0) { GetCharWidth32A(hdc, chSymFirst, chSymLast, lpdxp); } else { GetCharWidth32(hdc, chSymFirst, chSymLast, lpdxp); } SelectObject(hdc, hFont); for (ch = (UINT) chSymFirst; ch <= (UINT) chSymLast; ch++, lpdxp++) { *lpdxp = (sycm.dxpBox - *lpdxp) / 2 - 1; } ReleaseDC(hwnd, hdc); } InvalidateRect(hwndCharGrid, NULL, TRUE); } //////////////////////////////////////////////////////////////////////////// // // UpdateSymbolSelection // // Updates the values of the following global values: // chRangeFirst // chRangeLast // Subsets in the Unicode character set have different numbers of // characters. We have to do some bounds checking in order to set an // appropriate sycm.chCurr value. The "Keystroke" status field is // updated. // // Repaints Keystroke field if HWND != NULL. // //////////////////////////////////////////////////////////////////////////// VOID UpdateSymbolSelection( HWND hwnd, INT FirstChar, INT LastChar) { int iCmd = SW_HIDE; HWND hwndSB; UINT chFirst, chLast; chRangeFirst = FirstChar; chRangeLast = LastChar; chFirst = chRangeFirst; chLast = chFirst + cchFullMap - 1; chLast = min(chLast, chRangeLast); hwndSB = GetDlgItem(hwnd, ID_MAPSCROLL); if (chLast != chRangeLast) { int i; iCmd = SW_SHOW; SetScrollPos(hwndSB, SB_CTL, 0, FALSE); i = (chRangeLast - chRangeFirst + 1) - cchFullMap; if (i < 0) { i = 1; } else { i = i / cchSymRow; } SetScrollRange(hwndSB, SB_CTL, 0, i, FALSE); InvalidateRect(hwndSB, NULL, FALSE); } ShowWindow(hwndSB, iCmd); UpdateSymbolRange(hwnd, chFirst, chLast); } //////////////////////////////////////////////////////////////////////////// // // UpdateSymbolRange // // Updates the values of the following global values: // chSymFirst // chSymLast // sycm.chCurr // Subsets in the Unicode character set have different numbers of // characters. We have to do some bounds checking in order to set an // appropriate sycm.chCurr value. The "Keystroke" status field is // updated. // // Repaints Keystroke field if HWND != NULL. // //////////////////////////////////////////////////////////////////////////// VOID UpdateSymbolRange( HWND hwnd, INT FirstChar, INT LastChar) { UTCHAR chSymOffset; chSymOffset = sycm.chCurr - chSymFirst; chSymFirst = FirstChar; chSymLast = LastChar; sycm.chCurr = chSymOffset + chSymFirst; if (sycm.chCurr > chSymLast) { sycm.chCurr = chSymFirst; } if (hwnd != NULL) { HDC hdc; hdc = GetDC(hwnd); UpdateKeystrokeText(hdc, sycm.fAnsiFont, sycm.chCurr, TRUE); ReleaseDC(hwnd, hdc); } else { UpdateKeystrokeText(NULL, sycm.fAnsiFont, sycm.chCurr, FALSE); } } //////////////////////////////////////////////////////////////////////////// // // PaintStatusLine // // Paints the Help and Keystroke fields in the status bar. // // Repaints Help field if fHelp == TRUE. // Repaints Keystroke field if fKeystroke == TRUE. // //////////////////////////////////////////////////////////////////////////// VOID PaintStatusLine( HDC hdc, BOOL fHelp, BOOL fKeystroke) { HFONT hfontOld = NULL; RECT rect; INT dyBorder; TCHAR szHelpText[100]; dyBorder = GetSystemMetrics(SM_CYBORDER); if (hfontStatus) { hfontOld = SelectObject(hdc, hfontStatus); } // // Set the text and background colors. // SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT)); SetBkColor(hdc, GetSysColor(COLOR_BTNFACE)); if (fHelp) { // // Now the help text, with a gray background. // rect.top = rcStatusLine.top + 3 * dyBorder; rect.bottom = rcStatusLine.bottom - 3 * dyBorder; rect.left = 9 * dyBorder; rect.right = rect.left + dxHelpField - 2 * dyBorder; LoadString(hInst, iControl, szHelpText, BTOC(sizeof(szHelpText)) - 1); ExtTextOut( hdc, rect.left + dyBorder * 2, rect.top, ETO_OPAQUE | ETO_CLIPPED, &rect, szHelpText, lstrlen(szHelpText), NULL ); } if (fKeystroke) { // // Now the keystroke text, with a gray background. // rect.top = rcStatusLine.top + 3 * dyBorder; rect.bottom = rcStatusLine.bottom - 3 * dyBorder; rect.right = rcStatusLine.right - 9 * dyBorder; rect.left = rect.right - dxKeystrokeField + 2 * dyBorder; ExtTextOut( hdc, rect.left + dyBorder * 2, rect.top, ETO_OPAQUE | ETO_CLIPPED, &rect, szKeystrokeText, lstrlen(szKeystrokeText), NULL ); } if (hfontOld) { SelectObject(hdc, hfontOld); } } //////////////////////////////////////////////////////////////////////////// // // DrawFamilyComboItem // // Paints the font facenames and TT bitmap in the font combo box. // //////////////////////////////////////////////////////////////////////////// BOOL DrawFamilyComboItem( LPDRAWITEMSTRUCT lpdis) { HDC hDC, hdcMem; DWORD rgbBack, rgbText; TCHAR szFace[LF_FACESIZE]; HBITMAP hOld; INT dy; SHORT sFontType; hDC = lpdis->hDC; if (lpdis->itemState & ODS_SELECTED) { rgbBack = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT)); rgbText = SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); } else { rgbBack = SetBkColor(hDC, GetSysColor(COLOR_WINDOW)); rgbText = SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); } SendMessage( lpdis->hwndItem, CB_GETLBTEXT, lpdis->itemID, (LONG)(LPTSTR)szFace ); ExtTextOut( hDC, lpdis->rcItem.left + DX_BITMAP, lpdis->rcItem.top, ETO_OPAQUE | ETO_CLIPPED, &lpdis->rcItem, szFace, lstrlen(szFace), NULL ); hdcMem = CreateCompatibleDC(hDC); if (hdcMem) { if (hbmFont) { hOld = SelectObject(hdcMem, hbmFont); sFontType = ((ITEMDATA FAR *)&(lpdis->itemData))->FontType; if (sFontType) { int xSrc; dy = ((lpdis->rcItem.bottom - lpdis->rcItem.top) - DY_BITMAP) / 2; if (sFontType & TRUETYPE_FONT) xSrc = 0; else if (sFontType & TT_OPENTYPE_FONT) xSrc = 2; else if(sFontType & PS_OPENTYPE_FONT) xSrc = 3; else if (sFontType & TYPE1_FONT) xSrc = 4; BitBlt( hDC, lpdis->rcItem.left, lpdis->rcItem.top + dy, DX_BITMAP, DY_BITMAP, hdcMem, xSrc * DX_BITMAP, lpdis->itemState & ODS_SELECTED ? DY_BITMAP : 0, SRCCOPY ); } SelectObject(hdcMem, hOld); } DeleteDC(hdcMem); } SetTextColor(hDC, rgbText); SetBkColor(hDC, rgbBack); return (TRUE); } //////////////////////////////////////////////////////////////////////////// // // LoadBitmaps // // Loads DIB bitmaps and "fixes up" their color tables so that we get the // desired result for the device we are on. // // This routine requires: // - the DIB is a 16 color DIB authored with the standard windows colors // - bright blue (00 00 FF) is converted to the background color // - light grey (C0 C0 C0) is replaced with the button face color // - dark grey (80 80 80) is replaced with the button shadow color // // This means you can't have any of these colors in your bitmap. // //////////////////////////////////////////////////////////////////////////// HBITMAP LoadBitmaps( INT id) { HDC hdc; HANDLE h, hRes; DWORD *p; LPBYTE lpBits; LPBITMAPINFOHEADER lpBitmapInfo; INT numcolors; DWORD rgbSelected, rgbUnselected; HBITMAP hbm; rgbSelected = GetSysColor(COLOR_HIGHLIGHT); // // Flip the colors. // rgbSelected = RGB( GetBValue(rgbSelected), GetGValue(rgbSelected), GetRValue(rgbSelected) ); rgbUnselected = GetSysColor(COLOR_WINDOW); // // Flip the colors. // rgbUnselected = RGB( GetBValue(rgbUnselected), GetGValue(rgbUnselected), GetRValue(rgbUnselected) ); h = FindResource(hInst, MAKEINTRESOURCE(id), RT_BITMAP); hRes = LoadResource(hInst, h); // // Lock the bitmap and get a pointer to the color table. // lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes); if (!lpBitmapInfo) { return (FALSE); } p = (DWORD *)((LPSTR)(lpBitmapInfo) + lpBitmapInfo->biSize); // // Search for the Solid Blue entry and replace it with the current // background RGB. // numcolors = 16; while (numcolors-- > 0) { if (*p == BACKGROUND) { *p = rgbUnselected; } else if (*p == BACKGROUNDSEL) { *p = rgbSelected; } p++; } UnlockResource(hRes); // // Now create the DIB. // lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes); // // First skip over the header structure. // lpBits = (LPBYTE)(lpBitmapInfo + 1); // // Skip the color table entries, if any. // lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD); // // Create a color bitmap compatible with the display device. // hdc = GetDC(NULL); hbm = CreateDIBitmap( hdc, lpBitmapInfo, (DWORD)CBM_INIT, lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS ); ReleaseDC(NULL, hdc); GlobalUnlock(hRes); FreeResource(hRes); return (hbm); } //////////////////////////////////////////////////////////////////////////// // // DoHelp // // Invokes help if fInvokeHelp is true, or dismisses help if fInvokeHelp // is FALSE. // //////////////////////////////////////////////////////////////////////////// VOID DoHelp( HWND hWnd, BOOL fInvokeHelp) { TCHAR szHelp[80]; if (LoadString(hInst, IDS_HELP, szHelp, BTOC(sizeof(szHelp)) - 1)) { if (fInvokeHelp) { // APPCOMPAT: an error in HtmlHelp prevents the unicode version from working // This is a HACK to get around the problem. Remove this hack when the problem is fixed. HtmlHelpA(GetDesktopWindow(), "charmap.chm", HH_DISPLAY_TOPIC, 0L); } } } //////////////////////////////////////////////////////////////////////////// // // SaveFont // // Saves the current font facename in win.ini, so that it can be selected // the next time charmap comes up. // //////////////////////////////////////////////////////////////////////////// VOID SaveCurrentFont( HWND hWndDlg) { TCHAR szFaceName[LF_FACESIZE] = TEXT(""); SendDlgItemMessage( hWndDlg, ID_FONT, CB_GETLBTEXT, (WORD)SendDlgItemMessage( hWndDlg, ID_FONT, CB_GETCURSEL, 0, 0L ), (LONG)(LPTSTR)szFaceName ); WriteProfileString(TEXT("MSCharMap"), TEXT("Font"), (LPTSTR)szFaceName); } //////////////////////////////////////////////////////////////////////////// // // SelectInitialFont // // Selects the initial font by getting a saved facename from win.ini and // selecting it in the combo box. // // Returns index to font selected. // //////////////////////////////////////////////////////////////////////////// INT SelectInitialFont( HWND hWndDlg) { TCHAR szFaceName[LF_FACESIZE] = TEXT(""); INT iIndex; if ((GetProfileString( TEXT("MSCharMap"), TEXT("Font"), NULL, (LPTSTR)szFaceName, BTOC(sizeof(szFaceName)) ) == 0) || ((iIndex = (INT)SendDlgItemMessage( hWndDlg, ID_FONT, CB_SELECTSTRING, (WPARAM)-1, (LONG)(LPTSTR)szFaceName )) == CB_ERR)) { // // If there was no profile or the selection failed then try selecting // the symbol font, if that fails then select the first one. // if ((iIndex = (INT)SendDlgItemMessage( hWndDlg, ID_FONT, CB_SELECTSTRING, (WPARAM)-1, (LONG)(LPTSTR)TEXT("Symbol") )) == CB_ERR) { SendDlgItemMessage(hWndDlg, ID_FONT, CB_SETCURSEL, iIndex = 0, 0L); } } return (iIndex); } //////////////////////////////////////////////////////////////////////////// // // SaveCurrentSubset // // Saves the current subset name in win.ini, so that it can be selected // the next time charmap comes up. // //////////////////////////////////////////////////////////////////////////// VOID SaveCurrentSubset( HWND hWndDlg) { TCHAR szSubsetName[LF_SUBSETSIZE] = TEXT(""); SendDlgItemMessage( hWndDlg, ID_UNICODESUBSET, CB_GETLBTEXT, (WORD)SendDlgItemMessage( hWndDlg, ID_UNICODESUBSET, CB_GETCURSEL, 0, 0L ), (LONG)(LPTSTR)szSubsetName ); WriteProfileString(TEXT("MSCharMap"), TEXT("Block"), (LPTSTR)szSubsetName); } //////////////////////////////////////////////////////////////////////////// // // SelectInitialSubset // // Selects the initial Unicode subset by getting a saved block name from // win.ini. // // Returns index to subset selected. // //////////////////////////////////////////////////////////////////////////// INT SelectInitialSubset( HWND hWndDlg) { TCHAR szSubsetName[LF_SUBSETSIZE] = TEXT(""); INT iIndex; if ((GetProfileString( TEXT("MSCharMap"), TEXT("Block"), NULL, (LPTSTR)szSubsetName, BTOC(sizeof(szSubsetName)) ) == 0) || ((iIndex = (INT)SendDlgItemMessage( hWndDlg, ID_UNICODESUBSET, CB_SELECTSTRING, (WPARAM)-1, (LONG)(LPTSTR)szSubsetName )) == CB_ERR)) { // // If there was no profile or the selection failed then try selecting // the Basic Latin block, if that fails then select the first one. // if ((iIndex = (INT)SendDlgItemMessage( hWndDlg, ID_UNICODESUBSET, CB_SELECTSTRING, (WPARAM)-1, (LONG)(LPTSTR)TEXT("Basic Latin") )) == CB_ERR) { SendDlgItemMessage( hWndDlg, ID_UNICODESUBSET, CB_SETCURSEL, iIndex = 0, 0L ); } } chSymFirst = aSubsetData[iIndex].BeginRange; chSymLast = aSubsetData[iIndex].EndRange; sycm.chCurr = chSymFirst; return (iIndex); } //////////////////////////////////////////////////////////////////////////// // // ExitMagnify // // Releases mouse capture, exits magnify mode, and restores the cursor. // //////////////////////////////////////////////////////////////////////////// VOID ExitMagnify( HWND hWnd, PSYCM psycm) { // // Release capture, remove magnified character, restore cursor. // ReleaseCapture(); RestoreSymMag(psycm); DrawSymChOutlineHwnd(psycm, hWnd, psycm->chCurr, TRUE, TRUE); if (psycm->fCursorOff) { ShowCursor(TRUE); } psycm->fMouseDn = psycm->fCursorOff = FALSE; } //////////////////////////////////////////////////////////////////////////// // // SetEditCtlFont // // Creates a font for the Edit control that visually matches the handle // given, but is guaranteed not to be bigger than the size of the edit // control. // //////////////////////////////////////////////////////////////////////////// void SetEditCtlFont( HWND hwndDlg, int idCtl, HFONT hfont) { static HFONT hfNew = NULL; LOGFONT lfNew; HWND hwndCtl = GetDlgItem(hwndDlg, idCtl); RECT rc; if (hfNew != NULL) { DeleteObject(hfNew); } GetWindowRect(hwndCtl, &rc); if (GetObject(hfont, sizeof(lfNew), &lfNew) != 0) { lfNew.lfHeight = rc.bottom - rc.top - 8; lfNew.lfWidth = lfNew.lfEscapement = lfNew.lfOrientation = lfNew.lfWeight = 0; hfNew = CreateFontIndirect(&lfNew); } else { hfNew = hfont; } SendMessage(hwndCtl, WM_SETFONT, (WPARAM)hfNew, (LPARAM)TRUE); if (hfNew == hfont) { hfNew = NULL; } }