博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
防止系统锁屏-python、C++实现
阅读量:5925 次
发布时间:2019-06-19

本文共 6812 字,大约阅读时间需要 22 分钟。

一、背景

作为一个开发,我的电脑经常是一个礼拜不关机,甚至时间更久,不知道在其他人看来这是不是一个常规操作。在日常工作中,我们的电脑也是一直处于非锁屏状态,出于对个人工作成果的安全性保护,我们公司给每个人的电脑上下发了一个组策略(属于强制下发,抗议无效),5min不对电脑进行操作,电脑就锁屏,这可真是令人操蛋,出去上个厕所的功夫电脑就锁屏啦、和别人讨论问题的功夫电脑又锁屏了,作为一个开发,这真不能忍。

最近一直在学习python,刚好接触到了pythonwindows服务相关的一些东西,嘿嘿,5分钟不操作电脑锁屏是吧,那么我们在无任何操作下2分钟给他模拟一次键盘或者鼠标操作可好。

二、模拟鼠标、键盘事件

要写一个windows服务也是比较简单的,只需要继承自win32serviceutil.ServiceFramework这个类,然后实现相关方法即可,主要的方法是SvcDoRun,服务启动后,该方法处于激活状态,该方法结束服务退出

具体的实现方式可参考文章中的第三小节,优化定时任务。

1、python实现

这里我只贴出关键代码,服务的整体框架不在细说,不会的同学请看这里

a、python服务

首先判断鼠标2分钟内是否有操作,我们需要能获取到当前鼠标位置的函数,pyautogui是一个python的自动化库,满足我们的需求,该库提供了丰富的鼠标、键盘操作,使用该库,首先就得使用pip进行安装

pip install pyautogui

使用方式如下,x和y即是当前鼠标相对于屏幕左上角(0,0)的坐标

import pyautogui as pagx, y = pag.position() #返回鼠标的坐标

模拟鼠标、键盘操作,无非是鼠标点击、移动、键盘按下等,这些pyautogui都已经提供,看名字就知道什么意思,这里我们先进行了鼠标点击,默认是左键,然后移动了鼠标位置,并且在最后按下了键盘上的esc键

pag.click()pag.moveTo(x + 10, y + 10, 0.1)pag.moveTo(x, y, 0.1)writeLog('模拟一次鼠标移动\n')#pag.press('esc')writeLog('模拟点击esc\n')#

完整的SvcDoRUn函数如下

def SvcDoRun(self):    #what to do#    prev_time = datetime.datetime.now()    oldx = 0    oldy = 0    while self.run:        x, y = pag.position() #返回鼠标的坐标        now_time = datetime.datetime.now()        if x == oldx and y == oldy:            stay_seconds = (now_time -  prev_time).seconds            if stay_seconds >= 60:                prev_time = now_time                pag.click()                pag.moveTo(x + 10, y + 10, 0.1)                pag.moveTo(x, y, 0.1)                writeLog('模拟一次鼠标移动\n')#                pag.press('esc')                writeLog('模拟点击esc\n')#        else:            #更新旧坐标 最后一次移动鼠标时间            oldx = x            oldy = y            prev_time = now_time            #os.system('cls')#清楚屏幕        stay_seconds = (now_time -  prev_time).seconds        writeLog('鼠标{}秒未移动\n'.format(stay_seconds))#打印坐标        posStr = "Position:" + str(x).rjust(4) + ',' + str(y).rjust(4)        writeLog(posStr + '\n')#打印坐标        time.sleep(2)

服务函数写完了,接下来是打包服务的过程,并启动服务

1. 打包服务成一个exe,pyinstaller -F  aaa.py2. 安装服务 python aaa.exe install3. 启动服务 python aaa.exe start 4. 停止服务 python aaa.exe stop5. 移除服务 python aaa.exe remove

执行上述流程的1、2和3,服务就已经被成功启动,但不幸的是发现pag.position()返回的坐标一直是0,各种测试都不对,开始怀疑是服务里可能找不到pyautogui资源导致失败,后来在网上找了另一种或许鼠标位置的函数

def get_mouse_point():   po = POINT()   windll.user32.GetCursorPos(byref(po))   return int(po.x), int(po.y)

经过测试,该函数单独运行时没有问题,放在服务里拿到的坐标还是(0, 0),写服务的路子算是泡汤啦

为了更好的查找服务的运行状态,我们这里把服务的运行时状态卸载了一个文件里,写日志代码如下

