 
 : message>button ( uMsg -- button down? )
     {
-        { [ dup WM_LBUTTONDOWN   = ] [ drop 1 t ] }
-        { [ dup WM_LBUTTONUP     = ] [ drop 1 f ] }
-        { [ dup WM_MBUTTONDOWN   = ] [ drop 2 t ] }
-        { [ dup WM_MBUTTONUP     = ] [ drop 2 f ] }
-        { [ dup WM_RBUTTONDOWN   = ] [ drop 3 t ] }
-        { [ dup WM_RBUTTONUP     = ] [ drop 3 f ] }
-
-        { [ dup WM_NCLBUTTONDOWN = ] [ drop 1 t ] }
-        { [ dup WM_NCLBUTTONUP   = ] [ drop 1 f ] }
-        { [ dup WM_NCMBUTTONDOWN = ] [ drop 2 t ] }
-        { [ dup WM_NCMBUTTONUP   = ] [ drop 2 f ] }
-        { [ dup WM_NCRBUTTONDOWN = ] [ drop 3 t ] }
-        { [ dup WM_NCRBUTTONUP   = ] [ drop 3 f ] }
-    } cond ;
+        { WM_LBUTTONDOWN   [ 1 t ] }
+        { WM_LBUTTONUP     [ 1 f ] }
+        { WM_MBUTTONDOWN   [ 2 t ] }
+        { WM_MBUTTONUP     [ 2 f ] }
+        { WM_RBUTTONDOWN   [ 3 t ] }
+        { WM_RBUTTONUP     [ 3 f ] }
+
+        { WM_NCLBUTTONDOWN [ 1 t ] }
+        { WM_NCLBUTTONUP   [ 1 f ] }
+        { WM_NCMBUTTONDOWN [ 2 t ] }
+        { WM_NCMBUTTONUP   [ 2 f ] }
+        { WM_NCRBUTTONDOWN [ 3 t ] }
+        { WM_NCRBUTTONUP   [ 3 f ] }
+    } case ;
 
 ! If the user clicks in the window border ("non-client area")
 ! Windows sends us an NC[LMR]BUTTONDOWN message; but if the

: alt? ( -- ? ) left-alt? right-alt? or ;
: caps-lock? ( -- ? ) VK_CAPITAL GetKeyState zero? not ;

: switch-case ( seq -- seq )
    dup first CHAR: a >= [ >upper ] [ >lower ] if ;

: switch-case? ( -- ? ) shift? caps-lock? xor not ;

: key-modifiers ( -- seq )
    [
        shift? [ S+ , ] when

: exclude-key-wm-char? ( n -- bool )
    exclude-keys-wm-char key? ;

: keystroke>gesture ( n -- mods sym )
    wm-keydown-codes at* [ key-modifiers swap ] [ drop f f ] if ;

: send-key-gesture ( sym action? quot hWnd -- )
    [ [ key-modifiers ] 3dip call ] dip
    window-focus propagate-gesture ; inline

: send-key-down ( sym action? hWnd -- )
    [ [ <key-down> ] ] dip send-key-gesture ;

: send-key-up ( sym action? hWnd -- )
    [ [ <key-up> ] ] dip send-key-gesture ;

: key-sym ( wParam -- string/f action? )
    {
        {
            [ dup LETTER? ]
            [ shift? caps-lock? xor [ CHAR: a + CHAR: A - ] unless 1string f ]
        }
        { [ dup digit? ] [ 1string f ] }
        [ wm-keydown-codes at t ]
    } cond ;

:: handle-wm-keydown ( hWnd uMsg wParam lParam -- )
    wParam exclude-key-wm-keydown? [
        wParam key-sym over [
            dup ctrl? alt? xor or [
                hWnd send-key-down
            ] [ 2drop ] if
        ] [ 2drop ] if
    ] unless ;

:: handle-wm-char ( hWnd uMsg wParam lParam -- )
    wParam exclude-key-wm-char? [
        ctrl? alt? xor [
            wParam 1string
            [ f hWnd send-key-down ]
            [ hWnd window-focus user-input ] bi
        ] unless
    ] unless ;

:: handle-wm-keyup ( hWnd uMsg wParam lParam -- )
    wParam exclude-key-wm-keydown? [
        wParam key-sym over [
            hWnd send-key-up
        ] [ 2drop ] if
    ] unless ;

:: set-window-active ( hwnd uMsg wParam lParam ? -- n )
    ? hwnd window (>>active?)
