mirror of
https://github.com/quantum5/MusicKeyboard.git
synced 2025-04-24 13:11:58 -04:00
Working touch support.
This commit is contained in:
parent
86dfb3d33f
commit
6b456f6bec
2
Makefile
2
Makefile
|
@ -3,7 +3,7 @@ INCDIR=include
|
||||||
|
|
||||||
CXX=cl /nologo
|
CXX=cl /nologo
|
||||||
LD=link /nologo
|
LD=link /nologo
|
||||||
CXXFLAGS=/c /O1 /I$(INCDIR) /W4 /Zi /DWIN32_LEAN_AND_MEAN /DWINVER=0x0501 /D_WIN32_WINNT=0x0501 /DUNICODE /D_UNICODE
|
CXXFLAGS=/c /O1 /I$(INCDIR) /W4 /Zi /DWIN32_LEAN_AND_MEAN /DWINVER=0x0601 /D_WIN32_WINNT=0x0601 /DUNICODE /D_UNICODE
|
||||||
LDFLAGS=/subsystem:windows /debug /incremental:no /opt:REF
|
LDFLAGS=/subsystem:windows /debug /incremental:no /opt:REF
|
||||||
RC=rc /nologo
|
RC=rc /nologo
|
||||||
RCFLAGS=/i$(INCDIR)
|
RCFLAGS=/i$(INCDIR)
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
#include <commctrl.h>
|
#include <commctrl.h>
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
|
||||||
|
typedef BOOL (WINAPI *T_GetTouchInputInfo)(HTOUCHINPUT hTouchInput, UINT cInputs, PTOUCHINPUT pInputs, int cbSize);
|
||||||
|
typedef BOOL (WINAPI *T_CloseTouchInputHandle)(HTOUCHINPUT hTouchInput);
|
||||||
|
typedef BOOL (WINAPI *T_RegisterTouchWindow)(HWND hWnd, ULONG ulFlags);
|
||||||
|
|
||||||
#define MPCM_GETKEYSTATUS (WM_USER + 0)
|
#define MPCM_GETKEYSTATUS (WM_USER + 0)
|
||||||
#define MPCM_SETKEYSTATUS (WM_USER + 1)
|
#define MPCM_SETKEYSTATUS (WM_USER + 1)
|
||||||
#define MPCM_GETOCTAVES (WM_USER + 2)
|
#define MPCM_GETOCTAVES (WM_USER + 2)
|
||||||
|
@ -19,6 +23,15 @@
|
||||||
#define MMWM_TURNNOTE (WM_APP + 0)
|
#define MMWM_TURNNOTE (WM_APP + 0)
|
||||||
#define MMWM_NOTEID (WM_APP + 1)
|
#define MMWM_NOTEID (WM_APP + 1)
|
||||||
|
|
||||||
|
#define MAXPOINTS 20
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool down;
|
||||||
|
POINTL point;
|
||||||
|
int lastNote;
|
||||||
|
int lastKey;
|
||||||
|
} PianoTouchPoint;
|
||||||
|
|
||||||
class PianoControl : public Window {
|
class PianoControl : public Window {
|
||||||
public:
|
public:
|
||||||
virtual LPCTSTR ClassName() { return TEXT("KeyboardControl"); }
|
virtual LPCTSTR ClassName() { return TEXT("KeyboardControl"); }
|
||||||
|
@ -52,6 +65,14 @@ protected:
|
||||||
virtual void PaintContent(PAINTSTRUCT *pps);
|
virtual void PaintContent(PAINTSTRUCT *pps);
|
||||||
BOOL WinRegisterClass(WNDCLASS *pwc);
|
BOOL WinRegisterClass(WNDCLASS *pwc);
|
||||||
|
|
||||||
|
void OnTouchPoint(UINT id, int x, int y);
|
||||||
|
int GetTouchPointID(DWORD dwID);
|
||||||
|
PianoTouchPoint touchPoint[MAXPOINTS];
|
||||||
|
DWORD touchPointID[MAXPOINTS];
|
||||||
|
bool hasTouch;
|
||||||
|
T_GetTouchInputInfo F_GetTouchInputInfo;
|
||||||
|
T_CloseTouchInputHandle F_CloseTouchInputHandle;
|
||||||
|
|
||||||
virtual int keyIDToInternal(int id, bool &black);
|
virtual int keyIDToInternal(int id, bool &black);
|
||||||
virtual int internalToKeyID(int id, bool black);
|
virtual int internalToKeyID(int id, bool black);
|
||||||
virtual bool haveBlackToLeft(int id);
|
virtual bool haveBlackToLeft(int id);
|
||||||
|
|
|
@ -4,11 +4,16 @@
|
||||||
#include <windowsx.h>
|
#include <windowsx.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <tpcshrd.h>
|
||||||
|
|
||||||
#ifndef max
|
#ifndef max
|
||||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MOUSEEVENTF_FROMTOUCH 0xFF515700
|
||||||
|
|
||||||
BOOL PianoControl::WinRegisterClass(WNDCLASS *pwc)
|
BOOL PianoControl::WinRegisterClass(WNDCLASS *pwc)
|
||||||
{
|
{
|
||||||
return Window::WinRegisterClass(pwc);
|
return Window::WinRegisterClass(pwc);
|
||||||
|
@ -34,6 +39,38 @@ LRESULT PianoControl::OnCreate()
|
||||||
mouseDown = false;
|
mouseDown = false;
|
||||||
lastNote = lastKey = 0;
|
lastNote = lastKey = 0;
|
||||||
|
|
||||||
|
int touchSupport = GetSystemMetrics(SM_DIGITIZER);
|
||||||
|
T_RegisterTouchWindow F_RegisterTouchWindow = NULL;
|
||||||
|
hasTouch = false;
|
||||||
|
|
||||||
|
if (touchSupport & NID_READY) {
|
||||||
|
// Has touch
|
||||||
|
hasTouch = true;
|
||||||
|
|
||||||
|
F_GetTouchInputInfo = (T_GetTouchInputInfo) GetProcAddress(GetModuleHandle(TEXT("user32")), "GetTouchInputInfo");
|
||||||
|
F_CloseTouchInputHandle = (T_CloseTouchInputHandle) GetProcAddress(GetModuleHandle(TEXT("user32")), "CloseTouchInputHandle");
|
||||||
|
F_RegisterTouchWindow = (T_RegisterTouchWindow) GetProcAddress(GetModuleHandle(TEXT("user32")), "RegisterTouchWindow");
|
||||||
|
if (!F_GetTouchInputInfo || !F_CloseTouchInputHandle || !F_RegisterTouchWindow)
|
||||||
|
hasTouch = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasTouch) {
|
||||||
|
F_RegisterTouchWindow(m_hwnd, TWF_WANTPALM);
|
||||||
|
memset(touchPoint, 0, MAXPOINTS * sizeof(PianoTouchPoint));
|
||||||
|
|
||||||
|
ATOM atom = GlobalAddAtom(MICROSOFT_TABLETPENSERVICE_PROPERTY);
|
||||||
|
SetProp(m_hwnd, MICROSOFT_TABLETPENSERVICE_PROPERTY, (HANDLE) (
|
||||||
|
TABLET_DISABLE_PRESSANDHOLD | // disables press and hold (right-click) gesture
|
||||||
|
TABLET_DISABLE_PENTAPFEEDBACK | // disables UI feedback on pen up (waves)
|
||||||
|
TABLET_DISABLE_PENBARRELFEEDBACK | // disables UI feedback on pen button down
|
||||||
|
TABLET_DISABLE_FLICKS // disables pen flicks (back, forward, drag down, drag up)
|
||||||
|
));
|
||||||
|
GlobalDeleteAtom(atom);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < MAXPOINTS; ++i)
|
||||||
|
touchPointID[i] = (DWORD) -1;
|
||||||
|
|
||||||
SetOctaves(2);
|
SetOctaves(2);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -495,15 +532,72 @@ void PianoControl::OnPaint()
|
||||||
EndPaint(m_hwnd, &ps);
|
EndPaint(m_hwnd, &ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PianoControl::DisableDraw() {
|
void PianoControl::DisableDraw()
|
||||||
|
{
|
||||||
SendMessage(m_hwnd, WM_SETREDRAW, FALSE, 0);
|
SendMessage(m_hwnd, WM_SETREDRAW, FALSE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PianoControl::EnableDraw() {
|
void PianoControl::EnableDraw()
|
||||||
|
{
|
||||||
SendMessage(m_hwnd, WM_SETREDRAW, TRUE, 0);
|
SendMessage(m_hwnd, WM_SETREDRAW, TRUE, 0);
|
||||||
RedrawWindow(m_hwnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
|
RedrawWindow(m_hwnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PianoControl::OnTouchPoint(UINT id, int x, int y)
|
||||||
|
{
|
||||||
|
if (x != -1 && y != -1) {
|
||||||
|
// Touch point is down
|
||||||
|
if (touchPoint[id].down) {
|
||||||
|
// Dragged
|
||||||
|
bool black;
|
||||||
|
int internal = hitTest(x, y, black);
|
||||||
|
int key = internalToKeyID(internal, black);
|
||||||
|
int external = SendMessage(hwParent, MMWM_NOTEID, key, 0);
|
||||||
|
if (touchPoint[id].lastNote != external) {
|
||||||
|
SendMessage(hwParent, MMWM_TURNNOTE, touchPoint[id].lastNote, 0);
|
||||||
|
SetKeyStatus(touchPoint[id].lastKey, false);
|
||||||
|
SendMessage(hwParent, MMWM_TURNNOTE, external, 1);
|
||||||
|
SetKeyStatus(key, true);
|
||||||
|
touchPoint[id].lastNote = external;
|
||||||
|
touchPoint[id].lastKey = key;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Pressed
|
||||||
|
bool black;
|
||||||
|
int internal = hitTest(x, y, black);
|
||||||
|
int key = internalToKeyID(internal, black);
|
||||||
|
int external = SendMessage(hwParent, MMWM_NOTEID, key, 0);
|
||||||
|
SendMessage(hwParent, MMWM_TURNNOTE, external, 1);
|
||||||
|
SetKeyStatus(key, true);
|
||||||
|
touchPoint[id].lastNote = external;
|
||||||
|
touchPoint[id].lastKey = key;
|
||||||
|
touchPoint[id].down = true;
|
||||||
|
}
|
||||||
|
touchPoint[id].point.x = x;
|
||||||
|
touchPoint[id].point.y = y;
|
||||||
|
} else {
|
||||||
|
// It just went up
|
||||||
|
SendMessage(hwParent, MMWM_TURNNOTE, touchPoint[id].lastNote, 0);
|
||||||
|
SetKeyStatus(touchPoint[id].lastKey, false);
|
||||||
|
touchPoint[id].down = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int PianoControl::GetTouchPointID(DWORD dwID)
|
||||||
|
{
|
||||||
|
for (DWORD i = 0; i < MAXPOINTS; ++i) {
|
||||||
|
if (touchPointID[i] == dwID)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
for (DWORD i = 0; i < MAXPOINTS; ++i) {
|
||||||
|
if (touchPointID[i] == (DWORD) -1) {
|
||||||
|
touchPointID[i] = dwID;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
LRESULT PianoControl::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
LRESULT PianoControl::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
switch (uMsg) {
|
switch (uMsg) {
|
||||||
|
@ -520,27 +614,29 @@ 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:
|
||||||
bool black;
|
if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) != MOUSEEVENTF_FROMTOUCH) {
|
||||||
int internal = hitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), black);
|
bool black;
|
||||||
int key = internalToKeyID(internal, black);
|
int internal = hitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), black);
|
||||||
int external = SendMessage(hwParent, MMWM_NOTEID, key, 0);
|
int key = internalToKeyID(internal, black);
|
||||||
SendMessage(hwParent, MMWM_TURNNOTE, external, 1);
|
int external = SendMessage(hwParent, MMWM_NOTEID, key, 0);
|
||||||
SetKeyStatus(key, true);
|
SendMessage(hwParent, MMWM_TURNNOTE, external, 1);
|
||||||
lastNote = external;
|
SetKeyStatus(key, true);
|
||||||
lastKey = key;
|
lastNote = external;
|
||||||
mouseDown = true;
|
lastKey = key;
|
||||||
SetFocus(m_hwnd);
|
mouseDown = true;
|
||||||
return 0;
|
SetFocus(m_hwnd);
|
||||||
}
|
return 0;
|
||||||
case WM_LBUTTONUP: {
|
}
|
||||||
SendMessage(hwParent, MMWM_TURNNOTE, lastNote, 0);
|
case WM_LBUTTONUP:
|
||||||
SetKeyStatus(lastKey, false);
|
if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) != MOUSEEVENTF_FROMTOUCH) {
|
||||||
mouseDown = false;
|
SendMessage(hwParent, MMWM_TURNNOTE, lastNote, 0);
|
||||||
return 0;
|
SetKeyStatus(lastKey, false);
|
||||||
}
|
mouseDown = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
case WM_MOUSEMOVE:
|
case WM_MOUSEMOVE:
|
||||||
if (mouseDown) {
|
if ((GetMessageExtraInfo() & 0x82) != 0x82 && mouseDown) {
|
||||||
bool black;
|
bool black;
|
||||||
int internal = hitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), black);
|
int internal = hitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), black);
|
||||||
int key = internalToKeyID(internal, black);
|
int key = internalToKeyID(internal, black);
|
||||||
|
@ -564,6 +660,39 @@ LRESULT PianoControl::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
case WM_SYSCHAR:
|
case WM_SYSCHAR:
|
||||||
case WM_SYSDEADCHAR:
|
case WM_SYSDEADCHAR:
|
||||||
return SendMessage(hwParent, uMsg, wParam, lParam);
|
return SendMessage(hwParent, uMsg, wParam, lParam);
|
||||||
|
case WM_TOUCH: {
|
||||||
|
if (!hasTouch)
|
||||||
|
break;
|
||||||
|
|
||||||
|
UINT cInputs = LOWORD(wParam);
|
||||||
|
TOUCHINPUT *pInputs = new TOUCHINPUT[cInputs];
|
||||||
|
if (pInputs != NULL) {
|
||||||
|
if (F_GetTouchInputInfo((HTOUCHINPUT) lParam, cInputs, pInputs, sizeof(TOUCHINPUT))) {
|
||||||
|
for (UINT i = 0; i < cInputs; ++i) {
|
||||||
|
POINT ptInput;
|
||||||
|
int id = GetTouchPointID(pInputs[i].dwID);
|
||||||
|
if (id == -1)
|
||||||
|
continue; // presumably you had 20 touch points
|
||||||
|
|
||||||
|
ptInput.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x);
|
||||||
|
ptInput.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y);
|
||||||
|
ScreenToClient(m_hwnd, &ptInput);
|
||||||
|
|
||||||
|
if (pInputs[i].dwFlags & TOUCHEVENTF_UP) {
|
||||||
|
OnTouchPoint(id, -1, -1);
|
||||||
|
touchPointID[id] = (DWORD) -1; // Free the ID
|
||||||
|
} else {
|
||||||
|
OnTouchPoint(id, ptInput.x, ptInput.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
F_CloseTouchInputHandle((HTOUCHINPUT) lParam);
|
||||||
|
delete [] pInputs;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
delete [] pInputs;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case WM_GETFONT:
|
case WM_GETFONT:
|
||||||
return (LRESULT) GetFont();
|
return (LRESULT) GetFont();
|
||||||
case WM_SETFONT:
|
case WM_SETFONT:
|
||||||
|
|
Loading…
Reference in a new issue