#include #define MIDIMSG(stat , data1 , data2) (DWORD)(stat | (data1 << 8) | (data2 << 16)) // キーの状態 #define KEYST_D 1 #define KEYST_U 2 // 鍵のいろ #define COL_W 1 #define COL_B 2 // ボタンID #define BTN_ID0 0 #define BTN_ID1 1 #define BTN_ID2 2 #define BTN_ID3 3 #define BTN_ID4 4 #define BTN_ID5 5 #define BTN_ID6 6 #define BTN_ID7 7 using namespace std; // 以下データの作成 int retcrgn(int i); HRGN rethrgn(int i); char temp[] = {'a','w','s','d','r','f','t','g','h','u', // ←構造体初期化用 'j','i','k','o','l',';','@',':','[',']'}; struct KEYINFO{ int stat;// きーの状態 PTSTR ch; // キーの文字(tempのどれか WPARAM vkeycode; // 仮想キーコード HRGN hrgn; // 割り当てられているリージョンのハンドル int crgn; // リージョンの色 上のdefine節を参照 int usechan; // 割り当てられているチャンネル(0〜15) int usescale; // 鳴らしている音階 KEYINFO::KEYINFO(){ //構造体初期化 static int count=0; stat = KEYST_U; ch = (PTSTR)temp[count]; // 文字と対応 vkeycode = 0x07; crgn = retcrgn(count); // 鍵の色 count++; } }keyinfo[20]; LRESULT CALLBACK WindowProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) { HDC hdc; HBRUSH hbrush; PAINTSTRUCT ps; LPTSTR lptstr=" "; static HMIDIOUT hmidi; static WPARAM vkctemp; // 仮想キーコードを一時格納 static top=0; // 次使うべきチャンネル(0〜15) static vol=30; // ボリューム(0〜120) static sound=0; // 音色(0〜127) static trans=0; // 移調 static bool set=false; // 初期処理(リージョン生成)が終わっていれば真 switch(msg){ case WM_CREATE: midiOutOpen(&hmidi, MIDIMAPPER, 0,0,0); return 0; case WM_DESTROY: midiOutReset(hmidi); midiOutClose(hmidi); PostQuitMessage(0); return 0; case WM_KILLFOCUS: midiOutReset(hmidi); for(int i=0; i<20; i++){ keyinfo[i].stat = KEYST_U; } case WM_KEYDOWN: // キーが押された vkctemp = wp; return 0; case WM_KEYUP: // キーが離された for(int i=0; i<20; i++){ if(wp==keyinfo[i].vkeycode){ // 一致するきーがあれば top--; keyinfo[i].stat = KEYST_U; if(keyinfo[i].usechan<16) midiOutShortMsg(hmidi,MIDIMSG((144+keyinfo[i].usechan), (keyinfo[i].usescale),0)); InvalidateRgn(hwnd, keyinfo[i].hrgn, TRUE); // 書き直し } } return 0; case WM_CHAR: for(int i=0; i<20; i++){ // 全てを見ていく if((PTSTR)LOWORD(wp)==keyinfo[i].ch){ // 一致すれば if(keyinfo[i].stat==KEYST_D) return 0; if(top<16) midiOutShortMsg(hmidi,MIDIMSG(144+top,(45+i+trans),vol)); keyinfo[i].usechan = top; // 以下報告 keyinfo[i].vkeycode = vkctemp; keyinfo[i].stat = KEYST_D; keyinfo[i].usescale = 45+i+trans; top++; // 以下は描画 hdc = GetDC(hwnd); hbrush = CreateSolidBrush(RGB(0xcc,0x66,0x66)); FillRgn(hdc, keyinfo[i].hrgn, hbrush); DeleteObject(hbrush); ReleaseDC(hwnd, hdc); } } return 0; case WM_COMMAND: switch(LOWORD(wp)){ case BTN_ID0: if(vol) vol-=10; break; case BTN_ID1: if(vol<120) vol+=10; break; case BTN_ID2: if(sound) sound--; for(int i=0; i<16; i++){ midiOutShortMsg(hmidi,MIDIMSG(192+i,sound,0)); } break; case BTN_ID3: if(sound<127) sound++; for(int i=0; i<16; i++){ midiOutShortMsg(hmidi,MIDIMSG(192+i,sound,0)); } break; case BTN_ID4: if(sound<=10) sound = 0; else sound -=10; for(int i=0; i<16; i++){ midiOutShortMsg(hmidi,MIDIMSG(192+i,sound,0)); } break; case BTN_ID5: if(sound>=117) sound = 127; else sound +=10; for(int i=0; i<16; i++){ midiOutShortMsg(hmidi,MIDIMSG(192+i,sound,0)); } break; case BTN_ID6: if(trans<20) trans++; break; case BTN_ID7: if(trans>(-20)) trans--; break; } InvalidateRect(hwnd, NULL, TRUE); SetFocus(hwnd); return 0; case WM_PAINT: if(!set){ for(int i=0; i<20; i++){ keyinfo[i].hrgn = rethrgn(i); set=true; } } hdc = BeginPaint(hwnd, &ps); // とりあえず鍵盤描く for(int i=0; i<20; i++){ if(keyinfo[i].crgn==COL_W) FrameRgn(hdc, keyinfo[i].hrgn, (HBRUSH)GetStockObject(BLACK_BRUSH),1,1); else FillRgn(hdc, keyinfo[i].hrgn, (HBRUSH)GetStockObject(BLACK_BRUSH)); } wsprintf(lptstr, "VOL : %d\0", vol); TextOut(hdc, 500, 15, lptstr, lstrlen(lptstr)); wsprintf(lptstr, "sound no.%d\0", sound); TextOut(hdc, 490, 80, lptstr, lstrlen(lptstr)); wsprintf(lptstr, "TP:%d\0", trans); TextOut(hdc, 593, 85, lptstr, lstrlen(lptstr)); EndPaint(hwnd, &ps); return 0; } return DefWindowProc(hwnd, msg, wp, lp); } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) { HWND hwnd; WNDCLASS wndc; MSG msg; wndc.style = CS_HREDRAW | CS_VREDRAW; wndc.lpfnWndProc = WindowProc; wndc.cbClsExtra = wndc.cbWndExtra = 0; wndc.hInstance = hInstance; wndc.hIcon = LoadIcon(NULL, IDI_WINLOGO); wndc.hCursor = LoadCursor(NULL, IDC_ARROW); wndc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndc.lpszMenuName = NULL; wndc.lpszClassName = TEXT("wndc"); if(!RegisterClass(&wndc)) return 0; hwnd = CreateWindow(TEXT("wndc"), TEXT("KeyUtil"), WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 650, 185, NULL, NULL, hInstance, NULL); if(!hwnd) return 0; CreateWindow(TEXT("BUTTON"), TEXT("VOL-"), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 485, 38, 50, 30, hwnd, (HMENU)BTN_ID0, hInstance, NULL); CreateWindow(TEXT("BUTTON"), TEXT("VOL+"), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 540, 38, 50, 30, hwnd, (HMENU)BTN_ID1, hInstance, NULL); CreateWindow(TEXT("BUTTON"), TEXT("←"), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 485, 102, 50, 25, hwnd, (HMENU)BTN_ID2, hInstance, NULL); CreateWindow(TEXT("BUTTON"), TEXT("→"), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 540, 102, 50, 25, hwnd, (HMENU)BTN_ID3, hInstance, NULL); CreateWindow(TEXT("BUTTON"), TEXT("<<"), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 485, 126, 50, 25, hwnd, (HMENU)BTN_ID4, hInstance, NULL); CreateWindow(TEXT("BUTTON"), TEXT(">>"), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 540, 126, 50, 25, hwnd, (HMENU)BTN_ID5, hInstance, NULL); CreateWindow(TEXT("BUTTON"), TEXT("#"), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 595, 38, 40, 40, hwnd, (HMENU)BTN_ID6, hInstance, NULL); CreateWindow(TEXT("BUTTON"), TEXT("♭"), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 595, 110, 40, 40, hwnd, (HMENU)BTN_ID7, hInstance, NULL); while (GetMessage(&msg, NULL, 0, 0)){ DispatchMessage(&msg); TranslateMessage(&msg); } return msg.wParam; } // 以下は初期処理用ルーチン int retcrgn(int i){ // 番号を受け取り色を返す if(i==0||i==2||i==3||i==5||i==7||i==8||i==10||i==12||i==14||i==15||i==17||i==19) return COL_W; else return COL_B; } struct USEPOINT{ // 色々(ざひょうとか)作業用 POINT *pp; // 現在作業対象座標構造体 int Countp; // 添え字っぽいやつ void p(POINT *po){ pp = po; Countp = 0; } // ちょっと補助用 void p(int z,int w){ pp[Countp].x=z; pp[Countp].y=w; Countp++; } //同上 USEPOINT(){ pp=NULL; Countp=0; } // コンストラクタ }p; HRGN rethrgn(int i){// 番号を受け取りリージョン生成、ハンドルを返す POINT po[8]; switch(i){ case 0: p.p(po); p.p(0,0); p.p(0,150); p.p(40,150); p.p(40,90); p.p(30,90); p.p(30,0); return CreatePolygonRgn(po, 6, WINDING); case 1: p.p(po); p.p(30,0); p.p(30,90); p.p(50,90); p.p(50,0); return CreatePolygonRgn(po, 4, WINDING); case 2: p.p(po); p.p(50,0); p.p(50,90); p.p(40,90); p.p(40,150); p.p(80,150); p.p(80,0); return CreatePolygonRgn(po, 6, WINDING); case 3: p.p(po); p.p(80,0); p.p(80,150); p.p(120,150); p.p(120,90); p.p(110,90); p.p(110,0); return CreatePolygonRgn(po, 6, WINDING); case 4: p.p(po); p.p(110,0); p.p(110,90); p.p(130,90); p.p(130,0); return CreatePolygonRgn(po, 4, WINDING); case 5: p.p(po); p.p(130,0); p.p(130,90); p.p(120,90); p.p(120,150); p.p(160,150); p.p(160,90); p.p(150,90); p.p(150,0); return CreatePolygonRgn(po, 8, WINDING); case 6: p.p(po); p.p(150,0); p.p(150,90); p.p(170,90); p.p(170,0); return CreatePolygonRgn(po, 4, WINDING); case 7: p.p(po); p.p(170,0); p.p(170,90); p.p(160,90); p.p(160,150); p.p(200,150); p.p(200,0); return CreatePolygonRgn(po, 6, WINDING); case 8: p.p(po); p.p(200,0); p.p(200,150); p.p(240,150); p.p(240,90); p.p(230,90); p.p(230,0); return CreatePolygonRgn(po, 6, WINDING); case 9: p.p(po); p.p(230,0); p.p(230,90); p.p(250,90); p.p(250,0); return CreatePolygonRgn(po, 4, WINDING); case 10:p.p(po); p.p(250,0); p.p(250,90); p.p(240,90); p.p(240,150); p.p(280,150); p.p(280,90); p.p(270,90); p.p(270,0); return CreatePolygonRgn(po, 8, WINDING); case 11:p.p(po); p.p(270,0); p.p(270,90); p.p(290,90); p.p(290,0); return CreatePolygonRgn(po, 4, WINDING); case 12:p.p(po); p.p(290,0); p.p(290,90); p.p(280,90); p.p(280,150); p.p(320,150); p.p(320,90); p.p(310,90); p.p(310,0); return CreatePolygonRgn(po, 8, WINDING); case 13:p.p(po); p.p(310,0); p.p(310,90); p.p(330,90); p.p(330,0); return CreatePolygonRgn(po, 4, WINDING); case 14:p.p(po); p.p(330,0); p.p(330,90); p.p(320,90); p.p(320,150); p.p(360,150); p.p(360,0); return CreatePolygonRgn(po, 6, WINDING); case 15:p.p(po); p.p(360,0); p.p(360,150); p.p(400,150); p.p(400,90); p.p(390,90); p.p(390,0); return CreatePolygonRgn(po, 6, WINDING); case 16:p.p(po); p.p(390,0); p.p(390,90); p.p(410,90); p.p(410,0); return CreatePolygonRgn(po, 4, WINDING); case 17:p.p(po); p.p(410,0); p.p(410,90); p.p(400,90); p.p(400,150); p.p(440,150); p.p(440,90); p.p(430,90); p.p(430,0); return CreatePolygonRgn(po, 8, WINDING); case 18:p.p(po); p.p(430,0); p.p(430,90); p.p(450,90); p.p(450,0); return CreatePolygonRgn(po, 4, WINDING); case 19:p.p(po); p.p(450,0); p.p(450,90); p.p(440,90); p.p(440,150); p.p(480,150); p.p(480,0); return CreatePolygonRgn(po, 6, WINDING); default: return NULL; } }