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 <PianoControl.hpp>
+#include <MainWindow.hpp>
 
 #include <windowsx.h>
 #include <stdio.h>
@@ -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: