原型
BOOL WINAPI GetLastInputInfo( __out PLASTINPUTINFO plii);
參數
[out] 類型:PLASTINPUTINFO結構
一個指向接收到最後一個輸入事件時間的LASTINPUTINFO結構指針。
返回值
類型:BOOL
如果調用函式成功,返回值為非零。
如果調用函式失敗,返回值為零。
備註
此函式用來檢測系統的輸入空閒時間,然而GetLastInputInfo不提供全系統所有正在運行的會話用戶輸入信息。相反,GetLastInputInfo 僅提供調用的會話功能會話特定的用戶輸入的信息。
示例
GetLastInputInfo是Windows中獲取鍵盤和滑鼠空閒時間的API
1.調用函式GetLastInputInfo()以後, 結構成員lpi.dwTime 中的值並非上次輸入事件發生以後的毫秒數。而是上次輸入事件發生時的系統運行時間。相當於上次輸入事件發生時執行了lpi.dwTime=::GetTickCount()。::GetTickCount()-lpi.dwTime才是上次輸入事件發生以後的毫秒數。
2.如原文中所說windows2000以上系統才支持函式GetLastInputInfo()因此有可能需要在StdAfx.h中加上如下語句:
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0500
原文:
在編寫程式的過程中,我遇到了這樣的需求:在基於Windows® 9x 或Windows NT4.0
的程式中,要求確定鍵盤、滑鼠處於空閒狀態的時間。
查詢了有關資料文檔以後,發現Windows 9x和Windows NT4.0沒有提供API或系統調用來實現這樣的功能。但是,在Windows 2000中提供了一個新的函式:GetLastInputInfo(),這個函式使用結構 LASTINPUTINFO 作為參數:
LASTINPUTINFO lpi;
lpi.cbSize = sizeof(lpi);
GetLastInputInfo(&lpi);
調用函式GetLastInputInfo()以後, 結構成員lpi.dwTime 中的值便是自上次輸入事件發生以後的毫秒數。這個值也就是鍵盤、滑鼠處於空閒狀態的時間。
可惜的是這個函式只能在Windows 2000中使用,Windows 9x 或Windows NT4.0不提供此API函式。
那么,如何在Windows 9x 或Windows NT4.0中實現GetLastInputInfo()的功能呢?
筆者的方法是利用系統鉤子對鍵盤、滑鼠進行監控。
Windows中的鉤子實際上是一個回調函式,當用戶有輸入動作的時候,Windows要調用這個函式。比較典型的系統鉤子套用就是鍵盤鉤子和滑鼠鉤子,
HHOOK g_hHookKbd = NULL;
HHOOK g_hHookMouse = NULL;
在Windows中,一個系統(相對於一個特定進程而言)鉤子必須用一個動態程式庫(DLL)來實現。不妨將這個動態程式庫命名為IdleUI.dll。 這個動態程式庫在Windows 9x和Windows NT4.0中實現了GetLastInputInfo()的功能。IdleUI.dll中有三個函式:
BOOL IdleUIInit()
void IdleUITerm();
DWORD IdleUIGetLastInputTime();
IdleUIInit()是環境初始化函式,IdleUITerm()是環境清理函式,分別在MFC應用程式的InitInstance() 和 ExitInstance()中調用它們。當用IdleUIInit()做完初始化後,就可以調用第三個函式IdleUIGetLastInputTime()來獲取最後一次輸入事件後的時鐘。從而實現與GetLastInputInfo()一樣的功能。
程式TestIdleUI.exe是用來測試IdleUI動態庫的,程式中調用了IdleUIInit 和 IdleUITerm,同時在程式的客戶區中間顯示鍵盤、滑鼠空閒的秒數。
void CMainFrame::OnPaint()
{
CPaintDC dc(this);
CString s;
DWORD nsec = (GetTickCount() - IdleUIGetLastInputTime())/1000;
s.Format( "滑鼠或鍵盤空閒 %d 秒。",nsec);
CRect rc;
GetClientRect(&rc);
dc.DrawText(s, &rc, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
}
圖一顯示了TestIdleUI運行時的情形。
圖一
為了連續的顯示,TestIdleUI設定刷新定時器間隔為一秒。
void CMainFrame::OnTimer(UINT)
{
Invalidate();
UpdateWindow();
}
運行TestIdleUI,當鍵盤和滑鼠什麼也不做時,可以看到計時器跳動,當移動滑鼠或按鍵時,計時器又恢復到零,這樣就實現了對輸入設備空閒狀態的監控。實現細節請看下面對IdleUI.dll工作原理的描述:
首先調用IdleUIInit ()進行初始化,安裝兩個鉤子:一個用於監控滑鼠輸入,一個用於監控鍵盤輸入。
HHOOK g_hHookKbd;
HHOOK g_hHookMouse;
g_hHookKbd = SetWindowsHookEx(WH_KEYBOARD,
MyKbdHook,
hInst, 0);
g_hHookMouse = SetWindowsHookEx(WH_MOUSE,
MyMouseHook,
hInst, 0);
當用戶移動滑鼠或按下鍵盤鍵時,Windows調用其中的一個鉤子並且鉤子函式開始記錄時間:
LRESULT CALLBACK MyMouseHook(int code,
WPARAM wp,
LPARAM lp)
{
if (code==HC_ACTION) {
// note the tick count
g_dwLastInputTick = GetTickCount();
}
return ::CallNextHookEx(g_hHookMouse,
code, wp, lp);
}
如法炮製MyKbdHook。IdleUIGetLastInputTime 返回結果g_dwLastInputTick, 並且IdleUITerm 卸載兩個鉤子。
這個程式中有一個細節使用了一些技巧:通常,建立一個動態程式庫時,連結器將靜態數據標記為非共享,也就是說,每一個調用DLL的進程都獲得自己的數據拷貝------在本程式中是g_hHookKbd、g_hHookMouse和g_dwLastInputTick。當在整個進程空間中需要且只需要一個這些數據的實例時,這樣的靜態數據標記就不適合了,為了解決這個問題,必須實現數據共享。為此得把數據放入一個特定的段地址中,然後將它們標記為共享。實現代碼如下:
#pragma data_seg (".IdleUI") // 可以取任何別的名字
HHOOK g_hHookKbd = NULL;
HHOOK g_hHookMouse = NULL;
DWORD g_dwLastInputTick = 0;
#pragma data_seg ()
這段代碼告訴連結器將三個變數放到叫“.IdleUI”的數據段中。然後在模組定義檔案.DEF中加入下面的代碼來共享這個數據段:
SECTIONS .IdleUI READ WRITE SHARED // in IdleUI.def
Requirements
Minimum supported client | Windows 2000 Professional [desktop apps only] |
Minimum supported server | Windows 2000 Server [desktop apps only] |
Header | Winuser.h (include Windows.h) |
Library | User32.lib |
DLL | User32.dll |