首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • win32控制台程序(console)获取快捷键的问题,望大虾们解惑 [已结贴,结贴人:skyljp]
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • skyljp
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    • 揭帖率:
    发表于:2008-06-07 17:14:29 楼主
    小弟最近在做一个基于控制台下的文本编辑器,就是像eidt那样的东西,现在做的七七八八了。不过现在想用快捷键的来进行保存,粘贴,复制等操作。可惜不会获取组合键,经过baidu,google,msdn遍历仍不得解。心中甚为郁闷啊。特此来求教。
    我在msdn上整了段例子和着网上的东西自己又改了改如下:
    程序太长,大侠们复制下来看吧,问题在程序注释里,等待大虾们的佳音啦。哈哈。。。。

    #include <windows.h>
    #include <stdio.h>
    void ErrorExit (LPSTR lpszMessage);

    int main(void)
    {
        HANDLE hStdin;
        DWORD cNumRead, fdwMode, i;
        INPUT_RECORD irInBuf[1];
        int counter=0;

    hStdin = GetStdHandle(STD_INPUT_HANDLE); 
    while (counter++ <= 100)
        {
            if (! ReadConsoleInput(hStdin,irInBuf,1,&cNumRead) ) //读入键盘输入
    ErrorExit(TEXT("ReadConsoleInput"));
    for (i = 0; i < cNumRead; i++)
            {
                switch(irInBuf[i].EventType)
                {
    //这里我只处理上下左右键,ctrl+x,ctrl+v,ctrl+s的快捷键,鼠标移动的回应。
    //问题一:主要是下面这个的情况,我输入ctrl+x,ctrl+v等组合键后理论上
    //irInBuf[].Event.KeyEvent.uChar.AsciiChar中应该是's'等字符吧
    //可结果irInBuf[i].Event.KeyEvent.uChar.AsciiChar中存放的是某些控制字符.
    //第二个问题是:为什么下面用按位与。
    //看程序似乎感觉想起到 == 这个运算符的作用,可情况不是这样。
    //这程序是总和网上多个例子整出来的,具体也不知出自哪里。
    //但单个键,如上下左右键的反应倒是正常的。
                case KEY_EVENT: // keyboard input
    if(irInBuf[i].Event.KeyEvent.bKeyDown )
    {
    if (irInBuf[i].Event.KeyEvent.wVirtualKeyCode == VK_DOWN)
    printf("BACK\n");
    if (irInBuf[i].Event.KeyEvent.wVirtualKeyCode == VK_UP)
    printf("UP\n");
    if (irInBuf[i].Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)
    printf("RIGHT\n");
    if (irInBuf[i].Event.KeyEvent.wVirtualKeyCode == VK_LEFT)
    printf("LEFT\n");
    //下面为什么用按位与呢?
    if((irInBuf[i].Event.KeyEvent.uChar.AsciiChar &  'v') && (irInBuf[i].Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED))
    printf("AsciiChar 的值是 %d\n",irInBuf[i].Event.KeyEvent.uChar.AsciiChar);
    //输出irInBuf[i].Event.KeyEvent.uChar.AsciiChar的值

    if((irInBuf[i].Event.KeyEvent.uChar.AsciiChar &'x') && (irInBuf[i].Event.KeyEvent.dwControlKeyState &  LEFT_CTRL_PRESSED))
    printf("AsciiChar 的值是 %d\n",irInBuf[i].Event.KeyEvent.uChar.AsciiChar);

    if((irInBuf[i].Event.KeyEvent.uChar.AsciiChar & 'a') && (irInBuf[i].Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED))
    printf("AsciiChar 的值是 %d\n",irInBuf[i].Event.KeyEvent.uChar.AsciiChar);

    }
    break;

                    case MOUSE_EVENT: // mouse input
    printf("mouse_event\n");
                    case FOCUS_EVENT:  // disregard focus events
    case MENU_EVENT:  // disregard menu events
                        break;

                    default:
                        ErrorExit(TEXT("Unknown event type"));
                        break;
                }
            }
        }
    return 0;
    }


    void ErrorExit (LPSTR lpszMessage)
    {
        fprintf(stderr, "%s\n", lpszMessage);
        ExitProcess(0);
    }
    80  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • adlay
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-06-07 18:21:281楼 得分:10
    1. uChar 存储的是一个输入字符,是经过转换的,比如键盘上大小写状态,数字键状态等,如果打开了输入法的话这里存放的是经过输入法翻译后的字符。 用 Ctrl + X 的时候通常并不做为一个输入来处理,所以 uChar 里放的不是 X 很正常。
    2. 这个用 & 没看懂,如果要获得 Ctrl + a 的输入的话应该是
    if((irInBuf[i].Event.KeyEvent.wVirtualKeyCode  ==  'A') && (irInBuf[i].Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED))  才合理。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • grellen
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-06-07 18:43:592楼 得分:5
    up
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • VBSpine
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-06-07 20:40:213楼 得分:5
    顶1楼。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • skyljp
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-06-07 23:27:264楼 得分:0
    "uChar 存储的是一个输入字符,是经过转换的"
    这句话很有启发,我用下面的程序做了个测试:
    发现输入单个键‘v’与‘ctrl+v’得到的uChar不同。
    也就像adlay说的一样,用'ctrl+v'得到的uChar是经过转换的。
    并且由此我用以下的程序找到很多组合键的uChar值。
    如‘ctrl+x’,‘ctrl+v',‘ctrl+a’,‘ctrl+z’.

    但某些组合键无法得到,如‘ctrl+s’,‘ctrl+c’.
    ‘ctrl+s’没反应;‘ctrl+z’更狠,直接终止console......

    还有shift与上下左右键的组合,shift与insert,delete键的组合,
    似乎它们的uChar都是0,这样就无法使用这种组合。

    不知大虾们有没有写过这方面的程序,能给个完整的能读取上述快捷键的程序?
    大虾们,谢谢啦。

    #include <windows.h>
    #include <stdio.h>
    void ErrorExit (LPSTR lpszMessage);

    int main(void)
    {
        HANDLE hStdin;
        DWORD cNumRead, fdwMode, i;
        INPUT_RECORD irInBuf[1];
        int counter=0;

    hStdin = GetStdHandle(STD_INPUT_HANDLE); 
    while (counter++ <= 10000)
        {
            if (! ReadConsoleInput(hStdin,irInBuf,1,&cNumRead) ) //读入键盘输入
    ErrorExit(TEXT("ReadConsoleInput"));
    for (i = 0; i < cNumRead; i++)
            {
                switch(irInBuf[i].EventType)
                {
                case KEY_EVENT: // keyboard input
                    if(irInBuf[i].Event.KeyEvent.bKeyDown )
    //如果有键盘输入,将AsciiChar输出
                    {
                        printf("the ascii is %d\n",irInBuf[i].Event.KeyEvent.uChar.AsciiChar);
                    }
                    break;
                    case MOUSE_EVENT: // mouse input
    printf("mouse_event\n");
                    case FOCUS_EVENT:  // disregard focus events
                    case MENU_EVENT:  // disregard menu events
                        break;
                    default:
                        ErrorExit(TEXT("Unknown event type"));
                        break;
                }
            }
        }
    return 0;
    }


    void ErrorExit (LPSTR lpszMessage)
    {
        fprintf(stderr, "%s\n", lpszMessage);
        ExitProcess(0);
    }
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • adlay
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-06-08 01:42:435楼 得分:50
    uChar 保存的转换结果和按键不是一一对应的啊,用这个转换的结果来判断组合键显然不行。比如处于小写状态时按 A 键和处于大写状态时按 Shift + A 得到的 uChar 是一样的。
    正确的方法应该是使用 wVirtualKeyCode 和 dwControlKeyState 来判断输入的是什么组合键。

    给个处理 Ctrl, Shift, Alt 和其他键组合消息的列子:
    C/C++ code
    #include <windows.h> #include <stdio.h> int main(void) { HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); while(1) { INPUT_RECORD sInput; DWORD dwReaded = 0; if(!ReadConsoleInput(hStdin, &sInput, 1, &dwReaded)) { printf("Read Error: %d\n", GetLastError()); break; } if(sInput.EventType != KEY_EVENT) { continue; } KEY_EVENT_RECORD ke = sInput.Event.KeyEvent; if(!ke.bKeyDown) { continue; } if(ke.wVirtualKeyCode == VK_SHIFT || ke.wVirtualKeyCode == VK_CONTROL || ke.wVirtualKeyCode == VK_MENU) { continue; } printf("Input Key Is: "); if(ke.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) ) printf("Ctrl + "); if(ke.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) printf("Alt + "); if(ke.dwControlKeyState & SHIFT_PRESSED) printf("Shift + "); if( (ke.wVirtualKeyCode >= 'A' && ke.wVirtualKeyCode <= 'Z') || (ke.wVirtualKeyCode >= '0' && ke.wVirtualKeyCode <= '9') ) { printf("%C", ke.wVirtualKeyCode); } else if(ke.wVirtualKeyCode >= VK_NUMPAD0 && ke.wVirtualKeyCode <= VK_NUMPAD9) { printf("小键盘 %d", ke.wVirtualKeyCode - VK_NUMPAD0); } else if(ke.wVirtualKeyCode >= VK_F1 && ke.wVirtualKeyCode <= VK_F24) { printf("F%d", ke.wVirtualKeyCode - VK_F1 + 1); } else switch(ke.wVirtualKeyCode) { case VK_HOME: printf("home"); break; case VK_LEFT: printf("left arraw"); break; // case ...: 更多的虚拟键处理 default: printf("Other Keys"); break; } printf("\n"); } }
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • fanlehai
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-06-08 10:19:056楼 得分:5
    up
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • skyljp
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-06-08 12:57:087楼 得分:0
    太好了,问题解决。还是csdn牛人多啊。
    感谢adlay兄。
    不过我还有些疑问,就是ctrl+s的处理为什么出不来?
    我查到ctrl+c是个系统消息,可以用
    BOOL SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, BOOL Add )
    来处理,可是ctrl+s就不知道怎么回事了。

    还有起初我对下面这多代码不了解。
    if(ke.wVirtualKeyCode==VK_SHIFT ||ke.wVirtualKeyCode == VK_CONTROL ||ke.wVirtualKeyCode == VK_MENU)
    {
              continue;
    }
    按我理解,应该是处理只按下ctrl,alt等键时的操作.
    于是我用下面的代码做了个小测试,证明确实如此。但在此过程中,我又发现了问题.
    先来代码吧:
    #include <stdio.h>
    #include <windows.h>
    HANDLE hOut;
    HANDLE hIn;
    void main()
    {
    hOut =GetStdHandle(STD_OUTPUT_HANDLE);
    hIn=GetStdHandle(STD_INPUT_HANDLE);
    INPUT_RECORD keyRec;
    DWORD state=0,res;
    for(;;)
    {
    ReadConsoleInput(hIn,&keyRec,1,&res);
    if(keyRec.EventType == KEY_EVENT && keyRec.Event.KeyEvent.bKeyDown==TRUE)
    //检测只输入ctrl,alt,esc等键的反应。
    {
    if (keyRec.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT)
    printf("shift\n");
    if (keyRec.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)
    printf("escape\n");
    if (keyRec.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL)
    printf("ctrl\n");
    if (keyRec.Event.KeyEvent.wVirtualKeyCode == VK_MENU)
    printf("alt\n");
    }
    }
    CloseHandle(hOut);
    CloseHandle(hIn);
    }

    在输入过程中,alt,ctrl正常,可输入shift时,它打印出了两次shift.这个为什么呢?
    啰嗦了些,但还请大虾解惑啊。
    稍后散分。呵呵
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • adlay
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-06-08 16:28:308楼 得分:5
    1. 如果这个快捷键被某个进程用 RegisterHotKey 向系统注册了系统快捷键你就收不到这个消息了。 Ctrl + S 可能已经被使用了。
    2. 只要是会改变键盘状态的按键都会收到两次消息,还有象 Caps Lock, Num Lock, Scroll Lock 等等都是这样。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • skyljp
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-06-09 17:29:199楼 得分:0
    恩,看起来挺复杂的,看来学习之路漫漫啊。
    好,结贴啦。
    谢谢楼上各位了,特别是adlay。
    修改 删除 举报 引用 回复

    网站简介广告服务网站地图帮助联系方式诚聘英才English 问题报告
    北京创新乐知广告有限公司 版权所有 京 ICP 证 070598 号
    世纪乐知(北京)网络技术有限公司 提供技术支持
    Copyright © 2000-2008, CSDN.NET, All Rights Reserved