From 282f8bb7c8f11db4cdaab67a4d4206d349056d9d Mon Sep 17 00:00:00 2001 From: Quantum Date: Mon, 9 Sep 2013 18:14:14 -0400 Subject: [PATCH] Added mouse support. --- include/MainWindow.hpp | 1 + include/PianoControl.hpp | 7 ++++ src/MainWindow.cpp | 35 +++++++++++++++- src/PianoControl.cpp | 87 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 126 insertions(+), 4 deletions(-) diff --git a/include/MainWindow.hpp b/include/MainWindow.hpp index 5a23d35..6f04ebc 100644 --- a/include/MainWindow.hpp +++ b/include/MainWindow.hpp @@ -13,6 +13,7 @@ class MainWindow : public Window { public: virtual LPCTSTR ClassName() { return TEXT("MusicKeyboardMain"); } static MainWindow *Create(LPCTSTR szTitle); + void PlayNote(int note, bool down); protected: LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT OnCreate(); diff --git a/include/PianoControl.hpp b/include/PianoControl.hpp index 075b099..94c6c62 100644 --- a/include/PianoControl.hpp +++ b/include/PianoControl.hpp @@ -16,6 +16,8 @@ #define MPCM_SETKEYTEXT (WM_USER + 5) #define MPCM_GETBACKGROUND (WM_USER + 6) #define MPCM_SETBACKGROUND (WM_USER + 7) +#define MMWM_TURNNOTE (WM_APP + 0) +#define MMWM_NOTEID (WM_APP + 1) class PianoControl : public Window { public: @@ -48,12 +50,14 @@ protected: BOOL WinRegisterClass(WNDCLASS *pwc); virtual int keyIDToInternal(int id, bool &black); + virtual int internalToKeyID(int id, bool black); virtual bool haveBlackToLeft(int id); virtual bool haveBlackToRight(int id); int haveBlack(int id) { return (haveBlackToLeft(id) ? 2 : 0) | (haveBlackToRight(id) ? 1 : 0); } virtual void UpdateKey(int key, bool black); + virtual int hitTest(int x, int y, bool &black); bool *blackStatus; bool *whiteStatus; @@ -68,6 +72,9 @@ protected: HBITMAP hMemBitmap; HBRUSH hBackground; int bmx, bmy; + + bool mouseDown; + int lastNote, lastKey; }; #endif diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 8677b27..a9d27cb 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -264,6 +264,13 @@ bool MainWindow::Play(WPARAM wParam, LPARAM lParam, bool down) return false; note = GetMIDINote(wCode); + PlayNote(note, down); + piano->SetKeyStatus((note - 6) % 24, down); + return true; +} + +void MainWindow::PlayNote(int note, bool down) +{ if (down) { int num = note % 24; while (num < 0x7F) { @@ -276,8 +283,6 @@ bool MainWindow::Play(WPARAM wParam, LPARAM lParam, bool down) MIDI_MESSAGE(m_midi, 0x90, note, m_force); else MIDI_MESSAGE(m_midi, 0x90, note, 0); - piano->SetKeyStatus((note - 6) % 24, down); - return true; } LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) @@ -392,6 +397,32 @@ LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_EXITSIZEMOVE: SetWindowLongPtr(m_hwnd, GWL_EXSTYLE, GetWindowLongPtr(m_hwnd, GWL_EXSTYLE) & ~WS_EX_COMPOSITED); return 0; + case MMWM_NOTEID: { + int state = 0; + if (GetKeyState(VK_CONTROL) < 0) + state |= 0x001; + if (GetKeyState(VK_SHIFT) < 0) + state |= 0x010; + if (GetKeyState(VK_MENU) < 0) + state |= 0x100; + + int note = wParam + 54; + switch (state) { + case 0x001: + note -= 24; + break; + case 0x010: + note += 24; + break; + case 0x100: + note += 48; + break; + } + return note; + } + case MMWM_TURNNOTE: + PlayNote((int) wParam, lParam != 0); + return 0; } return Window::HandleMessage(uMsg, wParam, lParam); } diff --git a/src/PianoControl.cpp b/src/PianoControl.cpp index 01e2c64..0a1b0de 100644 --- a/src/PianoControl.cpp +++ b/src/PianoControl.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -30,6 +31,8 @@ LRESULT PianoControl::OnCreate() blackStatus = whiteStatus = NULL; blackText = whiteText = NULL; + mouseDown = false; + lastNote = lastKey = 0; SetOctaves(2); return 0; @@ -171,6 +174,16 @@ int PianoControl::keyIDToInternal(int id, bool &black) { return id / 12 * 7 + ret; } +static int internalToKeyIDMap[7] = {1, 3, 5, 6, 8, 10, 11}; + +int PianoControl::internalToKeyID(int id, bool black) +{ + id = id / 7 * 12 + internalToKeyIDMap[id % 7]; + if (black) + --id; + return id; +} + bool PianoControl::haveBlackToLeft(int i) { switch (i % 7) { case 0: // G @@ -206,6 +219,43 @@ bool PianoControl::haveBlackToRight(int i) { return false; // not reached } +int PianoControl::hitTest(int x, int y, bool &black) +{ + RECT client; + int width, height; + int wwidth, bwidth, bheight, hbwidth; + + GetClientRect(m_hwnd, &client); + width = client.right - client.left; + height = client.bottom - client.top; + wwidth = width / 7 / octaves; // Displaying 14 buttons. + bwidth = width / 12 / octaves; // smaller + bheight = height / 2; + bheight = height / 2; + hbwidth = bwidth / 2; + + int key = x / wwidth; + int dx = x % wwidth; + + if (y < bheight && (dx < hbwidth || dx > (wwidth - hbwidth))) { + int temp = key; + if (dx >= hbwidth) + ++temp; + switch (temp % 7) { + case 0: + case 1: + case 2: + case 4: + case 5: + black = true; + return temp; + } + } + + black = false; + return key; +} + void PianoControl::PaintContent(PAINTSTRUCT *pps) { RECT client, rect; @@ -459,8 +509,41 @@ LRESULT PianoControl::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_SIZE: InvalidateRect(m_hwnd, NULL, TRUE); return 0; - case WM_LBUTTONDOWN: - SetFocus(hwParent); + case WM_LBUTTONDOWN: { + /*if (mouseDown) + return 0;*/ + bool black; + int internal = hitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), black); + int key = internalToKeyID(internal, black); + int external = SendMessage(hwParent, MMWM_NOTEID, key, 0); + SendMessage(hwParent, MMWM_TURNNOTE, external, 1); + SetKeyStatus(key, true); + lastNote = external; + lastKey = key; + mouseDown = true; + return 0; + } + case WM_LBUTTONUP: { + SendMessage(hwParent, MMWM_TURNNOTE, lastNote, 0); + SetKeyStatus(lastKey, false); + mouseDown = false; + return 0; + } + case WM_MOUSEMOVE: + if (mouseDown) { + bool black; + int internal = hitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), black); + int key = internalToKeyID(internal, black); + int external = SendMessage(hwParent, MMWM_NOTEID, key, 0); + if (lastNote != external) { + SendMessage(hwParent, MMWM_TURNNOTE, lastNote, 0); + SetKeyStatus(lastKey, false); + SendMessage(hwParent, MMWM_TURNNOTE, external, 1); + SetKeyStatus(key, true); + lastNote = external; + lastKey = key; + } + } return 0; case WM_KEYDOWN: case WM_SYSKEYDOWN: