/*************************************************************************
    Project:    Microsoft Active Accessibility
    Module:     HOOK.CPP

    Author:     LauraBu, SteveDon, PeteW
    Date:       5/1/96
    
    Notes:
      This is the code for the hook dll.  It installs a global keyboard hook
      on request, and looks for a couple of hotkey combinations.  When it
      sees one it recognizes, it posts a message to the INSPECT app window.

    Copyright (C) 1996 by Microsoft Corporation.  All rights reserved.
    See bottom of file for disclaimer
    
    History:    

*************************************************************************/

#define STRICT
#include <windows.h>
#include "..\inspect.h"

#define NAVDIR_LEFT     0x0003
#define NAVDIR_UP       0x0001
#define NAVDIR_RIGHT    0x0004
#define NAVDIR_DOWN     0x0002

typedef struct tagHOTK
{
    WPARAM  keyVal;     // Key value, like F1
    int     wmMsg;      // Message to post, like WM_DOPROPERTIES
    WPARAM  wParam;     // wParam of message
} HOTK;


//
// Variables (all GLOBAL)
//
#pragma data_seg(".sdata")
HWND    hwndInspect = NULL;
HHOOK   hhookKey = NULL;

//
// Hot keys (+ CTRL & SHIFT):
//

#define CKEYS_HOT       10

HOTK rgHotKeys[CKEYS_HOT] =
{
    // Do properties
    {
        VK_F2,  WM_DOPROPERTIES, 0
    },

    // Do default
    {
        VK_F3, WM_DODEFAULT, 0
    },

    // Select object
    {
        VK_F4, WM_DOSELECT, 0
    },

    // Focus object
    {
        VK_F5, WM_DOSELECT, 1
    },

    // Next object
    {
        VK_F6,  WM_DONAVIGATE, TRUE
    },

    // Previous object
    {
        VK_F7, WM_DONAVIGATE, FALSE
    },


    // Left object
    {
        VK_F8, WM_DODIRECTION, NAVDIR_LEFT
    },

    // Up object
    {
        VK_F9, WM_DODIRECTION, NAVDIR_UP
    },

    // Right object
    {
        VK_F11, WM_DODIRECTION, NAVDIR_RIGHT
    },

    // Down object
    {
        VK_F12, WM_DODIRECTION, NAVDIR_DOWN
    },

};
#pragma data_seg()


LRESULT CALLBACK    KeyboardHook(int code, WPARAM wParam, LPARAM lParam);
HOTK*               FindHotKey(WPARAM wParam, LPARAM lParam);
__declspec(dllexport) BOOL WINAPI InstallHook(HWND hwnd, BOOL fInstall);


// --------------------------------------------------------------------------
//
//  InstallHook()
//
//  This is an API that INSPECT.EXE calls once it is initialized so we can
//  install our hook.  We need an HWND, that is why we don't do this on
//  first process init.
//
// --------------------------------------------------------------------------
BOOL WINAPI InstallHook(HWND hwnd, BOOL fInstall)
{
    if (fInstall)
    {
        HMODULE hModSelf;

        // If someone else has a hook installed, fail.
        if (hwndInspect)
            return(FALSE);

        hwndInspect = hwnd;

        hModSelf = GetModuleHandle("hook.dll");
        if (!hModSelf)
            return(FALSE);

        hhookKey = SetWindowsHookEx(WH_KEYBOARD, KeyboardHook, hModSelf, 0);

        return(hhookKey != NULL);
    }
    else
    {
        if (hhookKey)
        {
            UnhookWindowsHookEx(hhookKey);
            hhookKey = NULL;
        }

        hwndInspect = NULL;
    }

    return(TRUE);
}




// --------------------------------------------------------------------------
//
//  KeyboardHook()
//
//  This looks for some specific key combinations.
//
// --------------------------------------------------------------------------
LRESULT CALLBACK KeyboardHook(int code, WPARAM wParam, LPARAM lParam)
{
    HOTK * photk;

    //
    // Is this key down in our list?  If so then skip it and generate a
    // posted message only if this is a swallowed message.  Otherwise we
    // will generate multiple posted messages if someone is in a peek loop.
    // 

    if (code == HC_ACTION)
    {
        if (photk = FindHotKey(wParam, lParam))
            PostMessage(hwndInspect, photk->wmMsg, photk->wParam, 0);
    }
    
    return(CallNextHookEx(hhookKey, code, wParam, lParam));
}




// --------------------------------------------------------------------------
//
//  FindHotKey()
//
//  This looks up to see if the key down (down only) is in our list.
//
// --------------------------------------------------------------------------
HOTK* FindHotKey(WPARAM wKey, LPARAM lBits)
{
    int     ihotk;

    // If this is a key up, or the Alt key is down, bail out now.
    if (lBits & 0xA0000000)
        return(NULL);

    // If the Shift or Control key isn't down, bail out
    if ((GetKeyState(VK_SHIFT) >= 0) || (GetKeyState(VK_CONTROL) >= 0))
        return(NULL);

    //
    // OK, is this key in our list?
    //
    for (ihotk = 0; ihotk < CKEYS_HOT; ihotk++)
    {
        if (rgHotKeys[ihotk].keyVal == wKey)
            return(rgHotKeys + ihotk);
    }

    // Nope.
    return(NULL);
}



// --------------------------------------------------------------------------
//
//  Entry point:  DllMain()
//
//  We do this to avoid pulling in the CRT.
//
// --------------------------------------------------------------------------
BOOL WINAPI
DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID pvReserved)
{
    return(TRUE);
}


/*
    THE INFORMATION AND CODE PROVIDED HEREUNDER (COLLECTIVELY REFERRED TO
    AS "SOFTWARE") IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN
    NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR
    ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL,
    CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF
    MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR
    LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE
    FOREGOING LIMITATION MAY NOT APPLY.
*/
