新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 中文XML论坛 - 专业的XML技术讨论区计算机技术与应用『 C/C++编程思想 』 → Win里面获取键盘和鼠标处于空闲状态地时间 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 4677 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: Win里面获取键盘和鼠标处于空闲状态地时间 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客楼主
    发贴心情 Win里面获取键盘和鼠标处于空闲状态地时间

    在编写程序的过程中,我遇到了这样的需求:在基于Windows 9x 或 Windows NT4.0

          的程序中,要求确定键盘、鼠标处于空闲状态的时间。查询了有关资料文档以后,发现Windows 9x和Windows NT4.0 没有提供API或系统调用来实现这样的功能。但是,在Windows

          2000中提供了一个新的函数:GetLastInputInfo(),这个函数使用结构 LASTINPUTINFO 作为参数:

          LASTINPUTINFO lpi;

    lpi.cbSize = sizeof(lpi);

    GetLastInputInfo(%26;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(%26;rc);

         dc.DrawText(s, %26;rc, DT_CENTER|DT_VCENTER|DT_SINGLELINE);

    }      

          图一显示了TestIdleUI运行时的情形。


          


          
    [img]/Program/image/200605/200659183313690.gif[/img]


          图一 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

          
    IdleUI的头文件和实现文件


          


          具体实现细节请参考源代码。



       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/8/11 11:38:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/11/28 16:39:26

    本主题贴数1,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    46.875ms