c++版本(轉(zhuǎn)載):
今天在網(wǎng)上淘到Intel匯編語言程序設(shè)計(jì)(第四版)的電子書,可惜不是pdf格式的,因此我想把它轉(zhuǎn)成pdf格式。利用它自帶的閱讀器WinDjView-0.4.1.exe可以對(duì)此電子書進(jìn)行閱讀,但不能打印輸出到pdf文檔。但是我發(fā)現(xiàn),在每頁上點(diǎn)右鍵,會(huì)有菜單彈出,其中有“導(dǎo)出頁面選項(xiàng)(E)”,選中進(jìn)入后,會(huì)彈出保存對(duì)話框,它只能保存為位圖文件,并且?guī)湍惆次募撁婷?,比如第一頁命名為“p0001.bmp”,繼續(xù)確定后,我們就可以把當(dāng)前頁的文件保存為bmp格式了。這樣,我們只要把每頁都導(dǎo)出為bmp格式,就可以選中全部bmp文件,右鍵點(diǎn)出pdf的“在adobe acrobat中合并”的選項(xiàng),在adobe acrobat中轉(zhuǎn)成pdf格式了。
但是要手工地導(dǎo)出500多頁的文件,會(huì)累死人的。。因此我考慮用程序模擬鼠標(biāo)和鍵盤操作的方法來解決。
重新分析上面的操作,主要有這么幾步:
(1) 在頁面上點(diǎn)右鍵,按'E’鍵(菜單上注明'E’是快捷鍵)
(2) 這時(shí)候彈出保存對(duì)話框,因?yàn)槲募摮绦蛞呀?jīng)根據(jù)頁面為我們默認(rèn)設(shè)好了,所以直接點(diǎn)回車確認(rèn)就可以了。
(3) 轉(zhuǎn)到下一頁,查看程序的“視圖”菜單發(fā)現(xiàn),有一個(gè)“跳轉(zhuǎn)”-“下一頁”的選項(xiàng),快捷鍵是Ctrl+PageDown,因此只要再按下Ctrl+PageDown即可。
(4) 重復(fù)(1)直到全部操作結(jié)束。
程序如下:
//此程序用于模擬鼠標(biāo)和鍵盤操作。
#include<windows.h>
int main()
{
Sleep(3000);//留3秒用于我們把鼠標(biāo)移到文檔上
for(int i=1;i<567;i++)
{
//模擬右鍵按下彈起
mouse_event(MOUSEEVENTF_RIGHTDOWN,0, 0, 0, 0);
mouse_event(MOUSEEVENTF_RIGHTUP,0, 0, 0, 0);
//模擬按下'E'鍵
keybd_event('E',(BYTE)0, 0 ,0);
keybd_event('E', (BYTE)0, KEYEVENTF_KEYUP,0);
Sleep(50);
//模擬按下回車,對(duì)應(yīng)確定保存
keybd_event(VK_RETURN, 0, 0 ,0);
keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP,0);
Sleep(100);//等待保存
//模擬按下ctrl+PageDown鍵,對(duì)應(yīng)翻頁
keybd_event(VK_CONTROL, (BYTE)0, 0 ,0);
keybd_event(VK_NEXT,(BYTE)0, 0 ,0);
keybd_event(VK_NEXT, (BYTE)0, KEYEVENTF_KEYUP,0);
keybd_event(VK_CONTROL, (BYTE)0, KEYEVENTF_KEYUP,0);
Sleep(50);//等待翻頁
}
return 0;
}
如何模擬鍵盤操作(VB版本)
這年頭,在這個(gè)論壇里面已經(jīng)沒有什么技術(shù)貼了...呵呵~發(fā)一篇驚天地,泣鬼神的帖子.當(dāng)然這個(gè)只是模擬鍵盤的終極模擬.
呵呵~ 鍵盤是我們使用計(jì)算機(jī)的一個(gè)很重要的輸入設(shè)備了,即使在鼠標(biāo)大行其道的今天,很多程序依然離不開鍵盤來操作。但是有時(shí)候,一些重復(fù)性的,很繁瑣的鍵盤操作總會(huì)讓人疲憊,于是就有了用程序來代替人們按鍵的方法,這樣可以把很多重復(fù)性的鍵盤操作交給程序來模擬,省了很多精力,按鍵精靈就是這樣的一個(gè)軟件。
那么我們?cè)鯓硬拍苡肰B來寫一個(gè)程序,達(dá)到與按鍵精靈類似的功能呢?那就讓我們來先了解一下windows中響應(yīng)鍵盤事件的機(jī)制。 當(dāng)用戶按下鍵盤上的一個(gè)鍵時(shí),鍵盤內(nèi)的芯片會(huì)與游戲兼容性到這個(gè)動(dòng)作,并把這個(gè)信號(hào)傳送到計(jì)算機(jī)。如何區(qū)別是哪一個(gè)鍵被按下了呢?鍵盤上的所有按鍵都有一個(gè)編碼,稱作鍵盤掃描碼。當(dāng)你按下一個(gè)鍵時(shí),這個(gè)鍵的掃描碼就被傳給系統(tǒng)。掃描碼是跟具體的硬件相關(guān)的,同一個(gè)鍵,在不同鍵盤上的掃描碼有可能不同。鍵盤控制器就是將這個(gè)掃描碼傳給計(jì)算機(jī),然后交給鍵盤驅(qū)動(dòng)程序。
鍵盤驅(qū)動(dòng)程序會(huì)完成相關(guān)的工作,并把這個(gè)掃描碼轉(zhuǎn)換為鍵盤虛擬碼。什么是虛擬碼呢?因?yàn)閽呙璐a與硬件相關(guān),不具有通用性,為了統(tǒng)一鍵盤上所有鍵的編碼,于是就提出了虛擬碼概念。無論什么鍵盤,同一個(gè)按鍵的虛擬碼總是相同的,這樣程序就可以識(shí)別了。簡單點(diǎn)說,虛擬碼就是我們經(jīng)??梢钥吹降南馰K_A,VK_B這樣的常數(shù),比如鍵A的虛擬碼是65,寫成16進(jìn)制就是&H41,注意,人們經(jīng)常用16進(jìn)制來表示虛擬碼。當(dāng)鍵盤驅(qū)動(dòng)程序把掃描碼轉(zhuǎn)換為虛擬碼后,會(huì)把這個(gè)鍵盤操作的掃描碼和虛擬碼還有其它信息一起傳遞給操作系統(tǒng)。然后操作系統(tǒng)則會(huì)把這些信息封裝在一個(gè)消息中,并把這個(gè)鍵盤消息插入到消息列隊(duì)。
最后,要是不出意外的話,這個(gè)鍵盤消息最終會(huì)被送到當(dāng)前的活動(dòng)窗口那里,活動(dòng)窗口所在的應(yīng)用程序接收到這個(gè)消息后,就知道鍵盤上哪個(gè)鍵被按下,也就可以決定該作出什么響應(yīng)給用戶了。這個(gè)過程可以簡單的如下表示:用戶按下按鍵-----鍵盤驅(qū)動(dòng)程序?qū)⒋耸录鬟f給操作系統(tǒng)-----操作系統(tǒng)將鍵盤事件插入消息隊(duì)列-----鍵盤消息被發(fā)送到當(dāng)前活動(dòng)窗口明白了這個(gè)過程,我們就可以編程實(shí)現(xiàn)在其中的某個(gè)環(huán)節(jié)來模擬鍵盤操作了。在VB中,有多種方法可以實(shí)現(xiàn)鍵盤模擬,我們就介紹幾種比較典型的。
1.局部級(jí)模擬 從上面的流程可以看出,鍵盤事件是最終被送到活動(dòng)窗口,然后才引起目標(biāo)程序響應(yīng)的。那么最直接的模擬方法就是:直接偽造一個(gè)鍵盤消息發(fā)給目標(biāo)程序。哈哈,這實(shí)在是很簡單,windows提供了幾個(gè)這樣的API函數(shù)可以實(shí)現(xiàn)直接向目標(biāo)程序發(fā)送消息的功能,常用的有SendMessage和PostMessage,它們的區(qū)別是PostMessage函數(shù)直接把消息仍給目標(biāo)程序就不管了,而SendMessage把消息發(fā)出去后,還要等待目標(biāo)程序返回些什么東西才好。
這里要注意的是,模擬鍵盤消息一定要用PostMessage函數(shù)才好,用SendMessage是不正確的(因?yàn)槟M鍵盤消息是不需要返回值的,不然目標(biāo)程序會(huì)沒反應(yīng)),切記切記!PostMessage函數(shù)的VB聲明如下: Declare Function PostMessage Lib "user32" Alias "ostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long 參數(shù)hwnd 是你要發(fā)送消息的目標(biāo)程序上某個(gè)控件的句柄,參數(shù)wMsg 是消息的類型,表示你要發(fā)送什么樣的消息,最后wParam 和lParam 這兩個(gè)參數(shù)是隨消息附加的數(shù)據(jù),具體內(nèi)容要由消息決定。再來看看wMsg 這個(gè)參數(shù),要模擬按鍵就靠這個(gè)了。
鍵盤消息常用的有如下幾個(gè): WM_KEYDOWN 表示一個(gè)普通鍵被按下 WM_KEYUP 表示一個(gè)普通鍵被釋放 WM_SYSKEYDOWN 表示一個(gè)系統(tǒng)鍵被按下,比如Alt鍵 WM_SYSKEYUP 表示一個(gè)系統(tǒng)鍵被釋放,比如Alt鍵如果你確定要發(fā)送以上幾個(gè)鍵盤消息,那么再來看看如何確定鍵盤消息中的wParam 和lParam 這兩個(gè)參數(shù)。在一個(gè)鍵盤消息中,wParam 參數(shù)的含義較簡單,它表示你要發(fā)送的鍵盤事件的按鍵虛擬碼,比如你要對(duì)目標(biāo)程序模擬按下A鍵,那么wParam 參數(shù)的值就設(shè)為VK_A ,至于lParam 這個(gè)參數(shù)就比較復(fù)雜了,因?yàn)樗硕鄠€(gè)信息,一般可以把它設(shè)為0,但是如果你想要你的模擬更真實(shí)一些,那么建議你還是設(shè)置一下這個(gè)參數(shù)。那么我們就詳細(xì)了解一下lParam 吧。
lParam 是一個(gè)long類型的參數(shù),它在內(nèi)存中占4個(gè)字節(jié),寫成二進(jìn)制就是00000000 00000000 00000000 00000000 一共是32位,我們從右向左數(shù),假設(shè)最右邊那位為第0位(注意是從0而不是從1開始計(jì)數(shù)),最左邊的就是第31位,那么該參數(shù)的的0-15位表示鍵的發(fā)送次數(shù)等擴(kuò)展信息,16-23位為按鍵的掃描碼,24-31位表示是按下鍵還是釋放鍵。
大家一般習(xí)慣寫成16進(jìn)制的,那么就應(yīng)該是&H00 00 00 00 ,第0-15位一般為&H0001,如果是按下鍵,那么24-31位為&H00,釋放鍵則為&HC0,那么16-23位的掃描碼怎么會(huì)得呢?這需要用到一個(gè)API函數(shù)MapVirtualKey,這個(gè)函數(shù)可以將虛擬碼轉(zhuǎn)換為掃描碼,或?qū)呙璐a轉(zhuǎn)換為虛擬碼,還可以把虛擬碼轉(zhuǎn)換為對(duì)應(yīng)字符的ASCII碼。
它的VB聲明如下: Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long 參數(shù)wCode 表示待轉(zhuǎn)換的碼,參數(shù)wMapType 表示從什么轉(zhuǎn)換為什么,如果是虛擬碼轉(zhuǎn)掃描碼,則wMapType 設(shè)置為0,如果是虛擬掃描碼轉(zhuǎn)虛擬碼,則wMapType 設(shè)置為1,如果是虛擬碼轉(zhuǎn)ASCII碼,則wMapType 設(shè)置為2.相信有了這些,我們就可以構(gòu)造鍵盤事件的lParam參數(shù)了。
下面給出一個(gè)構(gòu)造lParam參數(shù)的函數(shù): Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long Function MakeKeyLparam(ByVal VirtualKey As Long, ByVal flag As Long) As Long '參數(shù)VirtualKey表示按鍵虛擬碼,flag表示是按下鍵還是釋放鍵,
用WM_KEYDOWN和WM_KEYUP這兩個(gè)常數(shù)表示 Dim s As String Dim Firstbyte As String 'lparam參數(shù)的24-31位 If flag = WM_KEYDOWN Then '如果是按下鍵 Firstbyte = "00" Else Firstbyte = "C0" '如果是釋放鍵 End If Dim Scancode As Long '獲得鍵的掃描碼 Scancode = MapVirtualKey(VirtualKey, 0) Dim Secondbyte As String 'lparam參數(shù)的16-23位,即虛擬鍵掃描碼 Secondbyte = Right("00" & Hex(Scancode), 2) s = Firstbyte & Secondbyte & "0001" '0001為lparam參數(shù)的0-15位,即發(fā)送次數(shù)和其它擴(kuò)展信息 MakeKeyLparam = Val("&H" & s) End Function 這個(gè)函數(shù)像這樣調(diào)用,比如按下A鍵,那么lParam=MakeKeyLparam(VK_A,WM_KEYDOWN) ,很簡單吧。
值得注意的是,即使你發(fā)送消息時(shí)設(shè)置了lParam參數(shù)的值,但是系統(tǒng)在傳遞消息時(shí)仍然可能會(huì)根據(jù)當(dāng)時(shí)的情況重新設(shè)置該參數(shù),那么目標(biāo)程序收到的消息中l(wèi)Param的值可能會(huì)和你發(fā)送時(shí)的有所不同。所以,如果你很懶的話,還是直接把它設(shè)為0吧,對(duì)大多數(shù)程序不會(huì)有影響的,呵呵。 好了,做完以上的事情,現(xiàn)在我們可以向目標(biāo)程序發(fā)送鍵盤消息了。首先取得目標(biāo)程序接受這個(gè)消息的控件的句柄,比如目標(biāo)句柄是12345,那么我們來對(duì)目標(biāo)模擬按下并釋放A鍵,像這樣:(為了簡單起見,lParam這個(gè)參數(shù)就不構(gòu)造了,直接傳0) PostMessage 12345,WM_KEYDOWN,VK_A,0& '按下A鍵 PostMessage 12345,WM_UP,VK_A,0& '釋放A鍵好了,一次按鍵就完成了。
現(xiàn)在你可以迫不及待的打開記事本做實(shí)驗(yàn),先用FindWindowEx這類API函數(shù)找到記事本程序的句柄,再向它發(fā)送鍵盤消息,期望記事本里能詭異的自動(dòng)出現(xiàn)字符??墒悄泷R上就是失望了,咦,怎么一點(diǎn)反應(yīng)也沒有?你欺騙感情啊~~~~~~~~~~55555555555555 不是的哦,接著往下看啊。一般目標(biāo)程序都會(huì)含有多個(gè)控件,并不是每個(gè)控件都會(huì)對(duì)鍵盤消息作出反應(yīng),只有把鍵盤消息發(fā)送給接受它的控件才會(huì)得到期望的反應(yīng)。那記事本來說,它的編輯框其實(shí)是個(gè)edit類,只有這個(gè)控件才對(duì)鍵盤事件有反應(yīng),如果只是把消息發(fā)給記事本的窗體,那是沒有用的?,F(xiàn)在你找出記事本那個(gè)編輯框的句柄,比如是54321,那么寫如下代碼: PostMessage 54321,WM_KEYDOWN,VK_F1,0& '按下F1鍵 PostMessage 54321,WM_UP,VK_F1,0& '釋放F1鍵怎么樣,是不是打開了記事本的“幫助”信息?
這說明目標(biāo)程序已經(jīng)收到了你發(fā)的消息,還不錯(cuò)吧~~~~~~~~ 可以馬上新問題就來了,你想模擬向記事本按下A這個(gè)鍵,好在記事本里自動(dòng)輸入字符,可是,沒有任何反應(yīng)!這是怎么一回事呢?原來,如果要向目標(biāo)程序發(fā)送字符,光靠WM_KEYDOWN和WM_UP這兩個(gè)事件還不行,還需要一個(gè)事件:WM_CHAR,這個(gè)消息表示一個(gè)字符,程序需靠它看來接受輸入的字符。一般只有A,B,C等這樣的按鍵才有WM_CHAR消息,別的鍵(比如方向鍵和功能鍵)是沒有這個(gè)消息的,WM_CHAR消息一般發(fā)生在WM_KEYDOWN消息之后。WM_CHAR消息的lParam參數(shù)的含義與其它鍵盤消息一樣,而它的wParam則表示相應(yīng)字符的ASCII編碼(可以輸入中文的哦^_^),現(xiàn)在你可以寫出一個(gè)完整的向記事本里自動(dòng)寫入字符的程序了,
下面是一個(gè)例子,并附有這些消息常數(shù)的具體值:
Declare Function PostMessage Lib "user32" Alias "ostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long Public Const WM_KEYDOWN = &H100 Public Const WM_KEYUP = &H101 Public Const WM_CHAR = &H102 Public Const VK_A = &H41 Function MakeKeyLparam(ByVal VirtualKey As Long, ByVal flag As Long) As Long Dim s As String Dim Firstbyte As String 'lparam參數(shù)的24-31位 If flag = WM_KEYDOWN Then '如果是按下鍵 Firstbyte = "00" Else Firstbyte = "C0"
'如果是釋放鍵 End If Dim Scancode As Long '獲得鍵的掃描碼 Scancode = MapVirtualKey(VirtualKey, 0) Dim Secondbyte As String 'lparam參數(shù)的16-23位,即虛擬鍵掃描碼 Secondbyte = Right("00" & Hex(Scancode), 2) s = Firstbyte & Secondbyte & "0001" '0001為lparam參數(shù)的0-15位,即發(fā)送次數(shù)和其它擴(kuò)展信息 MakeKeyLparam = Val("&H" & s) End Function Private Sub Form_Load() dim hwnd as long hwnd = XXXXXX 'XXXXX表示記事本編輯框的句柄 PostMessage hwnd,WM_KEYDOWN,VK_A,MakeKeyLparam(VK_A,WM_KEYDOWN) '按下A鍵 PostMessage hwnd,WM_CHAR,ASC("A"),MakeKeyLparam(VK_A,WM_KEYDOWN) '輸入字符A PostMessage hwnd,WM_UP,VK_A,MakeKeyLparam(VK_A,WM_UP) '釋放A鍵 End Sub 這就是通過局部鍵盤消息來模擬按鍵。這個(gè)方法有一個(gè)極大的好處,就是:它可以實(shí)現(xiàn)后臺(tái)按鍵,也就是說他對(duì)你的前臺(tái)操作不會(huì)有什么影響。比如,你可以用這個(gè)方法做個(gè)程序在游戲中模擬按鍵來不斷地執(zhí)行某些重復(fù)的操作,而你則一邊喝茶一邊與QQ上的MM們聊得火熱,它絲毫不會(huì)影響你的前臺(tái)操作。無論目標(biāo)程序是否獲得焦點(diǎn)都沒有影響,這就是后臺(tái)模擬按鍵的原理啦~~~~