mirror of
https://github.com/quantum5/MusicKeyboard.git
synced 2025-04-24 21:21:59 -04:00
Added mouse support.
This commit is contained in:
parent
f100921c57
commit
282f8bb7c8
|
@ -13,6 +13,7 @@ class MainWindow : public Window {
|
||||||
public:
|
public:
|
||||||
virtual LPCTSTR ClassName() { return TEXT("MusicKeyboardMain"); }
|
virtual LPCTSTR ClassName() { return TEXT("MusicKeyboardMain"); }
|
||||||
static MainWindow *Create(LPCTSTR szTitle);
|
static MainWindow *Create(LPCTSTR szTitle);
|
||||||
|
void PlayNote(int note, bool down);
|
||||||
protected:
|
protected:
|
||||||
LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
LRESULT OnCreate();
|
LRESULT OnCreate();
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#define MPCM_SETKEYTEXT (WM_USER + 5)
|
#define MPCM_SETKEYTEXT (WM_USER + 5)
|
||||||
#define MPCM_GETBACKGROUND (WM_USER + 6)
|
#define MPCM_GETBACKGROUND (WM_USER + 6)
|
||||||
#define MPCM_SETBACKGROUND (WM_USER + 7)
|
#define MPCM_SETBACKGROUND (WM_USER + 7)
|
||||||
|
#define MMWM_TURNNOTE (WM_APP + 0)
|
||||||
|
#define MMWM_NOTEID (WM_APP + 1)
|
||||||
|
|
||||||
class PianoControl : public Window {
|
class PianoControl : public Window {
|
||||||
public:
|
public:
|
||||||
|
@ -48,12 +50,14 @@ protected:
|
||||||
BOOL WinRegisterClass(WNDCLASS *pwc);
|
BOOL WinRegisterClass(WNDCLASS *pwc);
|
||||||
|
|
||||||
virtual int keyIDToInternal(int id, bool &black);
|
virtual int keyIDToInternal(int id, bool &black);
|
||||||
|
virtual int internalToKeyID(int id, bool black);
|
||||||
virtual bool haveBlackToLeft(int id);
|
virtual bool haveBlackToLeft(int id);
|
||||||
virtual bool haveBlackToRight(int id);
|
virtual bool haveBlackToRight(int id);
|
||||||
int haveBlack(int id) {
|
int haveBlack(int id) {
|
||||||
return (haveBlackToLeft(id) ? 2 : 0) | (haveBlackToRight(id) ? 1 : 0);
|
return (haveBlackToLeft(id) ? 2 : 0) | (haveBlackToRight(id) ? 1 : 0);
|
||||||
}
|
}
|
||||||
virtual void UpdateKey(int key, bool black);
|
virtual void UpdateKey(int key, bool black);
|
||||||
|
virtual int hitTest(int x, int y, bool &black);
|
||||||
|
|
||||||
bool *blackStatus;
|
bool *blackStatus;
|
||||||
bool *whiteStatus;
|
bool *whiteStatus;
|
||||||
|
@ -68,6 +72,9 @@ protected:
|
||||||
HBITMAP hMemBitmap;
|
HBITMAP hMemBitmap;
|
||||||
HBRUSH hBackground;
|
HBRUSH hBackground;
|
||||||
int bmx, bmy;
|
int bmx, bmy;
|
||||||
|
|
||||||
|
bool mouseDown;
|
||||||
|
int lastNote, lastKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -264,6 +264,13 @@ bool MainWindow::Play(WPARAM wParam, LPARAM lParam, bool down)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
note = GetMIDINote(wCode);
|
note = GetMIDINote(wCode);
|
||||||
|
PlayNote(note, down);
|
||||||
|
piano->SetKeyStatus((note - 6) % 24, down);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::PlayNote(int note, bool down)
|
||||||
|
{
|
||||||
if (down) {
|
if (down) {
|
||||||
int num = note % 24;
|
int num = note % 24;
|
||||||
while (num < 0x7F) {
|
while (num < 0x7F) {
|
||||||
|
@ -276,8 +283,6 @@ bool MainWindow::Play(WPARAM wParam, LPARAM lParam, bool down)
|
||||||
MIDI_MESSAGE(m_midi, 0x90, note, m_force);
|
MIDI_MESSAGE(m_midi, 0x90, note, m_force);
|
||||||
else
|
else
|
||||||
MIDI_MESSAGE(m_midi, 0x90, note, 0);
|
MIDI_MESSAGE(m_midi, 0x90, note, 0);
|
||||||
piano->SetKeyStatus((note - 6) % 24, down);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
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:
|
case WM_EXITSIZEMOVE:
|
||||||
SetWindowLongPtr(m_hwnd, GWL_EXSTYLE, GetWindowLongPtr(m_hwnd, GWL_EXSTYLE) & ~WS_EX_COMPOSITED);
|
SetWindowLongPtr(m_hwnd, GWL_EXSTYLE, GetWindowLongPtr(m_hwnd, GWL_EXSTYLE) & ~WS_EX_COMPOSITED);
|
||||||
return 0;
|
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);
|
return Window::HandleMessage(uMsg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <PianoControl.hpp>
|
#include <PianoControl.hpp>
|
||||||
|
#include <MainWindow.hpp>
|
||||||
|
|
||||||
#include <windowsx.h>
|
#include <windowsx.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -30,6 +31,8 @@ LRESULT PianoControl::OnCreate()
|
||||||
|
|
||||||
blackStatus = whiteStatus = NULL;
|
blackStatus = whiteStatus = NULL;
|
||||||
blackText = whiteText = NULL;
|
blackText = whiteText = NULL;
|
||||||
|
mouseDown = false;
|
||||||
|
lastNote = lastKey = 0;
|
||||||
|
|
||||||
SetOctaves(2);
|
SetOctaves(2);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -171,6 +174,16 @@ int PianoControl::keyIDToInternal(int id, bool &black) {
|
||||||
return id / 12 * 7 + ret;
|
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) {
|
bool PianoControl::haveBlackToLeft(int i) {
|
||||||
switch (i % 7) {
|
switch (i % 7) {
|
||||||
case 0: // G
|
case 0: // G
|
||||||
|
@ -206,6 +219,43 @@ bool PianoControl::haveBlackToRight(int i) {
|
||||||
return false; // not reached
|
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)
|
void PianoControl::PaintContent(PAINTSTRUCT *pps)
|
||||||
{
|
{
|
||||||
RECT client, rect;
|
RECT client, rect;
|
||||||
|
@ -459,8 +509,41 @@ LRESULT PianoControl::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
case WM_SIZE:
|
case WM_SIZE:
|
||||||
InvalidateRect(m_hwnd, NULL, TRUE);
|
InvalidateRect(m_hwnd, NULL, TRUE);
|
||||||
return 0;
|
return 0;
|
||||||
case WM_LBUTTONDOWN:
|
case WM_LBUTTONDOWN: {
|
||||||
SetFocus(hwParent);
|
/*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;
|
return 0;
|
||||||
case WM_KEYDOWN:
|
case WM_KEYDOWN:
|
||||||
case WM_SYSKEYDOWN:
|
case WM_SYSKEYDOWN:
|
||||||
|
|
Loading…
Reference in a new issue