#写日志def writeLog(msg):    try:        f = open('./prevent_lock_screen.log', 'a', encoding = 'utf-8')        f.write(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + ':' + msg)        f.close()    except BaseException:        pass
b、python函数

python服务的方式暂时算是中断了,但是我们还是不能放弃啊,经过尝试,把运行在服务里的代码拿出来放在正常python文件里执行还是好使的。不明所以啊,++哪位大神如果知道服务里的代码为什么运行失败,还请评论区支出,不胜感激。。。++

为了防止电脑自动锁屏,要一直运行一个dos窗口看起来确实挺扯的,初学python可能好多东西还是不懂,因此为了让这个需求更优雅一些,我拿起了C++,我们还是先来写一个服务吧

2、C++实现

为了实现这个需求,我也真是拼了

a、C++服务

不得不说,C++写服务还是挺费劲的,在网上扒了一个服务的模子,我便开始写了,其实最主要的还是要实现服务中的死循环函数,代码逻辑和上述python的思路一起,区别就是我们需要使用C++的语法实现一遍而已。

POINT p;    GetCursorPos(&p);//获取鼠标坐标    int x = p.x, y = p.y;//返回鼠标的坐标    time_t now_time = time(NULL);    if (x == oldx && y == oldy)    {        int stay_seconds = int(now_time - prev_time);        if (stay_seconds >= 6)        {            prev_time = now_time;            SetCursorPos(x + 10, y + 10);            SetCursorPos(x, y);            WriteToLog("模拟一次鼠标移动");            mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, x, y, 0, 0);            WriteToLog("模拟鼠标单击");            keybd_event('esc', 0, 0, 0);            keybd_event('a', 0, 0, 0);            WriteToLog("模拟点击esc");        }    }    else    {        //更新旧坐标 最后一次移动鼠标时间        oldx = x;        oldy = y;        prev_time = now_time;    }

接下来的操作就是我们需要把写好的服务安装并启动

1. sc create test binPath= 可执行文件的路径2. net start test3. net stop test4. net delete test

执行上述步骤1和2即可启动服务

经过测试,太不幸了,GetCursorPos(&p)返回的坐标也为(0, 0),这下真是郁闷了,服务这条路难道真的走不通了吗?看到的大神有解决思路的还请在评论区支出,不胜感激。。。

b、C++可执行程序

照搬照抄上述python服务转可执行程序的逻辑,我们把C++服务里的代码拿出来,放到 C++可执行程序中,我们也可以实现一个C++可执行程序

进过测试,以上python程序和C++程序都还有一些问题,在一些特定的窗口上模拟鼠标、键盘操作不好使,比如notepad ++、windows任务管理器等,系统在5分钟后还是锁屏,思前想后,觉着这个可能和程序权限有关系,随即把C++工程的属性进行了调整,生成的exe需要带有管理员权限,在次进行测试,结果是完美的,我们终于可以防止系统自动锁屏了,执行上述python的程序这里就不做权限升级研究了,有兴趣的同学自行研究

c++程序我们可以通过设置来吧程序设置成后台运行的,没有任何界面,这样显得更优雅一些,首先我们创建的是一个dos程序,设置设置两个地方即可

  1. 连接器->系统:子系统设置成窗口 (/SUBSYSTEM:WINDOWS)
  2. 连接器->高级:入口点设置成mainCRTStartup

三、优化

最开始的模拟用户操作,我们使用的是点击鼠标左键、移动鼠标、和模拟点击esc按键,但是上述操作都会不懂程度的带来一些影响。

例如:

  1. 如果用户正在看视频,没有进行键鼠操作,这个时候如果点击鼠标左键,可能会导致视频暂停,不是用户期望的操作
  2. 如果用户打开了一个弹框,例如顶层窗口是一个esc快捷键可以关闭的程序,这个时候如果用户2分钟没有操作电脑,那么模拟的esc按键将会把用户的原始状态打乱

模拟操作优化过程

1、win+d

切换到桌面,随即在开切换回来,这个操作相对来说比较靠谱,但是如果有一个窗口上有模态窗口存在,也会对打乱原始的窗口顺序

2、win键

点击windows键,随即在点击一次,恢复到点击之前的状态,这个操作相对第一种还是比较友好的

3、切换大小写

点击CapsLk按键,进行大小写切换,由于这个时候用户没有操作电脑,因此切换大小写不会对用户操作进行干扰,而且动静更小、更优雅

