resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio-generated include file.
// Used by LISWatch.rc
//
#define IDD_LISWATCH 101
#define IDC_EYES 101
#define IDI_LISWATCH 102
#define IDC_WNDFOCUS 1000
#define IDC_WNDACTIVE 1001
#define IDC_WNDFOREGRND 1002
#define IDC_THREADID 1003
#define IDC_WNDCAPTURE 1004
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 105
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1004
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
LISWatch.rc
//Microsoft Developer Studio-generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
// TEXTINCLUDE
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
// Dialog
IDD_LISWATCH DIALOG DISCARDABLE 32768, 5, 240, 42
STYLE WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "LISWatch"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "Thread:",IDC_STATIC,4,0,31,8
LTEXT "ThreadId",IDC_THREADID,36,0,200,8
LTEXT "Focus:",IDC_STATIC,4,8,31,8
LTEXT "Focus window",IDC_WNDFOCUS,36,8,200,8
LTEXT "Active:",IDC_STATIC,4,16,31,8
LTEXT "Active window",IDC_WNDACTIVE,36,16,200,8
LTEXT "Capture:",IDC_STATIC,4,24,31,8
LTEXT "Capture window",IDC_WNDCAPTURE,36,24,200,8
LTEXT "Foregrnd:",IDC_STATIC,4,32,31,8
LTEXT "Foreground window",IDC_WNDFOREGRND,36,32,200,8
END
/////////////////////////////////////////////////////////////////////////////
// Icon
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_LISWATCH ICON DISCARDABLE "LISWatch.ico"
/////////////////////////////////////////////////////////////////////////////
// Cursor
IDC_EYES CURSOR DISCARDABLE "Eyes.cur"
/////////////////////////////////////////////////////////////////////////////
// DESIGNINFO
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_LISWATCH, DIALOG
BEGIN
RIGHTMARGIN, 190
END
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
// Generated from the TEXTINCLUDE 3 resource.
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
LISWatch.cpp
/******************************************************************************
Module name: LISWatch.cpp
Notices: Written 1997 Jeffrey Richter
Purpose: Local-Input State (LIS) Watcher utility.
******************************************************************************/
#define STRICT
#include <windows.h>
#include <windowsx.h>
#pragma warning(disable: 4001) /* Single line comment */
#include "resource.h"
#include <tchar.h>
#include <stdio.h>
/////////////////////////// chHANDLE_DLGMSG Macro /////////////////////////////
// The normal HANDLE_MSG macro in WINDOWSX.H does not work properly for dialog
// boxes because DlgProc's return a BOOL instead of an LRESULT (like
// WndProcs). This chHANDLE_DLGMSG macro corrects the problem:
#define chHANDLE_DLGMSG(hwnd, message, fn) \
case (message): return (SetDlgMsgResult(hwnd, uMsg, \
HANDLE_##message((hwnd), (wParam),
(lParam), (fn))))
//////////////////////////////// chDIMOF Macro ////////////////////////////////
// This macro evaluates to the number of elements in an array.
#define chDIMOF(Array) (sizeof(Array) / sizeof(Array[0]))
///////////////////////////////////////////////////////////////////////////////
#define TIMER_DELAY (1 * 1000) // 1 second * 1000 milliseconds
UINT g_uTimerId = 1;
DWORD g_dwThreadIdAttachTo = 0; // 0=System-wide; Non-zero=specifc thread
///////////////////////////////////////////////////////////////////////////////
BOOL LISWatch_OnInitDialog (HWND hwnd, HWND hwndFocus, LPARAM lParam) {
// Update our contents periodically
g_uTimerId = SetTimer(hwnd, g_uTimerId, TIMER_DELAY, NULL);
// Make our window on top of all others
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
// Give our window an icon
SendMessage(hwnd, WM_SETICON, TRUE,
(LPARAM) LoadIcon(GetWindowInstance(hwnd),
MAKEINTRESOURCE(IDI_LISWATCH)));
return(TRUE); // Accept default focus window.
}
///////////////////////////////////////////////////////////////////////////////
void LISWatch_OnLButtonDown (HWND hwnd, BOOL fDoubleClick,
int x, int y, UINT keyFlags) {
// If we're attached to a thread, detach from it
if (g_dwThreadIdAttachTo != 0)
AttachThreadInput(GetCurrentThreadId(), g_dwThreadIdAttachTo, FALSE);
// Set capture to ourself and change the mouse cursor
SetCapture(hwnd);
SetCursor(LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_EYES)));
}
///////////////////////////////////////////////////////////////////////////////
void LISWatch_OnLButtonUp (HWND hwnd, int x, int y, UINT keyFlags) {
if (GetCapture() == hwnd) {
// If we had mouse capture set, get the ID of the thread that
// created the window that is under the mouse cursor.
POINT pt;
pt.x = LOWORD(GetMessagePos());
pt.y = HIWORD(GetMessagePos());
ReleaseCapture();
g_dwThreadIdAttachTo = GetWindowThreadProcessId(
ChildWindowFromPointEx(GetDesktopWindow(), pt, CWP_SKIPINVISIBLE),
NULL);
if (g_dwThreadIdAttachTo == GetCurrentThreadId()) {
// The mouse button is released on one of our windows,
// monitor local-input state on a system-wide basis
g_dwThreadIdAttachTo = 0;
} else {
// The mouse button is released on a window that our thread didn't
// create, monitor local input state for that thread only.
AttachThreadInput(GetCurrentThreadId(), g_dwThreadIdAttachTo, TRUE);
}
}
}
///////////////////////////////////////////////////////////////////////////////
static void CalcWndText (HWND hwnd, LPTSTR szBuf, int nLen) {
TCHAR szClass[50], szCaption[50], szBufT[150];
if (hwnd == (HWND) NULL) {
_tcscpy(szBuf, __TEXT("(no window)")); return;
}
if (!IsWindow(hwnd)) {
_tcscpy(szBuf, __TEXT("(invalid window)")); return;
}
GetClassName(hwnd, szClass, chDIMOF(szClass));
GetWindowText(hwnd, szCaption, chDIMOF(szCaption));
_stprintf(szBufT, __TEXT("[%s] %s"), (LPTSTR) szClass,
(*szCaption == 0) ? (LPTSTR) __TEXT("(no caption)")
: (LPTSTR) szCaption);
_tcsncpy(szBuf, szBufT, nLen - 1);
szBuf[nLen - 1] = 0; // Force zero-terminated string
}
//////////////////////////////////////////////////////////////
void LISWatch_OnTimer (HWND hwnd, UINT id) {
TCHAR szBuf[100] = __T("System-wide");
HWND hwndForeground = GetForegroundWindow();
DWORD dwThreadIdAttachTo = g_dwThreadIdAttachTo;
if (dwThreadIdAttachTo == 0) {
// If monitoring local input state system-wide, attach our input
// state to the thread that created the current foreground window.
dwThreadIdAttachTo =
GetWindowThreadProcessId(hwndForeground, NULL);
AttachThreadInput(GetCurrentThreadId(), dwThreadIdAttachTo, TRUE);
} else wsprintf(szBuf, __T("0x%08x"), dwThreadIdAttachTo);
SetWindowText(GetDlgItem(hwnd, IDC_THREADID), szBuf);
CalcWndText(GetFocus(), szBuf, chDIMOF(szBuf));
SetWindowText(GetDlgItem(hwnd, IDC_WNDFOCUS), szBuf);
CalcWndText(GetActiveWindow(), szBuf, chDIMOF(szBuf));
SetWindowText(GetDlgItem(hwnd, IDC_WNDACTIVE), szBuf);
CalcWndText(GetCapture(), szBuf, chDIMOF(szBuf));
SetWindowText(GetDlgItem(hwnd, IDC_WNDCAPTURE), szBuf);
CalcWndText(hwndForeground, szBuf, chDIMOF(szBuf));
SetWindowText(GetDlgItem(hwnd, IDC_WNDFOREGRND), szBuf);
if (g_dwThreadIdAttachTo == 0) {
// If monitoring local input state system-wide, detach our input
// state from the thread that created the current foreground window.
AttachThreadInput(GetCurrentThreadId(), dwThreadIdAttachTo, FALSE);
}
}
///////////////////////////////////////////////////////////////////////////////
void LISWatch_OnCommand (HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) {
switch (id) {
case IDOK:
case IDCANCEL: // Allows dialog box to close
EndDialog(hwnd, id);
break;
}
}
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI LISWatch_DlgProc (HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
// Standard Window's messages
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, LISWatch_OnInitDialog);
chHANDLE_DLGMSG(hwnd, WM_COMMAND, LISWatch_OnCommand);
chHANDLE_DLGMSG(hwnd, WM_TIMER, LISWatch_OnTimer);
chHANDLE_DLGMSG(hwnd, WM_LBUTTONDOWN, LISWatch_OnLButtonDown);
chHANDLE_DLGMSG(hwnd, WM_LBUTTONUP, LISWatch_OnLButtonUp);
}
return(FALSE); // We didn't process the message.
}
///////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain (HINSTANCE hinstExe, HINSTANCE hinstPrev,
LPSTR lpszCmdLine, int nCmdShow) {
DialogBox(hinstExe, MAKEINTRESOURCE(IDD_LISWATCH),
NULL, LISWatch_DlgProc);
return(0);
}
//////////////////////////////// End of File //////////////////////////////////
Figure 3 LISWatch_OnTimer
void LISWatch_OnTimer (HWND hwnd, UINT id) {
TCHAR szBuf[100] = __T("System-wide");
HWND hwndForeground = GetForegroundWindow();
DWORD dwThreadIdAttachTo = g_dwThreadIdAttachTo;
if (dwThreadIdAttachTo == 0) {
// If monitoring local input state system-wide, attach our input
// state to the thread that created the current foreground window.
dwThreadIdAttachTo =
GetWindowThreadProcessId(hwndForeground, NULL);
AttachThreadInput(GetCurrentThreadId(), dwThreadIdAttachTo, TRUE);
} else wsprintf(szBuf, __T("0x%08x"), dwThreadIdAttachTo);
SetWindowText(GetDlgItem(hwnd, IDC_THREADID), szBuf);
CalcWndText(GetFocus(), szBuf, chDIMOF(szBuf));
SetWindowText(GetDlgItem(hwnd, IDC_WNDFOCUS), szBuf);
CalcWndText(GetActiveWindow(), szBuf, chDIMOF(szBuf));
SetWindowText(GetDlgItem(hwnd, IDC_WNDACTIVE), szBuf);
CalcWndText(GetCapture(), szBuf, chDIMOF(szBuf));
SetWindowText(GetDlgItem(hwnd, IDC_WNDCAPTURE), szBuf);
CalcWndText(hwndForeground, szBuf, chDIMOF(szBuf));
SetWindowText(GetDlgItem(hwnd, IDC_WNDFOREGRND), szBuf);
if (g_dwThreadIdAttachTo == 0) {
// If monitoring local input state system-wide, detach our input
// state from the thread that created the current foreground window.
AttachThreadInput(GetCurrentThreadId(), dwThreadIdAttachTo, FALSE);
}
}