//
//
//

#define DBG_LEVEL 1

#include <Raym/GlobalHook.h>

namespace Raym
{

HINSTANCE   GlobalHook_instance_  = NULL;
HOOKPROC    GlobalHook_mouseHookProc_ = NULL;
HOOKPROC    GlobalHook_keybdHookProc_ = NULL;
#pragma data_seg(".GBLHOOK")
HHOOK       GlobalHook_mouseHook_ = NULL;
HHOOK       GlobalHook_keybdHook_ = NULL;
unsigned int GlobalHook_check_flag_ = 0;
#pragma data_seg()

// KeyboardProc
LRESULT CALLBACK GlobalHook_KeyboardProc(int code,       // フックコード
                              WPARAM wParam,  // 仮想キーコード
                              LPARAM lParam)  // キーストロークメッセージの情報
{
GlobalHook_check_flag_ |= 0x00000001;
    if (code < 0)
    {
GlobalHook_check_flag_ |= 0x00000002;
        return CallNextHookEx(GlobalHook_keybdHook_, code, wParam, lParam);
    }

    LRESULT result = 0;
    if (GlobalHook_keybdHookProc_ != NULL)
    {
GlobalHook_check_flag_ |= 0x00000004;
        result = GlobalHook_keybdHookProc_(code, wParam, lParam);
    }
    if (result == 0)
    {
GlobalHook_check_flag_ |= 0x00000008;
        result = CallNextHookEx(GlobalHook_keybdHook_, code, wParam, lParam);
    }

    return result;
}

// MouseProc
LRESULT CALLBACK GlobalHook_MouseProc(int code,       // フックコード
                           WPARAM wParam,  // メッセージ識別子
                           LPARAM lParam)  // マウスの座標
{
GlobalHook_check_flag_ |= 0x00000010;
    if (code < 0)
    {
GlobalHook_check_flag_ |= 0x00000020;
        return CallNextHookEx(GlobalHook_mouseHook_, code, wParam, lParam);
    }

    LRESULT result = 0;
    if (GlobalHook_mouseHookProc_ != NULL)
    {
GlobalHook_check_flag_ |= 0x00000040;
        LRESULT result = GlobalHook_mouseHookProc_(code, wParam, lParam);
    }
    if (result == 0)
    {
GlobalHook_check_flag_ |= 0x00000080;
        result = CallNextHookEx(GlobalHook_mouseHook_, code, wParam, lParam);
    }

    return result;
}

EXPORT unsigned int GetFlag()
{
    return GlobalHook_check_flag_;
}

EXPORT BOOL SetGlobalHook(int idHook, HOOKPROC lpfn)
{
GlobalHook_check_flag_ |= 0x00000100;    
    BOOL result = FALSE;
    switch (idHook)
    {
    case WH_KEYBOARD:
GlobalHook_check_flag_ |= 0x00000200;
        if ((lpfn != NULL) && (GlobalHook_keybdHook_ == NULL))
        {
#if DBG_LEVEL == 0
GlobalHook_check_flag_ != 0x00000400;
            GlobalHook_keybdHook_ = SetWindowsHookEx(WH_KEYBOARD, GlobalHook_KeyboardProc, GlobalHook_instance_, 0);
#else
GlobalHook_check_flag_ |= 0x00000800;
            GlobalHook_keybdHook_ = SetWindowsHookEx(WH_KEYBOARD_LL, GlobalHook_KeyboardProc, GlobalHook_instance_, 0);
#endif
            if (GlobalHook_keybdHook_ != NULL)
            {
GlobalHook_check_flag_ |= 0x00001000;
                result = TRUE;
                GlobalHook_keybdHookProc_ = lpfn;
            }
        }
        else if ((lpfn == NULL) && (GlobalHook_keybdHook_ != NULL))
        {
GlobalHook_check_flag_ |= 0x00002000;
            if (UnhookWindowsHookEx(GlobalHook_keybdHook_) != 0)
            {
GlobalHook_check_flag_ |= 0x00004000;
                result = TRUE;
                GlobalHook_keybdHook_ = NULL;
                GlobalHook_keybdHookProc_ = NULL;
            }
        }
        break;

    case WH_MOUSE:
GlobalHook_check_flag_ |= 0x00008000;
        if ((lpfn != NULL) && (GlobalHook_mouseHook_ == NULL))
        {
#if DBG_LEVEL == 0
GlobalHook_check_flag_ |= 0x00010000;
            GlobalHook_mouseHook_ = SetWindowsHookEx(WH_MOUSE, GlobalHook_MouseProc, GlobalHook_instance_, 0);
#else
GlobalHook_check_flag_ |= 0x00020000;
            GlobalHook_mouseHook_ = SetWindowsHookEx(WH_MOUSE_LL, GlobalHook_MouseProc, GlobalHook_instance_, 0);
#endif
            if (GlobalHook_mouseHook_ != NULL)
            {
GlobalHook_check_flag_ |= 0x00040000;
                result = TRUE;
                GlobalHook_mouseHookProc_ = lpfn;
            }
        }
        else if ((lpfn == NULL) && (GlobalHook_mouseHook_ != NULL))
        {
GlobalHook_check_flag_ |= 0x00080000;
            if (UnhookWindowsHookEx(GlobalHook_mouseHook_) != 0)
            {
GlobalHook_check_flag_ |= 0x00100000;
                result = TRUE;
                GlobalHook_mouseHook_ = NULL;
                GlobalHook_mouseHookProc_ = NULL;
GlobalHook_check_flag_ |= 0x00200000;
            }
        }
        break;

    default:
GlobalHook_check_flag_ |= 0x00400000;
        break;
    }
GlobalHook_check_flag_ |= 0x00800000;

    return result;
}

} // Raym

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    if (ul_reason_for_call == DLL_PROCESS_ATTACH)
    {
        Raym::GlobalHook_instance_ = hModule;
    }

    return TRUE;
}