上述3中模拟操作行为基本思路都是一样的,只是模拟的方式所有不同,下边我们就以第三种方式讲解实现过程

点击CapsLk的操作分两部分,第一次主要是为了模拟用户点击,第二次是为了恢复第一次操作留下的痕迹,为了让程序更优雅的运行,我们这里需要启动子线程来恢复主线程留下的痕迹

main函数代码如下

hMutex = CreateMutex(NULL, FALSE, (LPCWSTR)"PreventLockScreenApp");WaitForSingleObject(hMutex, INFINITE);HANDLE hThread = CreateThread(NULL, 0, RestoreWinState, NULL, 0, NULL);     //创建线程01CloseHandle(hThread); //关闭句柄remove(LOGFILE);time_t prev_time = time(NULL);//int oldx = 0;int oldy = 0;char positionText[100] = { 0 };sprintf(positionText, "防锁屏进程已启动,程序将在无鼠标移动情况下每隔%d秒模拟一次键盘操作", Job_TIME);WriteToLog(positionText);while (1){    POINT p;    GetCursorPos(&p);//获取鼠标坐标    int x = p.x, y = p.y;//返回鼠标的坐标    time_t now_time = time(NULL);    if (x == oldx && y == oldy)    {        int stay_seconds = int(now_time - prev_time);        if (stay_seconds >= Job_TIME)        {            prev_time = now_time;            keybd_event(VK_CAPITAL, (BYTE)0, 0, 0);            keybd_event(VK_CAPITAL, (BYTE)0, KEYEVENTF_KEYUP, 0);            WriteToLog("模拟点击CapsLk,切换大小写");            //释放锁 让子线程去恢复win键状态            ReleaseMutex(hMutex);            Sleep(Restore_TIME / 2);            WaitForSingleObject(hMutex, INFINITE);        }    }    else    {        //更新旧坐标 最后一次移动鼠标时间        oldx = x;        oldy = y;        prev_time = now_time;    }    int stay_seconds = int(now_time - prev_time);    char mousemoved[100] = { 0 };    sprintf(mousemoved, "鼠标%d秒未移动", stay_seconds);    WriteToLog(mousemoved);//打印坐标    char positionText[100] = { 0 };    sprintf(positionText, "当前鼠标位置(%d,%d)", x, y);    WriteToLog(positionText);//打印坐标    Sleep(SLEEP_TIME);}

子线程代码如下

void SimulationBehavior(){    keybd_event(VK_CAPITAL, (BYTE)0, 0, 0);    keybd_event(VK_CAPITAL, (BYTE)0, KEYEVENTF_KEYUP, 0);}DWORD WINAPI RestoreWinState(LPVOID lvParamter){    while (true)    {        WaitForSingleObject(hMutex, INFINITE);        Sleep(Restore_TIME);        SimulationBehavior();        ReleaseMutex(hMutex);    }    return 0;}

主子线程使用一个全局的信号量来进行同步

四、demo下载

需要C++python代码的同学到csdn下载:

博客园地址:

简书地址:


转载声明:本站文章无特别说明,皆为原创,版权所有,转载请注明: or


你可能感兴趣的文章
Uva 1347,旅行
查看>>
是机遇还是挑战?---浅谈谷歌收购摩托罗拉移动
查看>>
13.段落排版--缩进
查看>>
(转载)高速ADC的关键指标:量化误差、offset/gain error、DNL、INL、ENOB、分辨率、RMS、SFDR、THD、SINAD、dBFS、TWO-TONE IMD...
查看>>
Git
查看>>
Jmeter启动闪退
查看>>
【阿里面试题】Java中的类及方法的加载顺序
查看>>
LeetCode OJ:Copy List with Random Pointer(复制存在随机链接的链表)
查看>>
Oracle存储过程、函数、包加密wrap
查看>>
BlinkToRadio 两个节点通信
查看>>
RCP开发小技巧(一)
查看>>
微软雅黑的问题(for silverlight)
查看>>
Oracle函数大全
查看>>
mysql 常用操作语句
查看>>
ArcGIS api for JavaScript 3.27 按需显示需要的图层
查看>>
Java实现发邮件功能
查看>>
强制开启android webview debug模式使用Chrome inspect
查看>>
win8 解析json数据模板 XMl解析数据
查看>>
项目总结26:java调用webservice接口(asmx)
查看>>
VS2013导入密钥出错:找不到解密的证书和私钥
查看>>