/*************************************************************************
    Project:    Active Accessibility
    Module:     AccEvent

    Author:     LauraBu, SteveDon, PeteW
    Date:       5-1-96
    
    Notes:      Active Accessibility event logger

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

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

#include <windows.h>
#include <windowsx.h>
#include <winable.h>
#include <initguid.h>
#include <objbase.h>
#include <objerror.h>
#include <ole2.h>
#include "accevent.h"
#define NOTEVENTDLL
#include "resource.h"
#include ".\event\event.h"

// Constants
#define     CITEMS_FLUSH        2048
#define     HFILE_NONE          ((HFILE)-1)


//
// Variables
//
HWND        hwndMain;
HMENU       hmenuMain;
HWND        hwndList;
UINT        cListItems = 0;
HINSTANCE   hinstApp;
HANDLE      hheapStringMem;
//HACCEL      haccel;
HFILE       hFileLog = HFILE_NONE;
BOOL        fLogToFile = FALSE;
BOOL        fLogToWindow = TRUE;
BOOL		fInContext = TRUE;
TCHAR       szReaderClass[] = "AccEventClass";
DWORD       idThreadMenu = 0;
SHORT       shVerbosity = 0;
UINT        grfTrack = SEF_WINDOW_OBJECTS | SEF_CREATION | SEF_STATE |
    SEF_DESCRIPTION | SEF_LOCATION | SEF_FOCUSSEL | SEF_OTHER | SEF_MODE_TRACK;


//
// Functions
//
BOOL PASCAL FInitReader(HINSTANCE);
void PASCAL TermReader(void);
void PASCAL AddEventString(UINT, LPSTR);
void PASCAL FileLogging(BOOL fOn);

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);





// --------------------------------------------------------------------------
//
//  WinMain()
//
// --------------------------------------------------------------------------
int PASCAL
WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR szCmdLine, int nCmdShow)
{
    if (FInitReader(hinst))
    {
        MSG     msg;

        // Main message loop
        while (GetMessage(&msg, NULL, 0, 0))
        {
            // for beta 2, we have no accellerators    
            //if (!TranslateAccelerator(hwndMain, haccel, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    }
    TermReader();

    return(0);
}



// --------------------------------------------------------------------------
//
//  FInitReader()
//
//  Initialize our titlebar test applet
//
// --------------------------------------------------------------------------
BOOL PASCAL FInitReader(HINSTANCE hInstance)
{
    WNDCLASSEX      wc;

    hinstApp = hInstance;

    CoInitialize(NULL);

    //
    // Register our class
    //
    wc.cbSize       = sizeof(wc);
    wc.style        = 0;
    wc.lpfnWndProc  = MainWndProc;
    wc.cbClsExtra   = 0;
    wc.cbWndExtra   = 0;
    wc.hInstance    = hinstApp;
    wc.hIcon        = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor      = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName    = szReaderClass;
    wc.hIconSm      = NULL;

    if (!RegisterClassEx(&wc))
        return(FALSE);

    //
    // Load our menu bar
    //
    hmenuMain = LoadMenu(hinstApp, MAKEINTRESOURCE(IDM_MENU));
    if (!hmenuMain)
        return(FALSE);

    //
    // Load our accelerator table
    //
    // commented out for beta 2 - no accelerators any more
    //haccel = LoadAccelerators(hinstApp, MAKEINTRESOURCE(IDA_ACCEL));
    //if (!haccel)
    //    return(FALSE);

    //
    // Create our reader window
    //
    hwndMain = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_APPWINDOW,
        szReaderClass, "Accessibility Events - In Context", WS_OVERLAPPEDWINDOW,
        0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) / 2,
        NULL, hmenuMain, hinstApp, NULL);
    if (!hwndMain)
        return(FALSE);

    ShowWindow(hwndMain, SW_SHOW);
    UpdateWindow(hwndMain);

    // Set system-wide screen reader present flag 
    SystemParametersInfo(SPI_SETSCREENREADER, TRUE, NULL, SPIF_SENDWININICHANGE);

    // Install win event hook
    hheapStringMem = InstallEventHook(hwndMain,fInContext);
    if (hheapStringMem)
        SetEventFilter(grfTrack);

    return(hheapStringMem != NULL);
}



// --------------------------------------------------------------------------
//
//  TermReader()
//
//  Cleans up anything still around when the screen reader exits
//
// --------------------------------------------------------------------------
void PASCAL TermReader(void)
{
    if (hheapStringMem)
    {
        hheapStringMem = NULL;
        InstallEventHook(NULL,FALSE);
    }

    FileLogging(FALSE);

    CoUninitialize();

    if (hwndMain)
    {
        //
        // DestroyWindow() will also clean up our menu bar
        //
        DestroyWindow(hwndMain);
        hwndMain = NULL;
    }
}


// --------------------------------------------------------------------------
//
//  MainWndProc()
//
// --------------------------------------------------------------------------
LRESULT CALLBACK
MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    RECT    rc;
    UINT    sefToggle;

    switch (uMsg)
    {
        case WM_CREATE:
            //
            // Create our listbox child.
            //
            GetClientRect(hwnd, &rc);

            hwndList = CreateWindowEx(WS_EX_CLIENTEDGE, "LISTBOX", NULL,
                WS_CHILD | WS_HSCROLL | WS_VSCROLL | LBS_NOSEL | LBS_HASSTRINGS
                | LBS_USETABSTOPS | LBS_DISABLENOSCROLL | LBS_NOINTEGRALHEIGHT,
                rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
                hwnd, (HMENU)0, hinstApp, NULL);
            if (!hwndList)
                return(-1);

            ShowWindow(hwndList, SW_SHOW);
            UpdateWindow(hwndList);
            break;

        case WM_SIZE:
            if (wParam != SIZEICONIC)
            {
                SetWindowPos(hwndList, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam),
                    SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
            }
            break;

        case WM_SETFOCUS:
            SetFocus(hwndList);
            break;

        case WM_DESTROY:
            FileLogging(FALSE);
            SetEventFilter(grfTrack = 0);
            hwndList = NULL;
            hwndMain = NULL;
            PostQuitMessage(0);
            break;

        case WM_COMMAND:
            switch (GET_WM_COMMAND_ID(wParam, lParam))
            {
                case CMD_LOGTOFILE:
                    // Toggle logging to file
                    fLogToFile = !fLogToFile;
                    FileLogging(fLogToFile);

                    // Update menu item
                    CheckMenuItem(hmenuMain, CMD_LOGTOFILE, (fLogToFile ?
                        MF_CHECKED : MF_UNCHECKED));
                    break;

                case CMD_LOGTOWINDOW:
                    // Toggle logging to window
                    fLogToWindow = !fLogToWindow;
                    CheckMenuItem(hmenuMain, CMD_LOGTOWINDOW, (fLogToWindow ?
                        MF_CHECKED : MF_UNCHECKED));
                    break;

		case CMD_INCONTEXT:
                    // Toggle event hook InContext/OutOfContext
                    fInContext = !fInContext;
                    CheckMenuItem(hmenuMain, CMD_INCONTEXT, (fInContext ?
                        MF_CHECKED : MF_UNCHECKED));
					InstallEventHook (NULL,FALSE); // remove existing hook
					hheapStringMem = InstallEventHook(hwndMain,fInContext); // install new hook
					if (fInContext)
						SetWindowText (hwndMain,"Accessibility Events - In Context");
					else
						SetWindowText (hwndMain,"Accessibility Events - Out of Context");
                    break;

                case CMD_EXIT:
                    DestroyWindow(hwnd);
                    break;

                // These are not used!
                case FAKE_EVENT_SYSTEM_DEFACTION:
                case FAKE_EVENT_SYSTEM_FOCUS:
                case FAKE_EVENT_SYSTEM_SELECTION:
                case FAKE_EVENT_SYSTEM_SELECTIONADD:
                case FAKE_EVENT_SYSTEM_SELECTIONREMOVE:
                case FAKE_EVENT_SYSTEM_UNDERTHECURSOR:
                    DoFakeEvent(GET_WM_COMMAND_ID(wParam, lParam));
                    break;

                case CMD_USEINVOKE:
                    // Toggle to use ole automation
                    sefToggle = SEF_USEINVOKE;
                    goto ToggleEventTrack;

                //
                // Toggle tracking of differnt groups of events
                //

                case CMD_CREATION_EVENTS:
                    sefToggle = SEF_CREATION;
                    goto ToggleEventTrack;

                case CMD_DESCRIPTION_EVENTS:
                    sefToggle = SEF_DESCRIPTION;
                    goto ToggleEventTrack;

                case CMD_FOCUSSEL_EVENTS:
                    sefToggle = SEF_FOCUSSEL;
                    goto ToggleEventTrack;

                case CMD_STATE_EVENTS:
                    sefToggle = SEF_STATE;
                    goto ToggleEventTrack;

                case CMD_LOCATION_EVENTS:
                    sefToggle = SEF_LOCATION;
                    goto ToggleEventTrack;

                case CMD_OTHER_EVENTS:
                    sefToggle = SEF_OTHER;
                    goto ToggleEventTrack;

                //
                // Toggle tracking different kinds of objects
                //

                case CMD_CARET_OBJECTS:
                    sefToggle = SEF_CARET_OBJECTS;
                    goto ToggleEventTrack;

                case CMD_CURSOR_OBJECTS:
                    sefToggle = SEF_CURSOR_OBJECTS;
                    goto ToggleEventTrack;

                case CMD_WINDOW_OBJECTS:
                    sefToggle = SEF_WINDOW_OBJECTS;
                    goto ToggleEventTrack;

                case CMD_SOUND_OBJECTS:
                    sefToggle = SEF_SOUND_OBJECTS;
                    goto ToggleEventTrack;

                case CMD_ALERT_OBJECTS:
                    sefToggle = SEF_ALERT_OBJECTS;
                    goto ToggleEventTrack;

                case CMD_MODE_TRACK:
                    // Toggle tracking of mode events
                    sefToggle = SEF_MODE_TRACK;
ToggleEventTrack:
                    grfTrack ^= sefToggle;
                    CheckMenuItem(hmenuMain, GET_WM_COMMAND_ID(wParam, lParam),
                        (grfTrack & sefToggle) ? MF_CHECKED : MF_UNCHECKED);

                    SetEventFilter(grfTrack);
                    break;

                default:
                    break;
            }
            break;

        case WM_ADDEVENT:
            // Add a line to the event log
            AddEventString(wParam, (LPSTR)lParam);
            break;

        default:
            return(DefWindowProc(hwnd, uMsg, wParam, lParam));
    }

    return(0L);
}



// --------------------------------------------------------------------------
//
//  FileLogging()
//
//  Turns file logging on/off.
//
// --------------------------------------------------------------------------
void PASCAL FileLogging(BOOL fOn)
{
    if (fOn)
    {
        if (hFileLog == HFILE_NONE)
        {
            TCHAR    szTempFile[MAX_PATH];

            if (GetTempFileName(".\\", "Log", 0, szTempFile))
                hFileLog = _lcreat(szTempFile, 0);
        }
    }
    else
    {
        if (hFileLog != HFILE_NONE)
        {
            _lclose(hFileLog);
            hFileLog = HFILE_NONE;
        }
    }
}



// --------------------------------------------------------------------------
//
//  AddEventString()
//
//  This actually adds a string into our list when the WM_ADDEVENT message
//  is retrieved.  It takes care of flushing the list when needed, and
//  freeing the memory allocated inside of NotifyProc().
//
// --------------------------------------------------------------------------
void PASCAL AddEventString(UINT cbAdd, LPSTR lpszAdd)
{
    //
    // First, append this string to our file if one is open.  NOTE that
    // cbAdd includes the null terminator.
    //
    if (hFileLog != HFILE_NONE)
    {
        _lwrite(hFileLog, lpszAdd, cbAdd);
        _lwrite(hFileLog, "\r\n", 2);
    }

    if (hwndList && fLogToWindow)
    {
        //
        // Are there more than CITEMS_FLUSH strings?  If so, reset the list 
        // content before appending this one.
        //
        if (cListItems >= CITEMS_FLUSH)
        {
            cListItems = 0;

            SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
            SendMessage(hwndList, LB_RESETCONTENT, 0, 0);
            SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);

            InvalidateRect(hwndList, NULL, TRUE);
            UpdateWindow(hwndList);
        }

        //
        // Append our item.
        //
        ++cListItems;
        SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)lpszAdd);
        SendMessage(hwndList, WM_VSCROLL, SB_LINEDOWN, 0);
    }

    HeapFree(hheapStringMem, 0, lpszAdd);
}

/*
    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.
*/

