close
文章出處

   很早以前寫了一個刷卡程序,功能是定時監控讀卡器,當發現有IC卡放到讀卡器上后,自動識別出卡號,然后帶著這個卡號搜索一個英文用戶名和卡號的對照表,最后把英文用戶名直接自動輸入到當前光標所在的位置。本來程序一直用得好好的,可是最近遇到了一個新問題——因為用戶名現在居然可以用中文了!所以這下麻煩大了……

   原先實現英文的自動輸入,用的是keybd_event函數,直接模擬鍵盤事件。但是要輸入中文,貌似沒有輸入法還是不行,難道還要我先用keybd_event調出輸入法,然后輸入拼音?這個思路想想就很恐怖,所以趕緊就上網搜解決方案去了。可是搜了一圈下來,只有寥寥幾篇提到解決方案,雖然網上搜索結果眾多,但是基本上就是這幾個版本貼來貼去,浪費了我好多時間。

   不幸的事情還在后頭,雖然有人提到SendInput函數可以輸入中文,但是語焉不詳,按照他提供的點滴的代碼,我死活就是沒有試出來。所以最后中文搜索的結果,除了認識了這個SendInput函數之外,沒有更多的收獲。后來不死心,換了英文搜索,還真找到了一個比較接近我需求的,老外寫的VB版本的SendInput的例子,試驗了以下,果然可以輸入中文。大喜之下,決定花點時間研究一下人家的源代碼,然后寫一個VC的版本。

   摸索了兩天之后,發現實現中文自動輸入還真不難,因為SendInput確實支持,所以終于可以不用輸入法了,萬幸。特意整理了幾個函數,共享一下。

   首先是,頭文件必須包含以下兩個:
#include <winable.h>
#include <atlconv.h>

前者是SendInput函數要用到,后者是字符串轉換的時候要用到。


void SendAscii(wchar_t data, BOOL shift)
{
 INPUT input[2];
 memset(input, 0, 2 * sizeof(INPUT));
 
 if (shift)
 {
   input[0].type = INPUT_KEYBOARD;
   input[0].ki.wVk = VK_SHIFT;
   SendInput(1, input, sizeof(INPUT));
 }

 input[0].type = INPUT_KEYBOARD;
 input[0].ki.wVk = data;

 input[1].type = INPUT_KEYBOARD;
 input[1].ki.wVk = data;
 input[1].ki.dwFlags = KEYEVENTF_KEYUP;

 SendInput(2, input, sizeof(INPUT));

 if (shift)
 {
   input[0].type = INPUT_KEYBOARD;
   input[0].ki.wVk = VK_SHIFT;
   input[0].ki.dwFlags = KEYEVENTF_KEYUP;
   SendInput(1, input, sizeof(INPUT));  
 }
}


void SendUnicode(wchar_t data)
{
 INPUT input[2];
 memset(input, 0, 2 * sizeof(INPUT));
 
 input[0].type = INPUT_KEYBOARD;
 input[0].ki.wVk = 0;
 input[0].ki.wScan = data;
 input[0].ki.dwFlags = 0x4;//KEYEVENTF_UNICODE;
 
 input[1].type = INPUT_KEYBOARD;
 input[1].ki.wVk = 0;
 input[1].ki.wScan = data;
 input[1].ki.dwFlags = KEYEVENTF_KEYUP | 0x4;//KEYEVENTF_UNICODE;
 
 SendInput(2, input, sizeof(INPUT));
}

//為方便使用,下面這個函數包裝了前兩個函數。

void SendKeys(CString msg)
{
 short vk;
 BOOL shift;

 USES_CONVERSION;
 wchar_t* data = T2W(msg.GetBuffer(0));
 int len = wcslen(data);

 for(int i=0;i<len;i++)
 {
   if (data[i]>=0 && data[i]<256) //ascii字符
   {
     vk = VkKeyScanW(data[i]);

     if (vk == -1)
     {
       SendUnicode(data[i]);
     }
     else
     {
       if (vk < 0)
       {
         vk = ~vk + 0x1;
       }
       
       shift = vk >> 8 & 0x1;
       
       if (GetKeyState(VK_CAPITAL) & 0x1)
       {
         if (data[i]>='a' && data[i]<='z' || data[i]>='A' && data[i]<='Z')
         {
           shift = !shift;
         }
       }

       SendAscii(vk & 0xFF, shift);
     }
   }
   else //unicode字符
   {
     SendUnicode(data[i]);
   }
 }
}

直接調用SendKeys函數就可以在當前光標的位置自動輸入指定的字符串,下面的例子演示了如何自動打開記事本程序并輸入一段話:
void CSendInputDlg::OnTest()
{
 ShellExecute(NULL, NULL, "notepad.exe", NULL, NULL, SW_SHOWNORMAL);
 
 Sleep(500); //為了確保記事本程序打開完畢,稍等片刻

 CWnd *pWnd = FindWindow(NULL, "無標題 - 記事本");
 if (pWnd)
 {
   pWnd->SetForegroundWindow();
   SendKeys("我是sway,我愛中國!\nI love China!\nEmail: \b\b");
 }
}


不含病毒。www.avast.com
arrow
arrow
    全站熱搜

    AutoPoster 發表在 痞客邦 留言(0) 人氣()