2010年2月8日

一定時間ユーザ入力がないことを検知する

一定時間ユーザがPCの操作が行わなかったことを検知するにはGetLastInputInfo(ja)で最後に操作したタイミング(LASTINPUTINFO構造体のdwTime)と現在のGetTickCount(ja)の値(いずれもmsec単位)を比較します。注意点としてはGetLastInputInfoはシステム全体ではなく現在のセッションのユーザ入力のみを扱うというところでしょうか。
このサンプルではボタンをクリックしてポーリングを開始した後でユーザ入力(キーボード、マウス操作)が10秒間発生しなかったときにメッセージダイアログを表示します。またポーリング毎に前回からユーザ入力が発生していない場合はLabel1に表示しているGetTickCountの表示をclRedに変更しています。
procedure TForm1.Button1Click(Sender: TObject);
begin

  Timer1.Enabled := True;
  Button1.Enabled := False;

  FLastTick := 0;
  Timer1Timer(Sender);

end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  LII: TLastInputInfo;
begin

  FillChar(LII,SizeOf(LII),0);
  LII.cbSize := SizeOf(LII);
  if GetLastInputInfo(LII) = False then
  begin
    Exit;
  end;

  Label1.Caption := 'Last user input: ' + IntToStr(LII.dwTime);
  if FLastTick <> LII.dwTime then
  begin
    Label1.Font.Color := clWindowText;
    FLastTick := LII.dwTime;
  end
  else
  begin
    Label1.Font.Color := clRed;
  end;

  if (GetTickCount - LII.dwTime) > (10 * MSecsPerSec) then
  begin
    Timer1.Enabled := False;
    Button1.Enabled := True;
    MessageDlg('Detect for input idle (10 seconds).',
               mtInformation,[mbOk],0);
    Label1.Caption := '';
  end;

end;

別解としてSetWindowsHookEx(ja)にWH_KEYBOARD_LL(ja)/WH_MOUSE_LL(ja)を指定して低レベルフックをかけ、フック関数内でGetTickCountの値を取得、というものも考えられますが、
  1. DelphiのIDEから実行するとデバッガでブレークしたときにやたらに時間がかかる。
  2. Windows XPのVisual Style(Luna)とマウスの低レベルフックの相性が悪く(どちらかというとLunaの不具合)、フォームの最小化、最大化ボタンをクリックしたときに極端に反応が悪くなる。
という問題があるため、こちらはあまりお勧めできません。

0 件のコメント: