我需要从串口读出命令字符,发送消息给自己编写的程序,来模拟键盘按键,代替键盘操作。比如发送一个字符A,就代表按下键盘上的<-键值。
我是用::PostMessage(?, WM_KEYDOWN, value, 0);可是第一个窗口句柄的值用哪一个呢???如果直接使用view窗口的句柄,就可以实现我要求的功能,但是我的程序中有许多窗口,怎么办呢?如果不用PostMessage(),那么该怎样做呢?高手帮忙,任务非常急。

解决方案 »

  1.   

    可以用FindWindow来找到目标窗口
      

  2.   

    在OnKeyDown()中eg:
    switch(wParam)
    {
        case 'A':
           wParam = VT_LEFT;
           break;
       .......
    }
      

  3.   

    楼上的不要这样说,
    我需要给所有的窗口发送消息,
    我找到一种方法,使用keybd_event,好像好使。
    多谢各位
      

  4.   

    模拟键盘按键 自动输入文字   键盘对于每个操作电脑的人员来说是最熟悉不过的了。键盘上的按键可分为两类: 按下后会在电脑的输入窗口上出现对应字符的按键,如字母键和数字键等,我们称之为字符键;按下后虽然看不到字符但会产生控制作用的按键,如回车键、光标键等,我们称之为控制键。对于程序员来说,键盘上的每个按键都一样,无非是不同按键产生的键盘扫描码不同。在不同的操作系统下,键盘扫描码常常被转换为不同的编码以方便应用程序调用,比如在DOS系统下的ASCII码,在Windows系统下的虚拟键盘码等等。 有时我们希望能以程序的方式模拟键盘按键,以达到自动输入文字或者控制操作的目的。在DOS系统下通常使用中断调用,产生键盘的扫描码的方法来实现。在Windows 系统下,由于Windows本身的一些限制和特点,一般不直接使用中断调用。了解一点Windows编程的朋友应该知道, Windows系统是通过消息的传递(或称事件的发生)来控制各个应用程序的执行和数据通信的。例如:应用程序打开和关闭会产生相应的窗口消息,鼠标的移动、点击动作会产生相应的鼠标消息,同样键盘的按下、弹起也会产生相应的键盘消息。那么如果用程序产生键盘消息,也就达到了模拟键盘按键的目的。 有了这样的思路,我们现在就来实验一下。首先要知道在Windows系统中与键盘按键相关的消息有:WM_KEYDOWN、WM_KEYUP、 WM_SYSKEYDOWN、WM_SYSKEYUP、WM_CHAR等。其中,WM_KEYDOWN为键按下,WM_KEYUP为键弹起,WM_SYSKEYDOWN为系统键按下,WM_SYSKEYUP为系统键弹起,WM_CHAR为按键对应的字符。要模拟键盘产生键盘消息,我们就发送一条键盘消息给指定窗口。比如要模拟一个字母键“A”,可以这样:PostMessage(hWnd, WM_CHAR, 'A', 0); 模拟按一个回车:PostMessage(hWnd, WM_KEYDOWN, VK_RETURN, 0)。这里的关键问题是要确定窗口句柄(hWnd),使用GetFocus()函数可以得到键盘光标所在窗口句柄,但该函数只能得到当前进程内的窗口句柄。如果要得到其他应用程序的键盘光标所在窗口句柄,需要调用 AttachThreadInput()函数。该函数的作用就是将其他窗口线程的输入附加到本窗口线程的输入操作中,这样就可以调用GetFocus()函数得到其他窗口的句柄了。与2001年第24期程序谷刊登的《如何写一个聊天辅助程序》一文中作者使用ChildWindowFromPointEx的方法相比,使用AttachThreadInput似乎更能够使键盘模拟具有通用性。 
    AttachThreadInput()函数的原形如下: BOOL AttachThreadInput( DWORD idAttach, // 需要附加的线程ID DWORD idAttachTo, // 附加到的线程ID BOOL fAttach // true 附加 false 取消 ); 函数使用的过程大致如下: HWND hWnd; hWnd = GetForegroundWindow(); // 得到当前窗口 if (hWnd == Form1->Handle) return; // 排除程序本身的窗口 DWORD FormThreadID = GetCurrentThreadId(); // 本程序的线程ID // 当前窗口的线程ID DWORD CWndThreadID = GetWindowThreadProcessId(hWnd, NULL); // 附加输入线程 AttachThreadInput(CWndThreadID, FormThreadID, true); // 得到当前键盘光标所在的窗口 hWnd = GetFocus(); // 取消附加的输入线程 AttachThreadInput(CWndThreadID, FormThreadID, false); hWnd就是当前键盘光标所在的窗口句柄。另外,经过测试发现,在Windows2000系统下发送字符消息(WM_CHAR)时,如果字符是一个汉字,则该字符对应的虚拟键盘码高位不为0,这样得到的字符就不正确。解决办法是做一个“与”运算: ch & 0xFF就可以了。 下面又到了给出例程的时间了。例程“刷刷刷”能够在键盘光标所在的文本输入框中自动输入文字(中文、英文、数字),程序使用C++ Builder 5开发。首先运行C++ Builder并新建工程。接着,将窗体Form1的边框样式(BorderStyle)改为对话框(bsDialog),并放置相应控件如图所示,其中SS_Text是一个用于输入文本的TComboBox控件,当然,你可以在设计阶段预先向控件中输入一些常用文本,以便程序运行后可以直接选用; txtTimes和txtDelay为TEdit控件,分别用于控制发送文本的次数和间隔时间;chkAutoWrap和chkAutoNumber为TCheckBox控件,决定是否在每一行发送文本后面自动回车或自动加记数编号; 以上控件包含在Panel1(TPanel控件)中; Timer1用于控制循环发送和时间间隔。 下面是程序清单: //-------------------------------------------- #include #pragma hdrstop #include "Unit1.h" //-------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" 
    int nTotalTimes, // 发送本文的总次数 nTimes; // 已经发送的次数 TForm1 *Form1; //-------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //-------------------------------------------- void __fastcall TForm1::btnStartClick(TObject *Sender) // 开始刷屏 { if (SS_Text->Text.IsEmpty()) { // 文本不能为空 ShowMessage("请输入刷刷文本!"); SS_Text->SetFocus(); return; } __try { // Timer1->Interval取值为n秒(最小为50毫秒) int Interval = StrToInt(txtDelay->Text); Timer1->Interval = (Interval > 0) ? Interval * 1000 : 50; // nTotalTimes取值为n次(最小为0次) nTotalTimes = StrToInt(txtTimes->Text); if (nTotalTimes < 0) nTotalTimes = 0; nTimes = 0; Timer1->Enabled = true; } __except(EXCEPTION_EXECUTE_HANDLER) { ShowMessage("请输入数值类型数据!"); return; } btnStart->Enabled = false; btnStop->Enabled = true; Panel1->Enabled = false; Application->Minimize(); // 最小化刷刷窗口 } //-------------------------------------------- 
    void __fastcall TForm1::btnStopClick(TObject *Sender)// 停止刷屏 { Timer1->Enabled = false; btnStart->Enabled = true; btnStop->Enabled = false; Panel1->Enabled = true; } //-------------------------------------------- void __fastcall TForm1::Timer1Timer(TObject *Sender) { // 现刷屏nTimes次,到nTotalTimes次后完成。 if (nTimes == nTotalTimes) { btnStopClick(Sender); return; } 
    HWND hWnd; hWnd = GetForegroundWindow(); // 得到当前窗口 if (hWnd == Form1->Handle) return; // 不需要程序本身的窗口 
    DWORD FormThreadID = GetCurrentThreadId(); DWORD CWndThreadID = GetWindowThreadProcessId(hWnd, NULL); 
    // 附加输入线程 AttachThreadInput(CWndThreadID, FormThreadID, true); hWnd = GetFocus(); // 得到当前键盘光标所在的窗口 AttachThreadInput(CWndThreadID, FormThreadID, false); // 取消 if (hWnd == NULL) return; 
    nTimes++; for (int i = 1; i <= SS_Text->Text.Length(); i++) { // 模拟键盘按键输入文本 PostMessage(hWnd, WM_CHAR, (WPARAM)(SS_Text->Text[i] & 0xFF), 0); } 
    if (chkAutoNumber->Checked) { // 自动编号 AnsiString Lines = IntToStr(nTimes); for (int j = 1; j <= Lines.Length(); j++) PostMessage(hWnd, WM_CHAR, (WPARAM)(Lines[j]), 0); } if (chkAutoWrap->Checked) // 自动回车 PostMessage(hWnd, WM_KEYDOWN, VK_RETURN, 0); } //--------------------------------------------- 本程序在Windows 2000 + C++ Builder 5下编译通过
    源程序下载地址是:http://www.cfan.net.cn/qikan/ cxg/0206mnj.zip。 
      

  5.   

    // 模拟按下一个键   keybd_event( VK_CAPITAL,//键名 大写锁定   0x45,   KEYEVENTF_EXTENDEDKEY | 0,   0 );   // 模拟放开一个键   keybd_event( VK_CAPITAL,   0x45,  KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,   0);   }
      

  6.   

    上面的是C++ Builder的,原理是一样的,再看看下面的:
    WINDOWS键盘事件的挂钩监控原理及其应用技术
    WINDOW的消息处理机制为了能在应用程序中监控系统的各种事件消息,提供了挂接
    各种反调函数(HOOK)的功能。这种挂钩函数(HOOK)类似扩充中断驱动程序,挂钩上
    可以挂接多个反调函数构成一个挂接函数链。系统产生的各种消息首先被送到各种
    挂接函数,挂接函数根据各自的功能对消息进行监视、修改和控制等,然后交还控
    制权或将消息传递给下一个挂接函数以致最终达到窗口函数。WINDOW系统的这种反
    调函数挂接方法虽然会略加影响到系统的运行效率,但在很多场合下是非常有用
    的,通过合理有效地利用键盘事件的挂钩函数监控机制可以达到预想不到的良好效
    果。一、在WINDOWS键盘事件上挂接监控函数的方法
    WINDOW下可进行挂接的过滤函数包括11种:
    WH_CALLWNDPROC 窗口函数的过滤函数
    WH_CBT 计算机培训过滤函数
    WH_DEBUG 调试过滤函数
    WH_GETMESSAGE 获取消息过滤函数
    WH_HARDWARE 硬件消息过滤函数
    WH_JOURNALPLAYBACK 消息重放过滤函数
    WH_JOURNALRECORD 消息记录过滤函数
    WH_MOUSE 鼠标过滤函数
    WH_MSGFILTER 消息过滤函数
    WH_SYSMSGFILTER 系统消息过滤函数
    WH_KEYBOARD 键盘过滤函数
    其中键盘过滤函数是最常用最有用的过滤函数类型,不管是哪一种类型的过滤函
    数,其挂接的基本方法都是相同的。
    WINDOW调用挂接的反调函数时总是先调用挂接链首的那个函数,因此必须将键盘挂
    钩函数利用函数SetWindowsHookEx()将其挂接在函数链首。至于消息是否传递给函
    数链的下一个函数是由每个具体函数功能确定的,如果消息需要传统给下一个函
    数,可调用API函数的CallNextHookEx()来实现,如果不传递直接返回即可。
    挂接函数可以是用来监控所有线程消息的全局性函数,也可以是单独监控某一线程
    的局部性函数。如果挂接函数是局部函数,可以将它放到一个.DLL动态链接库中,
    也可以放在一个局部模块中;如果挂接函数是全局的,那么必须将其放在一个.DLL
    动态链接库中。挂接函数必须严格按照下述格式进行声明,以键盘挂钩函数为例:
    int FAR PASCAL KeyboardProc(
    int nCode,WORD wParam,DWORD lParam)
    其中KeyboardProc为定义挂接函数名,该函数必须在模块定义文件中利用EXPORTS命
    令进行说明;nCode决定挂接函数是否对当前消息进行处理;wParam和lParam为具体
    的消息内容。二、键盘事件挂接函数的安装与下载
    在程序中可以利用函数SetWindowsHookEx()来挂接过滤函数,在挂接函数时必须指
    出该挂接函数的类型、函数的入口地址以及函数是全局性的还是局部性的,挂接函
    数的具体调用格式如下:
    SetWindowsHookEx(iType,iProc,hInst,iCode)
    其中iType为挂接函数类型,键盘类型为WH_KEYBOARD,iProc为挂接函数地址,hInst
    为挂接函数链接库实例句柄,iCode为监控代码-0表示全局性函数。
    如果挂接函数需要将消息传递给下一个过滤函数,则在该挂接函数返回前还需要调
    用一次CallNextHookEx()函数,当需要下载挂接函数时,只要调用一次
    UnhookWindowsHookEx(iProc)函数即可实现。
    如果函数是全局性的,那么它必须放在一个.DLL动态链接库中,这时该函数调用方
    法可以和其它普通.DLL函数一样有三种:
    1.在DEF定义文件中直接用函数名或序号说明:
    EXPORTS
    WEP @1 RESIDENTNAME
    InitHooksDll @2
    InstallFilter @3
    KeyboardProc @4
    用序号说明格式为:链接库名.函数名(如本例中说明方法为KEYDLL.KeyboardProc)。
    2.在应用程序中利用函数直接调用:
    首先在应用程序中利用LoadLibrary(LPSTR "链接库名")将动态链接库装入,并取得
    装载库模块句柄hInst,然后直接利用GetProcAddress(HINSTANCE hInst,LPSTR "函
    数过程名")获取函数地址,然后直接调用该地址即可,程序结束前利用函数
    FreeLibrary( )释放装入的动态链接库即可。
    3.利用输入库.LIB方法
    利用IMPLIB.EXE程序在建立动态链接库的同时建立相应的输入库.LIB,然后直接在
    项目文件中增加该输入库。三、WINDOWS挂钩监控函数的实现步骤
    WINDOWS挂钩函数只有放在动态链接库DLL中才能实现所有事件的监控功能。在.DLL
    中形成挂钩监控函数基本方法及其基本结构如下:
    1、首先声明DLL中的变量和过程;
    2、然后编制DLL主模块LibMain(),建立模块实例;
    3、建立系统退出DLL机制WEP()函数;
    4、完成DLL初始化函数InitHooksDll(),传递主窗口程序句柄;
    5、编制挂钩安装和下载函数InstallFilter();
    6、编制挂钩函数KeyboardProc(),在其中设置监控功能,并确定继续调下一个钩
    子函数还是直接返回WINDOWS应用程序。
    7、在WINDOWS主程序中需要初始化DLL并安装相应挂钩函数,由挂接的钩子函数负
    责与主程序通信;
    8、在不需要监控时由下载功能卸掉挂接函数。
    四、WINDOWS下键盘挂钩监控函数的应用技术目前标准的104 键盘上都有两个特殊的按键,其上分别用WINDOW程序徽标和鼠标下
    拉列表标识,本文暂且分别称为Micro左键和Micro右键,前者用来模拟鼠标左键激
    活开始菜单,后者用来模拟鼠标右键激活属性菜单。这两个特殊按键只有在按下后
    立即抬起即完成 CLICK过程才能实现其功能,并且没有和其它按键进行组合使用。
    由于WINDOWS 系统中将按键划分得更加详细,使应用程序中很难灵活定义自己的专
    用快捷键,比如在开发.IME等应用程序时很难找到不与WORD8.0等其它应用程序冲突
    的功能按键。如果将标准104键盘中的这两个特殊按键作为模拟CTRL和ALT 等专用按
    键,使其和其它按键组合,就可以在自己的应用程序中自由地设置专用功能键,为
    应用程序实现各种功能快捷键提供灵活性。正常情况下WINDOWS 键盘事件驱动程序
    并不将这两个按键的消息进行正常解释,这就必须利用键盘事件的挂钩监控函数来
    实现其特定的功能。其方法如下:
    1、首先编制如下一个简单动态链接库程序,并编译成DLL文件。
    #include "windows.h"
    int FAR PASCAL LibMain(HANDLE hModule,UINT wDataSeg,
    UINT cbHeapSize,LPSTR lpszCmdLine);
    int WINAPI WEP(int bSystemExit);
    int WINAPI InitHooksDll(HWND hwndMainWindow);
    int WINAPI InstallFilter(BOOL nCode);
    LRESULT CALLBACK KeyHook(int nCode,WORD wParam,DWORD lParam);
    static HANDLE hInstance; // 全局句柄
    static HWND hWndMain; // 主窗口句柄
    static int InitCalled=0; // 初始化标志
    static HHOOK hKeyHook;
    FARPROC lpfnKeyHook=(FARPROC)KeyHook;
    BOOL HookStates=FALSE;
    int FAR PASCAL LibMain(
    HANDLE hModule,
    UINT wDataSeg,
    UINT cbHeapSize,
    LPSTR lpszCmdLine)
    {
    if (cbHeapSize!=0) UnlockData(0);
    hInstance = hModule;
    return 1;
    }
    int WINAPI WEP (int bSystemExit)
    { return 1;}
    int WINAPI InitHooksDll(HWND hwndMainWindow)
    { hWndMain = hwndMainWindow;
    InitCalled = 1;
    return (0);
    }
    int WINAPI InstallFilter(BOOL nCode)
    { if (InitCalled==0) return (-1);
    if (nCode==TRUE) {
    hKeyHook=SetWindowsHookEx(WH_KEYBOARD,
    (HOOKPROC)lpfnKeyHook,hInstance,0);
    HookStates=TRUE;
    } else {
    UnhookWindowsHookEx(hKeyHook);
    HookStates=FALSE;
    }
    return(0);
    }
    LRESULT CALLBACK KeyHook(int nCode,WORD wParam,DWORD lParam)
    {
    static BOOL msflag=FALSE;
    if(nCode>=0) {
    if(HookStates==TRUE){
    if((wParam==0xff)|| //WIN3.X下按键值
    (wParam==0x5b)||(wParam==0x5c)){//WIN95下按键值
    if((i==0x15b)||(i==0x15c)){ //按键按下处理
    msflag=TRUE;
    PostMessage(hWndMain,0x7fff,0x1,0x3L);
    } else if((i==0xc15b)||(i==0xc15c)){//按键抬起处理
    msflag=FALSE;
    PostMessage(hWndMain,0x7fff,0x2,0x3L);
    }
    }
    }
    }
    return((int)CallNextHookEx(hKeyHook,nCode,wParam,lParam));
    }
    该程序的主要功能是监控键盘按键消息,将两个特殊按键Micro按下和抬起消息转换
    成自定义类型的消息,并将自定义消息发送给应用程序主窗口函数。
    2、在应用程序主函数中建立窗口后,调用InitHooksDll()函数来初始化动态链接
    库,并将应用程序主窗口句柄传递给链接库,然后调用InstallFilter()函数挂接键
    盘事件监控回调函数。
    InitHooksDll(hIMEWnd); //初始化DLL
    InstallFilter(TRUE); //安装键盘回调函数
    3、在应用程序主窗口函数处理自定义消息时,保存Micro按键的状态,供组合按键
    处理时判断使用。
    switch (iMessage) {
    case 0x7fff: //自定义消息类型
    if(lParam==0x3L){//设置Micro键的状态
    if(wParam==0x1) MicroFlag=TRUE;
    else if(wParam==0x2) MicroFlag=FALSE;
    }
    break;
    4、在进行按键组合处理时,首先判断Micro键是否按下,然后再进行其它按键的判
    断处理。
    case WM_KEYDOWN: // 按键按下处理
    if(MicroFlag==TRUE){//Micro键按下
    if((BYTE)HIBYTE(wParam)==0x5b){
    //Micro+"["组合键
    ......//按键功能处理
    } else if((BYTE)HIBYTE(wParam)==0x5d){
    //Micro+"]"组合键
    ......//按键功能处理
    }
    }
    break;
    5、当应用程序退出时应注意下载键盘监控函数,即调用InstallFilter(FALSE)函
    数一次。
    6、利用本文提供的方法设置自己的应用程序功能按键,在保证程序功能按键不会
    与其它系统发生冲突的同时,有效地利用了系统中现有资源,而且在实现应用程序
    功能的同时灵活应用了系统中提供的各种功能调用。  
      
      

  7.   

    用keybd_event函数,可以模拟键盘操作。