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
0f297cfae3
commit
c8a835e83f
2
Makefile
2
Makefile
|
@ -3,7 +3,7 @@ INCDIR=include
|
|||
|
||||
CXX=cl /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
|
||||
RC=rc /nologo
|
||||
RCFLAGS=/i$(INCDIR)
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#include <commctrl.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_SETKEYSTATUS (WM_USER + 1)
|
||||
#define MPCM_GETOCTAVES (WM_USER + 2)
|
||||
|
@ -19,6 +23,15 @@
|
|||
#define MMWM_TURNNOTE (WM_APP + 0)
|
||||
#define MMWM_NOTEID (WM_APP + 1)
|
||||
|
||||
#define MAXPOINTS 20
|
||||
|
||||
typedef struct {
|
||||
bool down;
|
||||
POINTL point;
|
||||
int lastNote;
|
||||
int lastKey;
|
||||
} PianoTouchPoint;
|
||||
|
||||
class PianoControl : public Window {
|
||||
public:
|
||||
virtual LPCTSTR ClassName() { return TEXT("KeyboardControl"); }
|
||||
|
@ -52,6 +65,14 @@ protected:
|
|||
virtual void PaintContent(PAINTSTRUCT *pps);
|
||||
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 internalToKeyID(int id, bool black);
|
||||
virtual bool haveBlackToLeft(int id);
|
||||
|
|
|
@ -4,11 +4,16 @@
|
|||
#include <windowsx.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <tchar.h>
|
||||
#include <tpcshrd.h>
|
||||
|
||||
#ifndef max
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define MOUSEEVENTF_FROMTOUCH 0xFF515700
|
||||
|
||||
BOOL PianoControl::WinRegisterClass(WNDCLASS *pwc)
|
||||
{
|
||||
return Window::WinRegisterClass(pwc);
|
||||
|
@ -34,6 +39,38 @@ LRESULT PianoControl::OnCreate()
|
|||
mouseDown = false;
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
@ -495,15 +532,72 @@ void PianoControl::OnPaint()
|
|||
EndPaint(m_hwnd, &ps);
|
||||
}
|
||||
|
||||
void PianoControl::DisableDraw() {
|
||||
void PianoControl::DisableDraw()
|
||||
{
|
||||
SendMessage(m_hwnd, WM_SETREDRAW, FALSE, 0);
|
||||
}
|
||||
|
||||
void PianoControl::EnableDraw() {
|
||||
void PianoControl::EnableDraw()
|
||||
{
|
||||
SendMessage(m_hwnd, WM_SETREDRAW, TRUE, 0);
|
||||
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)
|
||||
{
|
||||
switch (uMsg) {
|
||||
|
@ -520,27 +614,29 @@ LRESULT PianoControl::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||
case WM_SIZE:
|
||||
InvalidateRect(m_hwnd, NULL, TRUE);
|
||||
return 0;
|
||||
case WM_LBUTTONDOWN: {
|
||||
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;
|
||||
SetFocus(m_hwnd);
|
||||
return 0;
|
||||
}
|
||||
case WM_LBUTTONUP: {
|
||||
SendMessage(hwParent, MMWM_TURNNOTE, lastNote, 0);
|
||||
SetKeyStatus(lastKey, false);
|
||||
mouseDown = false;
|
||||
return 0;
|
||||
}
|
||||
case WM_LBUTTONDOWN:
|
||||
if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) != MOUSEEVENTF_FROMTOUCH) {
|
||||
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;
|
||||
SetFocus(m_hwnd);
|
||||
return 0;
|
||||
}
|
||||
case WM_LBUTTONUP:
|
||||
if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) != MOUSEEVENTF_FROMTOUCH) {
|
||||
SendMessage(hwParent, MMWM_TURNNOTE, lastNote, 0);
|
||||
SetKeyStatus(lastKey, false);
|
||||
mouseDown = false;
|
||||
return 0;
|
||||
}
|
||||
case WM_MOUSEMOVE:
|
||||
if (mouseDown) {
|
||||
if ((GetMessageExtraInfo() & 0x82) != 0x82 && mouseDown) {
|
||||
bool black;
|
||||
int internal = hitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), black);
|
||||
int key = internalToKeyID(internal, black);
|
||||
|
@ -564,6 +660,39 @@ LRESULT PianoControl::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||
case WM_SYSCHAR:
|
||||
case WM_SYSDEADCHAR:
|
||||
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:
|
||||
return (LRESULT) GetFont();
|
||||
case WM_SETFONT:
|
||||
|
|
Loading…
Reference in a new issue