// wonbe Win32 text emulation /* First Created: Nov.4,2000 by Pie Dey Co.,Ltd. */ /* This source code is distributed under GNU General Public License (GPL) */ /* see http://www.gnu.org/ about GPL */ #include #include #include "win32text.h" #define SCREEN_SIZE_X (224/8) #define SCREEN_SIZE_Y (144/8) static WORD screen[SCREEN_SIZE_X][SCREEN_SIZE_Y]; //static WORD lastChar; static UINT lastVKey; static HWND hwnd; static void wmPaint( HWND hWnd, HDC hdc ) { int x,y; int xArea, yArea; RECT rect, rectDraw; TEXTMETRIC tm; GetClientRect( hWnd, &rect ); SelectObject( hdc, GetStockObject( SYSTEM_FIXED_FONT ) ); GetTextMetrics( hdc, &tm ); xArea = SCREEN_SIZE_X * tm.tmMaxCharWidth; yArea = SCREEN_SIZE_Y * tm.tmHeight; rectDraw.left = (rect.right-rect.left)/2-xArea/2; rectDraw.top = (rect.bottom-rect.top)/2-yArea/2; rectDraw.right = (rect.right-rect.left)/2+xArea/2; rectDraw.bottom = (rect.bottom-rect.top)/2+yArea/2; FillRect( hdc, &rect, GetStockObject(GRAY_BRUSH) ); FillRect( hdc, &rectDraw, GetStockObject(WHITE_BRUSH) ); for( y=0; y= 0x100 ) { str[0] = (val >> 8); str[1] = (val & 0xff); TextOut( hdc, rectDraw.left+x*tm.tmMaxCharWidth, rectDraw.top+y*tm.tmHeight, str, 2 ); } else { static char table[] = " !”#$%&’()*+,−./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[¥]^_`abcdefghijklmnopqrstuvwxyz{|} ̄"; if( val >= 0x20 && val <= 0x7e ) { TextOut( hdc, rectDraw.left+x*tm.tmMaxCharWidth, rectDraw.top+y*tm.tmHeight, &table[(val-0x20)*2], 2 ); } else { str[0] = (BYTE)val; TextOut( hdc, rectDraw.left+x*tm.tmMaxCharWidth, rectDraw.top+y*tm.tmHeight, str, 1 ); } } } } } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); wmPaint(hWnd,hdc); EndPaint(hWnd, &ps); break; case WM_KEYDOWN: lastVKey = (WORD)wParam; break; //case WM_CHAR: // lastChar = (WORD)wParam; // break; case WM_CLOSE: return 0; // 閉じちゃ駄目 case WM_DESTROY: hwnd = NULL; PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, message, wParam, lParam)); } return (0); } static int createTextInThread() { WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetModuleHandle(NULL); wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; wc.lpszClassName = "wonbe_win32text"; RegisterClass(&wc); hwnd = CreateWindow(wc.lpszClassName, "WONBE TEXT", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, SCREEN_SIZE_X*16+64, SCREEN_SIZE_Y*20+64, NULL, NULL, wc.hInstance, NULL); if( !hwnd ) return FALSE; clearText(); ShowWindow( hwnd, SW_SHOW ); UpdateWindow( hwnd ); return TRUE; } void clearText() { int x,y; if( hwnd == NULL ) return; for( y=0; y= SCREEN_SIZE_X ) return; if( y >= SCREEN_SIZE_Y ) return; screen[x][y] = ch; InvalidateRect( hwnd, NULL, FALSE ); } void updateText() { UpdateWindow( hwnd ); } void deleteText() { if( hwnd == NULL ) return; DestroyWindow( hwnd ); hwnd = NULL; } DWORD WINAPI ThreadFunc( LPVOID lpParam ) { MSG msg; createTextInThread(); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } int createText() { DWORD dwThreadId, dwThrdParam = 1; HANDLE hThread; //lastChar = 0; lastVKey = 0; hThread = CreateThread( NULL, // no security attributes 0, // use default stack size ThreadFunc, // thread function &dwThrdParam, // argument to thread function 0, // use default creation flags &dwThreadId); // returns the thread identifier return TRUE; } unsigned short win32_wait() { UINT t; while( TRUE ) { // 以下の2行は本当はマルチスレッド的にNGなんだけど // テスト用環境だから大目に見る t = lastVKey; lastVKey = 0; switch( t ) { case 'P': return 0x02; // START BUTTON case VK_SPACE: return 0x04; //KEYWORD_SCAN_A; case VK_ESCAPE: return 0x08; //KEYWORD_SCAN_B; case VK_UP: case 'E': return 0x10; //KEYWORD_SCAN_X1; case VK_RIGHT: case 'D': return 0x20; //KEYWORD_SCAN_X2; case VK_DOWN: case 'X': return 0x40; //KEYWORD_SCAN_X3; case VK_LEFT: case 'S': return 0x80; //KEYWORD_SCAN_X4; case 'T': return 0x100; //KEYWORD_SCAN_Y1; case 'G': return 0x200; //KEYWORD_SCAN_Y2; case 'V': return 0x400; //KEYWORD_SCAN_Y3; case 'F': return 0x800; //KEYWORD_SCAN_Y4; } Sleep( 100 ); } } unsigned short win32_scan() { WORD t; t = 0; if( GetAsyncKeyState('P') & 0x8000 ) { t |= 0x02; // START } if( GetAsyncKeyState(VK_SPACE) & 0x8000 ) { t |= 0x04; // A } if( GetAsyncKeyState(VK_ESCAPE) & 0x8000 ) { t |= 0x08; // B } if( GetAsyncKeyState('E') & 0x8000 ) { t |= 0x10; // X1 } if( GetAsyncKeyState('D') & 0x8000 ) { t |= 0x20; // X2 } if( GetAsyncKeyState('X') & 0x8000 ) { t |= 0x40; // X3 } if( GetAsyncKeyState('S') & 0x8000 ) { t |= 0x80; // X4 } if( GetAsyncKeyState('T') & 0x8000 ) { t |= 0x100; // Y1 } if( GetAsyncKeyState('G') & 0x8000 ) { t |= 0x200; // Y2 } if( GetAsyncKeyState('V') & 0x8000 ) { t |= 0x400; // Y3 } if( GetAsyncKeyState('F') & 0x8000 ) { t |= 0x800; // Y4 } return t; } unsigned int win32_get_tick_count() { return GetTickCount()/10; } void win32_sys_wait( unsigned int val ) { Sleep( val*10 ); } static BOOL bPlayingMIDI = FALSE; static UINT wDeviceID; DWORD stopMIDIFile(HWND hwnd) { if( bPlayingMIDI ) { mciSendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, (DWORD)NULL); bPlayingMIDI = FALSE; } return 0; } DWORD playMIDIFile(HWND hWndNotify, LPSTR lpszMIDIFileName) { DWORD dwReturn; MCI_OPEN_PARMS mciOpenParms; MCI_PLAY_PARMS mciPlayParms; MCI_STATUS_PARMS mciStatusParms; //MCI_SEQ_SET_PARMS mciSeqSetParms; // Open the device by specifying the device and filename. // MCI will attempt to choose the MIDI mapper as the output port. mciOpenParms.lpstrDeviceType = "sequencer"; mciOpenParms.lpstrElementName = lpszMIDIFileName; if (dwReturn = mciSendCommand((MCIDEVICEID)NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD)(LPVOID) &mciOpenParms)) { // Failed to open device. Don't close it; just return error. return (dwReturn); } // The device opened successfully; get the device ID. wDeviceID = mciOpenParms.wDeviceID; bPlayingMIDI = TRUE; // Check if the output port is the MIDI mapper. mciStatusParms.dwItem = MCI_SEQ_STATUS_PORT; if (dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD)(LPVOID) &mciStatusParms)) { mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD)NULL); return (dwReturn); } // The output port is not the MIDI mapper. // Ask if the user wants to continue. if (LOWORD(mciStatusParms.dwReturn) != MIDI_MAPPER) { //printf("Warning: The MIDI mapper is not available.\n"); } // Begin playback. The window procedure function for the parent // window will be notified with an MM_MCINOTIFY message when // playback is complete. At this time, the window procedure closes // the device. mciPlayParms.dwCallback = (DWORD) hWndNotify; if (dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms)) { mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD)NULL); return (dwReturn); } return (0L); } // "テキスト音楽「サクラ」"に含まれるdsakura.dllを用いてMMLを再生します // サクラは以下より入手できます http://www.text2music.com/ // dsakura.dllが無ければ音が出ないだけで、エラーにはなりません。 void win32_play_mml( const char * mml ) { static BOOL initialized = FALSE; static HMODULE hmod = NULL; static FARPROC pMMLtoMIDI = NULL; if( !initialized ) { HMODULE hmod = LoadLibrary("dsakura"); if( hmod != NULL ) { pMMLtoMIDI = GetProcAddress( hmod, "MMLtoMIDI" ); } else { printf("LoadLibrary(\"dsakura\") failed\n"); } initialized = TRUE; } if( pMMLtoMIDI != NULL ) { char errmsg[256]; BOOL b; stopMIDIFile(hwnd); b = (*pMMLtoMIDI)(mml,"$$$.mid",errmsg); if( b == FALSE ) { printf("dsakura: %s\n",errmsg); } playMIDIFile(hwnd, "$$$.mid"); } else { printf("play: %s\n", mml ); } } // end of win32text.c