/* * kml.c * * This file is part of Emu48 * * Copyright (C) 1995 Sebastien Carlier * */ #include "pch.h" #include "resource.h" #include "Emu48.h" #include "kml.h" static VOID FatalError(VOID); static VOID InitLex(LPTSTR szScript); static VOID CleanLex(VOID); static VOID SkipWhite(UINT nMode); static TokenId ParseToken(UINT nMode); static DWORD ParseInteger(VOID); static LPTSTR ParseString(VOID); static TokenId Lex(UINT nMode); static KmlLine* ParseLine(TokenId eCommand); static KmlLine* IncludeLines(LPCTSTR szFilename); static KmlLine* ParseLines(VOID); static KmlBlock* ParseBlock(TokenId eBlock); static KmlBlock* IncludeBlocks(LPCTSTR szFilename); static KmlBlock* ParseBlocks(VOID); static VOID FreeLines(KmlLine* pLine); static VOID PressButton(UINT nId); static VOID ReleaseButton(UINT nId); static VOID PressButtonById(UINT nId); static VOID ReleaseButtonById(UINT nId); static LPTSTR GetStringParam(KmlBlock* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam); static DWORD GetIntegerParam(KmlBlock* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam); static KmlLine* SkipLines(KmlLine* pLine, TokenId eCommand); static KmlLine* If(KmlLine* pLine, BOOL bCondition); static KmlLine* RunLine(KmlLine* pLine); static KmlBlock* LoadKMLGlobal(LPCTSTR szFilename); KmlBlock* pKml = NULL; static KmlBlock* pVKey[256]; static BYTE byVKeyMap[256]; static KmlButton pButton[256]; static KmlAnnunciator pAnnunciator[6]; static UINT nButtons = 0; static UINT nScancodes = 0; static UINT nAnnunciators = 0; static BOOL bDebug = TRUE; static UINT nLexLine; static UINT nLexInteger; static UINT nBlocksIncludeLevel; static UINT nLinesIncludeLevel; static DWORD nKMLFlags = 0; static LPTSTR szLexString; static LPTSTR szText; static LPCTSTR szLexDelim[] = { _T(" \t\n\r"), // valid whitespaces for LEX_BLOCK _T(" \t\n\r"), // valid whitespaces for LEX_COMMAND _T(" \t\r") // valid whitespaces for LEX_PARAM }; static KmlToken pLexToken[] = { {TOK_ANNUNCIATOR,000001,11,_T("Annunciator")}, {TOK_BACKGROUND, 000000,10,_T("Background")}, {TOK_IFPRESSED, 000001, 9,_T("IfPressed")}, {TOK_RESETFLAG, 000001, 9,_T("ResetFlag")}, {TOK_SCANCODE, 000001, 8,_T("Scancode")}, {TOK_HARDWARE, 000002, 8,_T("Hardware")}, {TOK_MENUITEM, 000001, 8,_T("MenuItem")}, {TOK_SETFLAG, 000001, 7,_T("SetFlag")}, {TOK_RELEASE, 000001, 7,_T("Release")}, {TOK_VIRTUAL, 000000, 7,_T("Virtual")}, {TOK_INCLUDE, 000002, 7,_T("Include")}, {TOK_NOTFLAG, 000001, 7,_T("NotFlag")}, {TOK_MENUBAR, 000001, 7,_T("Menubar")}, // for PPC compatibility reasons {TOK_GLOBAL, 000000, 6,_T("Global")}, {TOK_AUTHOR, 000002, 6,_T("Author")}, {TOK_BITMAP, 000002, 6,_T("Bitmap")}, {TOK_OFFSET, 000011, 6,_T("Offset")}, {TOK_BUTTON, 000001, 6,_T("Button")}, {TOK_IFFLAG, 000001, 6,_T("IfFlag")}, {TOK_ONDOWN, 000000, 6,_T("OnDown")}, {TOK_NOHOLD, 000000, 6,_T("NoHold")}, {TOK_TOPBAR, 000001, 6,_T("Topbar")}, // for PPC compatibility reasons {TOK_TITLE, 000002, 5,_T("Title")}, {TOK_OUTIN, 000011, 5,_T("OutIn")}, {TOK_PATCH, 000002, 5,_T("Patch")}, {TOK_PRINT, 000002, 5,_T("Print")}, {TOK_DEBUG, 000001, 5,_T("Debug")}, {TOK_COLOR, 001111, 5,_T("Color")}, {TOK_MODEL, 000002, 5,_T("Model")}, {TOK_CLASS, 000001, 5,_T("Class")}, {TOK_PRESS, 000001, 5,_T("Press")}, {TOK_TYPE, 000001, 4,_T("Type")}, {TOK_SIZE, 000011, 4,_T("Size")}, {TOK_ZOOM, 000001, 4,_T("Zoom")}, {TOK_DOWN, 000011, 4,_T("Down")}, {TOK_ELSE, 000000, 4,_T("Else")}, {TOK_ONUP, 000000, 4,_T("OnUp")}, {TOK_MAP, 000011, 3,_T("Map")}, {TOK_ROM, 000002, 3,_T("Rom")}, {TOK_VGA, 000001, 3,_T("Vga")}, // for PPC compatibility reasons {TOK_LCD, 000000, 3,_T("Lcd")}, {TOK_END, 000000, 3,_T("End")}, {0, 000000, 0,_T("")}, }; static CONST TokenId eIsGlobalBlock[] = { TOK_GLOBAL, TOK_BACKGROUND, TOK_LCD, TOK_ANNUNCIATOR, TOK_BUTTON, TOK_SCANCODE }; static CONST TokenId eIsBlock[] = { TOK_IFFLAG, TOK_IFPRESSED, TOK_ONDOWN, TOK_ONUP }; static BOOL bClicking = FALSE; static UINT uButtonClicked = 0; static BOOL bPressed = FALSE; // no key pressed static UINT uLastPressedKey = 0; // var for last pressed key //################ //# //# Compilation Result //# //################ static UINT nLogLength = 0; static LPTSTR szLog = NULL; static VOID ClearLog() { nLogLength = 0; if (szLog != NULL) { HeapFree(hHeap,0,szLog); szLog = NULL; } return; } static VOID AddToLog(LPCTSTR szString) { UINT nLength = lstrlen(szString) + 2; // CR+LF if (szLog == NULL) { nLogLength = nLength + 1; // \0 szLog = HeapAlloc(hHeap,0,nLogLength*sizeof(szLog[0])); if (szLog==NULL) { nLogLength = 0; return; } lstrcpy(szLog,szString); } else { LPTSTR szLogTmp = HeapReAlloc(hHeap,0,szLog,(nLogLength+nLength)*sizeof(szLog[0])); if (szLogTmp == NULL) { ClearLog(); return; } szLog = szLogTmp; lstrcpy(&szLog[nLogLength-1],szString); nLogLength += nLength; } szLog[nLogLength-3] = _T('\r'); szLog[nLogLength-2] = _T('\n'); szLog[nLogLength-1] = 0; return; } static VOID __cdecl PrintfToLog(LPCTSTR lpFormat, ...) { TCHAR cOutput[1024]; va_list arglist; va_start(arglist,lpFormat); wvsprintf(cOutput,lpFormat,arglist); AddToLog(cOutput); va_end(arglist); return; } static BOOL CALLBACK KMLLogProc(HWND hDlg, UINT message, DWORD wParam, LONG lParam) { LPCTSTR szString; switch (message) { case WM_INITDIALOG: // set OK EnableWindow(GetDlgItem(hDlg,IDOK),lParam); // set IDC_TITLE szString = GetStringParam(pKml, TOK_GLOBAL, TOK_TITLE, 0); if (szString == NULL) szString = _T("Untitled"); SetDlgItemText(hDlg,IDC_TITLE,szString); // set IDC_AUTHOR szString = GetStringParam(pKml, TOK_GLOBAL, TOK_AUTHOR, 0); if (szString == NULL) szString = _T(""); SetDlgItemText(hDlg,IDC_AUTHOR,szString); // set IDC_KMLLOG szString = szLog; if (szString == NULL) szString = _T("Memory Allocation Failure."); SetDlgItemText(hDlg,IDC_KMLLOG,szString); // set IDC_ALWAYSDISPLOG CheckDlgButton(hDlg,IDC_ALWAYSDISPLOG,bAlwaysDisplayLog); return TRUE; case WM_COMMAND: wParam = LOWORD(wParam); if ((wParam==IDOK)||(wParam==IDCANCEL)) { bAlwaysDisplayLog = IsDlgButtonChecked(hDlg, IDC_ALWAYSDISPLOG); EndDialog(hDlg, wParam); return TRUE; } break; } return FALSE; } BOOL DisplayKMLLog(BOOL bOkEnabled) { return IDOK == DialogBoxParam(hApp, MAKEINTRESOURCE(IDD_KMLLOG), hWnd, (DLGPROC)KMLLogProc, bOkEnabled); } //################ //# //# Choose Script //# //################ typedef struct _KmlScript { LPTSTR szFilename; LPTSTR szTitle; DWORD nId; struct _KmlScript* pNext; } KmlScript; static KmlScript* pKmlList = NULL; static CHAR cKmlType; static VOID DestroyKmlList(VOID) { KmlScript* pList; while (pKmlList) { pList = pKmlList->pNext; HeapFree(hHeap,0,pKmlList->szFilename); HeapFree(hHeap,0,pKmlList->szTitle); HeapFree(hHeap,0,pKmlList); pKmlList = pList; } return; } static VOID CreateKmlList(VOID) { HANDLE hFindFile; WIN32_FIND_DATA pFindFileData; UINT nKmlFiles; _ASSERT(pKmlList == NULL); // KML file list must be empty SetCurrentDirectory(szEmuDirectory); hFindFile = FindFirstFile(_T("*.KML"),&pFindFileData); SetCurrentDirectory(szCurrentDirectory); if (hFindFile == INVALID_HANDLE_VALUE) return; nKmlFiles = 0; do { KmlScript* pScript; KmlBlock* pBlock; LPTSTR szTitle; pBlock = LoadKMLGlobal(pFindFileData.cFileName); if (pBlock == NULL) continue; // check for correct KML script platform szTitle = GetStringParam(pBlock,TOK_GLOBAL,TOK_HARDWARE,0); if (szTitle && lstrcmpi(_T(HARDWARE),szTitle) != 0) { FreeBlocks(pBlock); continue; } // check for supported Model szTitle = GetStringParam(pBlock,TOK_GLOBAL,TOK_MODEL,0); // skip all scripts with invalid or different Model statement if ( (szTitle == NULL) || (cKmlType && szTitle[0] != cKmlType) || !isModelValid(szTitle[0])) { FreeBlocks(pBlock); continue; } VERIFY(pScript = HeapAlloc(hHeap,0,sizeof(KmlScript))); pScript->szFilename = DuplicateString(pFindFileData.cFileName); szTitle = GetStringParam(pBlock,TOK_GLOBAL,TOK_TITLE,0); if (szTitle == NULL) szTitle = pScript->szFilename; pScript->szTitle = DuplicateString(szTitle); FreeBlocks(pBlock); pScript->nId = nKmlFiles; pScript->pNext = pKmlList; pKmlList = pScript; nKmlFiles++; } while (FindNextFile(hFindFile,&pFindFileData)); FindClose(hFindFile); return; }; static INT CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) { TCHAR szDir[MAX_PATH]; switch(uMsg) { case BFFM_INITIALIZED: SendMessage(hwnd,BFFM_SETSELECTION,TRUE,pData); break; case BFFM_SELCHANGED: // Set the status window to the currently selected path. if (SHGetPathFromIDList((LPITEMIDLIST) lp,szDir)) { SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM) szDir); } break; } return 0; } static VOID BrowseFolder(HWND hDlg) { TCHAR szDir[MAX_PATH]; BROWSEINFO bi; LPITEMIDLIST pidl; LPMALLOC pMalloc; // gets the shell's default allocator if (SUCCEEDED(SHGetMalloc(&pMalloc))) { GetDlgItemText(hDlg,IDC_EMUDIR,szDir,ARRAYSIZEOF(szDir)); ZeroMemory(&bi,sizeof(bi)); bi.hwndOwner = hDlg; bi.pidlRoot = NULL; bi.pszDisplayName = NULL; bi.lpszTitle = _T("Choose a folder:"); bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT; bi.lpfn = BrowseCallbackProc; bi.lParam = (LPARAM) szDir; // current setting pidl = SHBrowseForFolder(&bi); if (pidl) { if (SHGetPathFromIDList(pidl,szDir)) { SetDlgItemText(hDlg,IDC_EMUDIR,szDir); } // free the PIDL allocated by SHBrowseForFolder pMalloc->lpVtbl->Free(pMalloc,pidl); } // release the shell's allocator pMalloc->lpVtbl->Release(pMalloc); } return; } static BOOL CALLBACK ChooseKMLProc(HWND hDlg, UINT message, DWORD wParam, LONG lParam) { HWND hList; KmlScript* pList; UINT nIndex; switch (message) { case WM_INITDIALOG: SetDlgItemText(hDlg,IDC_EMUDIR,szEmuDirectory); hList = GetDlgItem(hDlg,IDC_KMLSCRIPT); SendMessage(hList, CB_RESETCONTENT, 0, 0); pList = pKmlList; while (pList) { nIndex = SendMessage(hList, CB_ADDSTRING, 0, (LPARAM)pList->szTitle); SendMessage(hList, CB_SETITEMDATA, nIndex, (LPARAM)pList->nId); pList = pList->pNext; } SendMessage(hList, CB_SETCURSEL, 0, 0); return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_EMUDIRSEL: BrowseFolder(hDlg); // select new folder for IDC_EMUDIR // fall into IDC_UPDATE to search for KML files in new folder case IDC_UPDATE: DestroyKmlList(); GetDlgItemText(hDlg,IDC_EMUDIR,szEmuDirectory,ARRAYSIZEOF(szEmuDirectory)); CreateKmlList(); hList = GetDlgItem(hDlg,IDC_KMLSCRIPT); SendMessage(hList, CB_RESETCONTENT, 0, 0); pList = pKmlList; while (pList) { nIndex = SendMessage(hList, CB_ADDSTRING, 0, (LPARAM)pList->szTitle); SendMessage(hList, CB_SETITEMDATA, nIndex, (LPARAM)pList->nId); pList = pList->pNext; } SendMessage(hList, CB_SETCURSEL, 0, 0); return TRUE; case IDOK: GetDlgItemText(hDlg,IDC_EMUDIR,szEmuDirectory,ARRAYSIZEOF(szEmuDirectory)); hList = GetDlgItem(hDlg,IDC_KMLSCRIPT); nIndex = SendMessage(hList, CB_GETCURSEL, 0, 0); nIndex = SendMessage(hList, CB_GETITEMDATA, nIndex, 0); pList = pKmlList; while (pList) { if (pList->nId == nIndex) { lstrcpy(szCurrentKml, pList->szFilename); EndDialog(hDlg, IDOK); break; } pList = pList->pNext; } return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } } return FALSE; UNREFERENCED_PARAMETER(lParam); } BOOL DisplayChooseKml(CHAR cType) { BOOL bResult; cKmlType = cType; CreateKmlList(); bResult = DialogBox(hApp, MAKEINTRESOURCE(IDD_CHOOSEKML), hWnd, (DLGPROC)ChooseKMLProc); DestroyKmlList(); return (bResult == IDOK); } //################ //# //# KML File Mapping //# //################ static LPTSTR MapKMLFile(HANDLE hFile) { DWORD lBytesRead; DWORD dwFileSizeLow; DWORD dwFileSizeHigh; LPTSTR lpBuf = NULL; dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh); if (dwFileSizeHigh != 0) { AddToLog(_T("File is too large.")); goto fail; } lpBuf = HeapAlloc(hHeap,0,(dwFileSizeLow+1)*sizeof(lpBuf[0])); if (lpBuf == NULL) { PrintfToLog(_T("Cannot allocate %i bytes."), (dwFileSizeLow+1)*sizeof(lpBuf[0])); goto fail; } #if defined _UNICODE { LPSTR szTmp = HeapAlloc(hHeap,0,dwFileSizeLow+1); if (szTmp == NULL) { HeapFree(hHeap,0,lpBuf); lpBuf = NULL; PrintfToLog(_T("Cannot allocate %i bytes."), dwFileSizeLow+1); goto fail; } ReadFile(hFile, szTmp, dwFileSizeLow, &lBytesRead, NULL); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szTmp, lBytesRead, lpBuf, dwFileSizeLow+1); HeapFree(hHeap,0,szTmp); } #else { ReadFile(hFile, lpBuf, dwFileSizeLow, &lBytesRead, NULL); } #endif lpBuf[dwFileSizeLow] = 0; fail: CloseHandle(hFile); return lpBuf; } //################ //# //# Script Parsing //# //################ static VOID FatalError(VOID) { PrintfToLog(_T("Fatal Error at line %i"), nLexLine); szText[0] = 0; return; } static VOID InitLex(LPTSTR szScript) { nLexLine = 1; szText = szScript; return; } static VOID CleanLex(VOID) { nLexLine = 0; nLexInteger = 0; szLexString = NULL; szText = NULL; return; } static BOOL IsGlobalBlock(TokenId eId) { UINT i; for (i = 0; i < ARRAYSIZEOF(eIsGlobalBlock); ++i) { if (eId == eIsGlobalBlock[i]) return TRUE; } return FALSE; } static BOOL IsBlock(TokenId eId) { UINT i; for (i = 0; i < ARRAYSIZEOF(eIsBlock); ++i) { if (eId == eIsBlock[i]) return TRUE; } return FALSE; } static LPCTSTR GetStringOf(TokenId eId) { UINT i = 0; while (pLexToken[i].nLen) { if (pLexToken[i].eId == eId) return pLexToken[i].szName; i++; } return _T(""); } static VOID SkipWhite(UINT nMode) { UINT i; loop: i = 0; while (szLexDelim[nMode][i]) { if (*szText == szLexDelim[nMode][i]) break; i++; } if (szLexDelim[nMode][i] != 0) { if (szLexDelim[nMode][i]==_T('\n')) nLexLine++; szText++; goto loop; } if (*szText==_T('#')) { do szText++; while (*szText != _T('\n') && *szText != 0); if (nMode != LEX_PARAM) goto loop; } return; } static TokenId ParseToken(UINT nMode) { UINT i, j, k; i = 0; while (szText[i]) { j = 0; while (szLexDelim[nMode][j]) { if (szLexDelim[nMode][j] == szText[i]) break; j++; } if (szLexDelim[nMode][j] == _T('\n')) nLexLine++; if (szLexDelim[nMode][j] != 0) break; i++; } if (i==0) { return TOK_NONE; } j = 0; while (pLexToken[j].nLen) { if (pLexToken[j].nLen>i) { j++; continue; } if (pLexToken[j].nLen= LEX_BLOCK && nMode <= LEX_PARAM); _ASSERT(nMode >= 0 && nMode < ARRAYSIZEOF(szLexDelim)); SkipWhite(nMode); if (_istdigit(*szText)) { nLexInteger = ParseInteger(); return TOK_INTEGER; } if (*szText == _T('"')) { szLexString = ParseString(); return TOK_STRING; } if (nMode == LEX_PARAM) { if (*szText == _T('\n')) // end of line { nLexLine++; // next line szText++; // skip LF return TOK_EOL; } if (*szText == 0) // end of file { return TOK_EOL; } } return ParseToken(nMode); } static KmlLine* ParseLine(TokenId eCommand) { UINT i, j; DWORD nParams; TokenId eToken; KmlLine* pLine; i = 0; while (pLexToken[i].nLen) { if (pLexToken[i].eId == eCommand) break; i++; } if (pLexToken[i].nLen == 0) return NULL; j = 0; pLine = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(KmlLine)); pLine->eCommand = eCommand; nParams = pLexToken[i].nParams; loop: eToken = Lex(LEX_PARAM); if ((nParams&7)==TYPE_NONE) { if (eToken != TOK_EOL) { PrintfToLog(_T("%i: Too many parameters (%i expected)."), nLexLine, j); goto errline; // free memory of arguments } return pLine; } if ((nParams&7)==TYPE_INTEGER) { if (eToken != TOK_INTEGER) { PrintfToLog(_T("%i: Parameter %i of %s must be an integer."), nLexLine, j+1, pLexToken[i].szName); goto errline; // free memory of arguments } pLine->nParam[j++] = nLexInteger; nParams >>= 3; goto loop; } if ((nParams&7)==TYPE_STRING) { if (eToken != TOK_STRING) { PrintfToLog(_T("%i: Parameter %i of %s must be a string."), nLexLine, j+1, pLexToken[i].szName); goto errline; // free memory of arguments } pLine->nParam[j++] = (DWORD)szLexString; nParams >>= 3; goto loop; } AddToLog(_T("Oops...")); errline: // if last argument was string, free it if (eToken == TOK_STRING) HeapFree(hHeap,0,szLexString); nParams = pLexToken[i].nParams; // get argument types of command for (i=0; inParam[i]); } nParams >>= 3; // next argument type } HeapFree(hHeap,0,pLine); return NULL; } static KmlLine* IncludeLines(LPCTSTR szFilename) { HANDLE hFile; LPTSTR lpbyBuf; UINT uOldLine; LPTSTR szOldText; KmlLine* pLine; SetCurrentDirectory(szEmuDirectory); hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); SetCurrentDirectory(szCurrentDirectory); if (hFile == INVALID_HANDLE_VALUE) { PrintfToLog(_T("Error while opening include file %s."), szFilename); FatalError(); return NULL; } if ((lpbyBuf = MapKMLFile(hFile)) == NULL) { FatalError(); return NULL; } uOldLine = nLexLine; szOldText = szText; nLinesIncludeLevel++; PrintfToLog(_T("l%i:Including %s"), nLinesIncludeLevel, szFilename); InitLex(lpbyBuf); pLine = ParseLines(); CleanLex(); nLinesIncludeLevel--; nLexLine = uOldLine; szText = szOldText; HeapFree(hHeap,0,lpbyBuf); return pLine; } static KmlLine* ParseLines(VOID) { KmlLine* pFirst = NULL; KmlLine* pLine = NULL; TokenId eToken; UINT nLevel = 0; while ((eToken = Lex(LEX_COMMAND))) { if (IsGlobalBlock(eToken)) // check for block command { PrintfToLog(_T("%i: Invalid Command %s."), nLexLine, GetStringOf(eToken)); goto abort; } if (IsBlock(eToken)) nLevel++; if (eToken == TOK_INCLUDE) { LPTSTR szFilename; eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString' if (eToken != TOK_STRING) // not a string (token don't begin with ") { AddToLog(_T("Include: string expected as parameter.")); FatalError(); goto abort; } szFilename = szLexString; // save pointer to allocated memory if (pFirst) { pLine->pNext = IncludeLines(szLexString); } else { pLine = pFirst = IncludeLines(szLexString); } HeapFree(hHeap,0,szFilename); // free memory if (pLine == NULL) // parsing error goto abort; while (pLine->pNext) pLine=pLine->pNext; continue; } if (eToken == TOK_END) { if (nLevel) { nLevel--; } else { if (pLine) pLine->pNext = NULL; return pFirst; } } if (pFirst) { pLine = pLine->pNext = ParseLine(eToken); } else { pLine = pFirst = ParseLine(eToken); } if (pLine == NULL) // parsing error goto abort; } if (nLinesIncludeLevel) { if (pLine) pLine->pNext = NULL; return pFirst; } abort: if (pFirst) { FreeLines(pFirst); } return NULL; } static KmlBlock* ParseBlock(TokenId eType) { UINT u1; KmlBlock* pBlock; TokenId eToken; nLinesIncludeLevel = 0; pBlock = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(KmlBlock)); pBlock->eType = eType; u1 = 0; while (pLexToken[u1].nLen) { if (pLexToken[u1].eId == eType) break; u1++; } if (pLexToken[u1].nParams) { eToken = Lex(LEX_COMMAND); switch (eToken) { case TOK_NONE: AddToLog(_T("Open Block at End Of File.")); HeapFree(hHeap,0,pBlock); FatalError(); return NULL; case TOK_INTEGER: if ((pLexToken[u1].nParams&7)!=TYPE_INTEGER) { AddToLog(_T("Wrong block argument.")); HeapFree(hHeap,0,pBlock); FatalError(); return NULL; } pBlock->nId = nLexInteger; break; default: AddToLog(_T("Wrong block argument.")); HeapFree(hHeap,0,pBlock); FatalError(); return NULL; } } pBlock->pFirstLine = ParseLines(); if (pBlock->pFirstLine == NULL) // break on ParseLines error { HeapFree(hHeap,0,pBlock); pBlock = NULL; } return pBlock; } static KmlBlock* IncludeBlocks(LPCTSTR szFilename) { HANDLE hFile; LPTSTR lpbyBuf; UINT uOldLine; LPTSTR szOldText; KmlBlock* pFirst; SetCurrentDirectory(szEmuDirectory); hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); SetCurrentDirectory(szCurrentDirectory); if (hFile == INVALID_HANDLE_VALUE) { PrintfToLog(_T("Error while opening include file %s."), szFilename); FatalError(); return NULL; } if ((lpbyBuf = MapKMLFile(hFile)) == NULL) { FatalError(); return NULL; } uOldLine = nLexLine; szOldText = szText; nBlocksIncludeLevel++; PrintfToLog(_T("b%i:Including %s"), nBlocksIncludeLevel, szFilename); InitLex(lpbyBuf); pFirst = ParseBlocks(); CleanLex(); nBlocksIncludeLevel--; nLexLine = uOldLine; szText = szOldText; HeapFree(hHeap,0,lpbyBuf); return pFirst; } static KmlBlock* ParseBlocks(VOID) { TokenId eToken; KmlBlock* pFirst = NULL; KmlBlock* pBlock = NULL; while ((eToken=Lex(LEX_BLOCK))!=TOK_NONE) { if (eToken == TOK_INCLUDE) { LPTSTR szFilename; eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString' if (eToken != TOK_STRING) // not a string (token don't begin with ") { AddToLog(_T("Include: string expected as parameter.")); FatalError(); goto abort; } szFilename = szLexString; // save pointer to allocated memory if (pFirst) pBlock = pBlock->pNext = IncludeBlocks(szLexString); else pBlock = pFirst = IncludeBlocks(szLexString); HeapFree(hHeap,0,szFilename); // free memory if (pBlock == NULL) // parsing error goto abort; while (pBlock->pNext) pBlock=pBlock->pNext; continue; } if (!IsGlobalBlock(eToken)) // check for valid block commands { PrintfToLog(_T("%i: Invalid Block %s."), nLexLine, GetStringOf(eToken)); FatalError(); goto abort; } if (pFirst) pBlock = pBlock->pNext = ParseBlock(eToken); else pBlock = pFirst = ParseBlock(eToken); if (pBlock == NULL) { AddToLog(_T("Invalid block.")); FatalError(); goto abort; } } if (pFirst) pBlock->pNext = NULL; if (*szText != 0) // still KML text left { FatalError(); // error unknown block token goto abort; } return pFirst; abort: if (pFirst) FreeBlocks(pFirst); return NULL; } //################ //# //# Initialization Phase //# //################ static VOID InitGlobal(KmlBlock* pBlock) { KmlLine* pLine = pBlock->pFirstLine; while (pLine) { switch (pLine->eCommand) { case TOK_TITLE: PrintfToLog(_T("Title: %s"), (LPTSTR)pLine->nParam[0]); break; case TOK_AUTHOR: PrintfToLog(_T("Author: %s"), (LPTSTR)pLine->nParam[0]); break; case TOK_PRINT: AddToLog((LPTSTR)pLine->nParam[0]); break; case TOK_HARDWARE: PrintfToLog(_T("Hardware Platform: %s"), (LPTSTR)pLine->nParam[0]); break; case TOK_MODEL: cCurrentRomType = ((BYTE *)pLine->nParam[0])[0]; PrintfToLog(_T("Calculator Model : %c"), cCurrentRomType); break; case TOK_CLASS: nCurrentClass = pLine->nParam[0]; PrintfToLog(_T("Calculator Class : %u"), nCurrentClass); break; case TOK_DEBUG: bDebug = pLine->nParam[0]&1; PrintfToLog(_T("Debug %s"), bDebug?_T("On"):_T("Off")); break; case TOK_ROM: if (pbyRom != NULL) { PrintfToLog(_T("Rom %s Ignored."), (LPTSTR)pLine->nParam[0]); AddToLog(_T("Please put only one Rom command in the Global block.")); break; } if (!MapRom((LPTSTR)pLine->nParam[0])) { PrintfToLog(_T("Cannot open Rom %s"), (LPTSTR)pLine->nParam[0]); break; } PrintfToLog(_T("Rom %s Loaded."), (LPTSTR)pLine->nParam[0]); break; case TOK_PATCH: if (pbyRom == NULL) { PrintfToLog(_T("Patch %s ignored."), (LPTSTR)pLine->nParam[0]); AddToLog(_T("Please put the Rom command before any Patch.")); break; } if (PatchRom((LPTSTR)pLine->nParam[0]) == TRUE) PrintfToLog(_T("Patch %s Loaded"), (LPTSTR)pLine->nParam[0]); else PrintfToLog(_T("Patch %s is Wrong or Missing"), (LPTSTR)pLine->nParam[0]); break; case TOK_BITMAP: if (hMainDC != NULL) { PrintfToLog(_T("Bitmap %s Ignored."), (LPTSTR)pLine->nParam[0]); AddToLog(_T("Please put only one Bitmap command in the Global block.")); break; } if (!CreateMainBitmap((LPTSTR)pLine->nParam[0])) { PrintfToLog(_T("Cannot Load Bitmap %s."), (LPTSTR)pLine->nParam[0]); break; } PrintfToLog(_T("Bitmap %s Loaded."), (LPTSTR)pLine->nParam[0]); break; default: PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); } pLine = pLine->pNext; } return; } static KmlLine* InitBackground(KmlBlock* pBlock) { KmlLine* pLine = pBlock->pFirstLine; while (pLine) { switch (pLine->eCommand) { case TOK_OFFSET: nBackgroundX = pLine->nParam[0]; nBackgroundY = pLine->nParam[1]; break; case TOK_SIZE: nBackgroundW = pLine->nParam[0]; nBackgroundH = pLine->nParam[1]; break; case TOK_END: return pLine; default: PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); } pLine = pLine->pNext; } return NULL; } static KmlLine* InitLcd(KmlBlock* pBlock) { KmlLine* pLine = pBlock->pFirstLine; while (pLine) { switch (pLine->eCommand) { case TOK_OFFSET: nLcdX = pLine->nParam[0]; nLcdY = pLine->nParam[1]; break; case TOK_ZOOM: nLcdZoom = pLine->nParam[0]; if (!(nLcdZoom >= 1 && nLcdZoom <= 4)) nLcdZoom = 1; break; case TOK_COLOR: SetLcdColor(pLine->nParam[0],pLine->nParam[1],pLine->nParam[2],pLine->nParam[3]); break; case TOK_END: return pLine; default: PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); } pLine = pLine->pNext; } return NULL; } static KmlLine* InitAnnunciator(KmlBlock* pBlock) { KmlLine* pLine = pBlock->pFirstLine; UINT nId = pBlock->nId-1; if (nId >= ARRAYSIZEOF(pAnnunciator)) { PrintfToLog(_T("Wrong Annunciator Id %i"), nId); return NULL; } nAnnunciators++; while (pLine) { switch (pLine->eCommand) { case TOK_OFFSET: pAnnunciator[nId].nOx = pLine->nParam[0]; pAnnunciator[nId].nOy = pLine->nParam[1]; break; case TOK_DOWN: pAnnunciator[nId].nDx = pLine->nParam[0]; pAnnunciator[nId].nDy = pLine->nParam[1]; break; case TOK_SIZE: pAnnunciator[nId].nCx = pLine->nParam[0]; pAnnunciator[nId].nCy = pLine->nParam[1]; break; case TOK_END: return pLine; default: PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); } pLine = pLine->pNext; } return NULL; } static VOID InitButton(KmlBlock* pBlock) { KmlLine* pLine = pBlock->pFirstLine; UINT nLevel = 0; if (nButtons>=256) { AddToLog(_T("Only the first 256 buttons will be defined.")); return; } pButton[nButtons].nId = pBlock->nId; pButton[nButtons].bDown = FALSE; pButton[nButtons].nType = 0; // default : user defined button while (pLine) { if (nLevel) { if (IsBlock(pLine->eCommand)) nLevel++; if (pLine->eCommand == TOK_END) nLevel--; pLine = pLine->pNext; continue; } if (IsBlock(pLine->eCommand)) nLevel++; switch (pLine->eCommand) { case TOK_TYPE: pButton[nButtons].nType = pLine->nParam[0]; break; case TOK_OFFSET: pButton[nButtons].nOx = pLine->nParam[0]; pButton[nButtons].nOy = pLine->nParam[1]; break; case TOK_DOWN: pButton[nButtons].nDx = pLine->nParam[0]; pButton[nButtons].nDy = pLine->nParam[1]; break; case TOK_SIZE: pButton[nButtons].nCx = pLine->nParam[0]; pButton[nButtons].nCy = pLine->nParam[1]; break; case TOK_OUTIN: pButton[nButtons].nOut = pLine->nParam[0]; pButton[nButtons].nIn = pLine->nParam[1]; break; case TOK_ONDOWN: pButton[nButtons].pOnDown = pLine; break; case TOK_ONUP: pButton[nButtons].pOnUp = pLine; break; case TOK_NOHOLD: pButton[nButtons].dwFlags &= ~(BUTTON_VIRTUAL); pButton[nButtons].dwFlags |= BUTTON_NOHOLD; break; case TOK_VIRTUAL: pButton[nButtons].dwFlags &= ~(BUTTON_NOHOLD); pButton[nButtons].dwFlags |= BUTTON_VIRTUAL; break; default: PrintfToLog(_T("Command %s Ignored in Block %s %i"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType), pBlock->nId); } pLine = pLine->pNext; } if (nLevel) PrintfToLog(_T("%i Open Block(s) in Block %s %i"), nLevel, GetStringOf(pBlock->eType), pBlock->nId); nButtons++; return; } //################ //# //# Execution //# //################ static KmlLine* SkipLines(KmlLine* pLine, TokenId eCommand) { UINT nLevel = 0; while (pLine) { if (IsBlock(pLine->eCommand)) nLevel++; if (pLine->eCommand == eCommand) { // found token, return command behind token if (nLevel == 0) return pLine->pNext; } if (pLine->eCommand == TOK_END) { if (nLevel) nLevel--; else break; } pLine = pLine->pNext; } return pLine; } static KmlLine* If(KmlLine* pLine, BOOL bCondition) { pLine = pLine->pNext; if (bCondition) { while (pLine) { if (pLine->eCommand == TOK_END) { pLine = pLine->pNext; break; } if (pLine->eCommand == TOK_ELSE) { pLine = SkipLines(pLine, TOK_END); break; } pLine = RunLine(pLine); } } else { pLine = SkipLines(pLine, TOK_ELSE); while (pLine) { if (pLine->eCommand == TOK_END) { pLine = pLine->pNext; break; } pLine = RunLine(pLine); } } return pLine; } static KmlLine* RunLine(KmlLine* pLine) { switch (pLine->eCommand) { case TOK_MAP: if (byVKeyMap[pLine->nParam[0]&0xFF]&1) PressButtonById(pLine->nParam[1]); else ReleaseButtonById(pLine->nParam[1]); break; case TOK_PRESS: PressButtonById(pLine->nParam[0]); break; case TOK_RELEASE: ReleaseButtonById(pLine->nParam[0]); break; case TOK_MENUITEM: PostMessage(hWnd, WM_COMMAND, 0x19C40+(pLine->nParam[0]&0xFF), 0); break; case TOK_SETFLAG: nKMLFlags |= 1<<(pLine->nParam[0]&0x1F); break; case TOK_RESETFLAG: nKMLFlags &= ~(1<<(pLine->nParam[0]&0x1F)); break; case TOK_NOTFLAG: nKMLFlags ^= 1<<(pLine->nParam[0]&0x1F); break; case TOK_IFPRESSED: return If(pLine,byVKeyMap[pLine->nParam[0]&0xFF]); break; case TOK_IFFLAG: return If(pLine,(nKMLFlags>>(pLine->nParam[0]&0x1F))&1); default: break; } return pLine->pNext; } //################ //# //# Clean Up //# //################ static VOID FreeLines(KmlLine* pLine) { while (pLine) { KmlLine* pThisLine = pLine; UINT i = 0; DWORD nParams; while (pLexToken[i].nLen) // search in all token definitions { // break when token definition found if (pLexToken[i].eId == pLine->eCommand) break; i++; // next token definition } nParams = pLexToken[i].nParams; // get argument types of command i = 0; // first parameter while ((nParams&7)) // argument left { if ((nParams&7) == TYPE_STRING) // string type { HeapFree(hHeap,0,(LPVOID)pLine->nParam[i]); } i++; // incr. parameter buffer index nParams >>= 3; // next argument type } pLine = pLine->pNext; // get next line HeapFree(hHeap,0,pThisLine); } return; } VOID FreeBlocks(KmlBlock* pBlock) { while (pBlock) { KmlBlock* pThisBlock = pBlock; pBlock = pBlock->pNext; FreeLines(pThisBlock->pFirstLine); HeapFree(hHeap,0,pThisBlock); } return; } VOID KillKML(VOID) { if ((nState==SM_RUN)||(nState==SM_SLEEP)) { AbortMessage(_T("FATAL: KillKML while emulator is running !!!")); SwitchToState(SM_RETURN); DestroyWindow(hWnd); } UnmapRom(); DestroyLcdBitmap(); DestroyMainBitmap(); if (hPalette) { BOOL err; if (hWindowDC) SelectPalette(hWindowDC, hOldPalette, FALSE); err = DeleteObject(hPalette); _ASSERT(err != FALSE); // freed resource memory hPalette = NULL; } bClicking = FALSE; uButtonClicked = 0; FreeBlocks(pKml); pKml = NULL; nButtons = 0; nScancodes = 0; nAnnunciators = 0; bDebug = TRUE; nKMLFlags = 0; ZeroMemory(pButton, sizeof(pButton)); ZeroMemory(pAnnunciator, sizeof(pAnnunciator)); ZeroMemory(pVKey, sizeof(pVKey)); ClearLog(); nBackgroundX = 0; nBackgroundY = 0; nBackgroundW = 256; nBackgroundH = 0; nLcdZoom = 1; cCurrentRomType = 0; UpdateWindowStatus(); ResizeWindow(); return; } //################ //# //# Extract Keyword's Parameters //# //################ static LPTSTR GetStringParam(KmlBlock* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam) { while (pBlock) { if (pBlock->eType == eBlock) { KmlLine* pLine = pBlock->pFirstLine; while (pLine) { if (pLine->eCommand == eCommand) { return (LPTSTR)pLine->nParam[nParam]; } pLine = pLine->pNext; } } pBlock = pBlock->pNext; } return NULL; } static DWORD GetIntegerParam(KmlBlock* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam) { while (pBlock) { if (pBlock->eType == eBlock) { KmlLine* pLine = pBlock->pFirstLine; while (pLine) { if (pLine->eCommand == eCommand) { return pLine->nParam[nParam]; } pLine = pLine->pNext; } } pBlock = pBlock->pNext; } return 0; } //################ //# //# Buttons //# //################ static INT iSqrt(INT nNumber) // integer y=sqrt(x) function { INT m, b = 0, t = nNumber; do { m = (b + t + 1) / 2; // median number if (m * m - nNumber > 0) // calculate x^2-y t = m; // adjust upper border else b = m; // adjust lower border } while(t - b > 1); return b; } static VOID AdjustPixel(UINT x, UINT y, BYTE byOffset) { COLORREF rgb; WORD wB, wG, wR; rgb = GetPixel(hWindowDC, x, y); // adjust color red wR = (((WORD) rgb) & 0x00FF) + byOffset; if (wR > 0xFF) wR = 0xFF; rgb >>= 8; // adjust color green wG = (((WORD) rgb) & 0x00FF) + byOffset; if (wG > 0xFF) wG = 0xFF; rgb >>= 8; // adjust color blue wB = (((WORD) rgb) & 0x00FF) + byOffset; if (wB > 0xFF) wB = 0xFF; SetPixel(hWindowDC, x, y, RGB(wR,wG,wB)); return; } // draw transparent circle with center coordinates and radius in pixel static __inline VOID TransparentCircle(UINT cx, UINT cy, UINT r) { #define HIGHADJ 0x80 // color incr. at center #define LOWADJ 0x08 // color incr. at border INT x, y; INT rr = r * r; // calculate r^2 // y-rows of circle for (y = 0; y < (INT) r; ++y) { INT yy = y * y; // calculate y^2 // x-columns of circle INT nXWidth = iSqrt(rr-yy); for (x = 0; x < nXWidth; ++x) { // color offset, sqrt(x*x+y*y) <= r !!! BYTE byOff = HIGHADJ - (BYTE) (iSqrt((x*x+yy) * (HIGHADJ-LOWADJ)*(HIGHADJ-LOWADJ) / rr)); AdjustPixel(cx+x, cy+y, byOff); if (x != 0) AdjustPixel(cx-x, cy+y, byOff); if (y != 0) AdjustPixel(cx+x, cy-y, byOff); if (x != 0 && y != 0) AdjustPixel(cx-x, cy-y, byOff); } } return; #undef HIGHADJ #undef LOWADJ } static VOID DrawButton(UINT nId) { UINT x0 = pButton[nId].nOx; UINT y0 = pButton[nId].nOy; EnterCriticalSection(&csGDILock); // solving NT GDI problems { switch (pButton[nId].nType) { case 0: // bitmap key if (pButton[nId].bDown) { BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, pButton[nId].nDx, pButton[nId].nDy, SRCCOPY); } else { // update background only BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); } break; case 1: // shift key to right down if (pButton[nId].bDown) { UINT x1 = x0+pButton[nId].nCx-1; UINT y1 = y0+pButton[nId].nCy-1; BitBlt(hWindowDC, x0+3,y0+3,pButton[nId].nCx-5,pButton[nId].nCy-5,hMainDC,x0+2,y0+2,SRCCOPY); SelectObject(hWindowDC, GetStockObject(BLACK_PEN)); MoveToEx(hWindowDC, x0, y0, NULL); LineTo(hWindowDC, x1, y0); MoveToEx(hWindowDC, x0, y0, NULL); LineTo(hWindowDC, x0, y1); SelectObject(hWindowDC, GetStockObject(WHITE_PEN)); MoveToEx(hWindowDC, x1, y0, NULL); LineTo(hWindowDC, x1, y1); MoveToEx(hWindowDC, x0, y1, NULL); LineTo(hWindowDC, x1+1, y1); } else { BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); } break; case 2: // do nothing break; case 3: // invert key color, even in display if (pButton[nId].bDown) { PatBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, DSTINVERT); } else { RECT Rect; Rect.left = x0 - nBackgroundX; Rect.top = y0 - nBackgroundY; Rect.right = Rect.left + pButton[nId].nCx; Rect.bottom = Rect.top + pButton[nId].nCy; InvalidateRect(hWnd, &Rect, FALSE); // call WM_PAINT for background and display redraw } break; case 4: // bitmap key, even in display if (pButton[nId].bDown) { // update background only BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); } else { RECT Rect; Rect.left = x0 - nBackgroundX; Rect.top = y0 - nBackgroundY; Rect.right = Rect.left + pButton[nId].nCx; Rect.bottom = Rect.top + pButton[nId].nCy; InvalidateRect(hWnd, &Rect, FALSE); // call WM_PAINT for background and display redraw } break; case 5: // transparent circle if (pButton[nId].bDown) { TransparentCircle(x0 + pButton[nId].nCx / 2, // x-center coordinate y0 + pButton[nId].nCy / 2, // y-center coordinate min(pButton[nId].nCx,pButton[nId].nCy) / 2); // radius } else { // update background only BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); } break; default: // black key, default drawing on illegal types if (pButton[nId].bDown) { PatBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, BLACKNESS); } else { // update background only BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); } } GdiFlush(); } LeaveCriticalSection(&csGDILock); return; } static VOID PressButton(UINT nId) { if (pButton[nId].bDown) return; // key already pressed -> exit pButton[nId].bDown = TRUE; DrawButton(nId); if (pButton[nId].nIn) { KeyboardEvent(TRUE,pButton[nId].nOut,pButton[nId].nIn); } else { KmlLine* pLine = pButton[nId].pOnDown; while ((pLine)&&(pLine->eCommand!=TOK_END)) { pLine = RunLine(pLine); } } return; } static VOID ReleaseButton(UINT nId) { pButton[nId].bDown = FALSE; DrawButton(nId); if (pButton[nId].nIn) { KeyboardEvent(FALSE,pButton[nId].nOut,pButton[nId].nIn); } else { KmlLine* pLine = pButton[nId].pOnUp; while ((pLine)&&(pLine->eCommand!=TOK_END)) { pLine = RunLine(pLine); } } return; } static VOID PressButtonById(UINT nId) { UINT i; for (i=0; iright > (LONG) (pButton[i].nOx) && rc->bottom > (LONG) (pButton[i].nOy) && rc->left <= (LONG) (pButton[i].nOx + pButton[i].nCx) && rc->top <= (LONG) (pButton[i].nOy + pButton[i].nCy)) { // on button type 3 and 5 clear complete key area before drawing if (pButton[i].nType == 3 || pButton[i].nType == 5) { UINT x0 = pButton[i].nOx; UINT y0 = pButton[i].nOy; EnterCriticalSection(&csGDILock); // solving NT GDI problems { BitBlt(hWindowDC, x0, y0, pButton[i].nCx, pButton[i].nCy, hMainDC, x0, y0, SRCCOPY); GdiFlush(); } LeaveCriticalSection(&csGDILock); } DrawButton(i); // redraw pressed button } } return; } //################ //# //# Annunciators //# //################ VOID DrawAnnunciator(UINT nId, BOOL bOn) { UINT nSx,nSy; --nId; // zero based ID if (nId >= ARRAYSIZEOF(pAnnunciator)) return; if (bOn) { nSx = pAnnunciator[nId].nDx; // position of annunciator nSy = pAnnunciator[nId].nDy; } else { nSx = pAnnunciator[nId].nOx; // position of background nSy = pAnnunciator[nId].nOy; } EnterCriticalSection(&csGDILock); // solving NT GDI problems { BitBlt(hWindowDC, pAnnunciator[nId].nOx, pAnnunciator[nId].nOy, pAnnunciator[nId].nCx, pAnnunciator[nId].nCy, hMainDC, nSx, nSy, SRCCOPY); GdiFlush(); } LeaveCriticalSection(&csGDILock); return; } //################ //# //# Mouse //# //################ static BOOL ClipButton(UINT x, UINT y, UINT nId) { x += nBackgroundX; // source display offset y += nBackgroundY; return (pButton[nId].nOx<=x) && (pButton[nId].nOy<=y) &&(x<(pButton[nId].nOx+pButton[nId].nCx)) &&(y<(pButton[nId].nOy+pButton[nId].nCy)); } VOID MouseButtonDownAt(UINT nFlags, DWORD x, DWORD y) { UINT i; for (i=0; i quit if ((bPressed) && !(ClipButton(x,y,uLastPressedKey))) // not on last pressed key ReleaseAllButtons(); // release all buttons if (!bClicking) return; // normal emulation key -> quit if (pButton[uButtonClicked].dwFlags&BUTTON_NOHOLD) { if (ClipButton(x,y, uButtonClicked) != pButton[uButtonClicked].bDown) { pButton[uButtonClicked].bDown = !pButton[uButtonClicked].bDown; DrawButton(uButtonClicked); } return; } if (pButton[uButtonClicked].dwFlags&BUTTON_VIRTUAL) { if (!ClipButton(x,y, uButtonClicked)) { ReleaseButton(uButtonClicked); bClicking = FALSE; uButtonClicked = 0; } return; } return; } //################ //# //# Keyboard //# //################ VOID RunKey(BYTE nId, BOOL bPressed) { if (pVKey[nId]) { KmlLine* pLine = pVKey[nId]->pFirstLine; byVKeyMap[nId] = bPressed; while (pLine) pLine = RunLine(pLine); } else { if (bDebug&&bPressed) { TCHAR szTemp[128]; wsprintf(szTemp,_T("Scancode %i"),nId); InfoMessage(szTemp); } } return; } //################ //# //# Macro player //# //################ VOID PlayKey(UINT nOut, UINT nIn, BOOL bPressed) { // scan from last buttons because LCD buttons mostly defined first INT i = nButtons; while (--i >= 0) { if (pButton[i].nOut == nOut && pButton[i].nIn == nIn) { if (bPressed) PressButton(i); else ReleaseButton(i); return; } } return; } //################ //# //# Load and Initialize Script //# //################ static KmlBlock* LoadKMLGlobal(LPCTSTR szFilename) { HANDLE hFile; LPTSTR lpBuf; KmlBlock* pBlock; DWORD eToken; SetCurrentDirectory(szEmuDirectory); hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); SetCurrentDirectory(szCurrentDirectory); if (hFile == INVALID_HANDLE_VALUE) return NULL; if ((lpBuf = MapKMLFile(hFile)) == NULL) return NULL; InitLex(lpBuf); pBlock = NULL; while ((eToken = Lex(LEX_BLOCK)) != TOK_NONE) { if (eToken == TOK_GLOBAL) { pBlock = ParseBlock(eToken); if (pBlock) pBlock->pNext = NULL; break; } } CleanLex(); ClearLog(); HeapFree(hHeap,0,lpBuf); return pBlock; } BOOL InitKML(LPCTSTR szFilename, BOOL bNoLog) { HANDLE hFile; LPTSTR lpBuf; KmlBlock* pBlock; BOOL bOk = FALSE; KillKML(); nBlocksIncludeLevel = 0; PrintfToLog(_T("Reading %s"), szFilename); SetCurrentDirectory(szEmuDirectory); hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); SetCurrentDirectory(szCurrentDirectory); if (hFile == INVALID_HANDLE_VALUE) { AddToLog(_T("Error while opening the file.")); goto quit; } if ((lpBuf = MapKMLFile(hFile)) == NULL) goto quit; InitLex(lpBuf); pKml = ParseBlocks(); CleanLex(); HeapFree(hHeap,0,lpBuf); if (pKml == NULL) goto quit; pBlock = pKml; while (pBlock) { switch (pBlock->eType) { case TOK_BUTTON: InitButton(pBlock); break; case TOK_SCANCODE: nScancodes++; pVKey[pBlock->nId] = pBlock; break; case TOK_ANNUNCIATOR: InitAnnunciator(pBlock); break; case TOK_GLOBAL: InitGlobal(pBlock); break; case TOK_LCD: InitLcd(pBlock); break; case TOK_BACKGROUND: InitBackground(pBlock); break; default: PrintfToLog(_T("Block %s Ignored."), GetStringOf(pBlock->eType)); pBlock = pBlock->pNext; } pBlock = pBlock->pNext; } if (!isModelValid(cCurrentRomType)) { AddToLog(_T("This KML Script doesn't specify a valid model.")); goto quit; } if (pbyRom == NULL) { AddToLog(_T("This KML Script doesn't specify the ROM to use, or the ROM could not be loaded.")); goto quit; } if (hMainDC == NULL) { AddToLog(_T("This KML Script doesn't specify the background bitmap, or bitmap could not be loaded.")); goto quit; } CreateLcdBitmap(); PrintfToLog(_T("%i Buttons Defined"), nButtons); PrintfToLog(_T("%i Scancodes Defined"), nScancodes); PrintfToLog(_T("%i Annunciators Defined"), nAnnunciators); bOk = TRUE; quit: if (bOk) { // HP38G/HP39G/HP40G have no object loading, ignore DragAcceptFiles(hWnd,cCurrentRomType != '6' && cCurrentRomType != 'A' && cCurrentRomType != 'E'); if (!bNoLog) { AddToLog(_T("Press Ok to Continue.")); if (bAlwaysDisplayLog&&(!DisplayKMLLog(bOk))) { KillKML(); return FALSE; } } } else { AddToLog(_T("Press Cancel to Abort.")); if (!DisplayKMLLog(bOk)) { KillKML(); return FALSE; } } ResizeWindow(); ClearLog(); return bOk; }