C语言控制台窗口图形界面编程

句柄

在Windows操作系统下用C语言编写控制台的窗口界面首先要获取当前标准输入和标准输出设备的句柄。“句柄”是Windows最常用的一个概念。它通常用来标识Windows资源(如菜单、 图标、窗口等)和设备等对象。虽然可以把句柄理解为是一个指针变量类型,但它不是对象所在的地址指针,而是作为Windows系统内部表的索引值来使用 的。调用相关文本界面控制的API函数。这些函数可分为三类。

  1. 用于控制台窗口操作的函数(包括窗口的缓冲区大小、窗口前景字符和背景颜色、窗口标题、大小和位置等);
  2. 用于控制台输入输出的函数(包括字符属性操作函数);
  3. 其他的函数并为最后一类。通过调用CloseHandle函数来关闭输入输出句柄。

通过调用函数GetStdHandle可以获取当前标准输入以及输出设备的句柄。函数原型为:

HANDLE GetStdHandle(DWORD nStdHandle); 

其中,nStdHandle可以是:

  • STD_INPUT_HANDLE    标准输入设备句柄 
  • STD_OUTPUT_HANDLE   标准输出设备句柄 
  • STD_ERROR_HANDLE    标准错误设备句柄 

用于控制台窗口操作的API函数

GetConsoleScreenBufferInfo(); //获取控制台窗口信息
GetConsoleTitle();              //获取控制台窗口标题
SetConsoleScreenBufferSize(); //更改指定缓冲区大小
SetConsoleTitle();              //设置控制台窗口标题
SetConsoleWindowInfo();          //设置控制台窗口信息

举个例子:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <conio.h>
#define N 255
int main()
{
    HANDLE handle_out;                 //定义一个句柄
    CONSOLE_SCREEN_BUFFER_INFO scbi; //定义一个窗口缓冲区信息结构体
    COORD size = {80, 25};             //定义一个坐标结构体
    char strtitle[N];
    handle_out = GetStdHandle(STD_OUTPUT_HANDLE);  //获得标准输出设备句柄
    GetConsoleScreenBufferInfo(handle_out, &scbi); //获得窗口缓冲区信息
    GetConsoleTitle(strtitle, N);                   //获得当前窗口标题
    printf("当前窗口标题为:%s\n", strtitle);
    _getch();
    SetConsoleTitle("控制台窗口操作"); //设置窗口标题为“控制台窗口操作”
    GetConsoleTitle(strtitle, N);       //获得当前窗口标题
    printf("当前窗口标题为:%s\n", strtitle);
    _getch();
    SetConsoleScreenBufferSize(handle_out, size); // 重新设置缓冲区大小
    _getch();
    SMALL_RECT rc = {0, 0, 80 - 1, 25 - 1}; // 重置窗口位置和大小
    SetConsoleWindowInfo(handle_out, 1, &rc);
    CloseHandle(handle_out); //关闭标准输出设备句柄
    system("pause");
    return 0;
}

 

设置文本属性的函数

BOOL SetConsoleTextAttribute( // 设置WriteConsole等函数的字符属性
    HANDLE hConsoleOutput,      // 句柄
    WORD wAttributes          // 文本属性
);

文本属性,其实就是颜色属性,有背景色和前景色(就是字符的颜色)两类,每一类只提供三原色(红,绿,蓝)和加强色(灰色,可与其他颜色搭配使用,使颜色变亮。

基本文本属性:

  • FOREGROUND_BLUE 蓝色 
  • FOREGROUND_GREEN 绿色 
  • FOREGROUND_RED 红色 
  • FOREGROUND_INTENSITY 加强 
  • BACKGROUND_BLUE 蓝色背景 
  • BACKGROUND_GREEN 绿色背景 
  • BACKGROUND_RED 红色背景 
  • BACKGROUND_INTENSITY 背景色加强 
  • COMMON_LVB_REVERSE_VIDEO 反色 

 举个例子:

#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);

    SetConsoleTextAttribute(handle, FOREGROUND_RED);
    cout << "Red     " << flush;
    SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_INTENSITY);
    cout << "Red" << endl;

    SetConsoleTextAttribute(handle, FOREGROUND_GREEN);
    cout << "Green   " << flush;
    SetConsoleTextAttribute(handle, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
    cout << "Green" << endl;

    SetConsoleTextAttribute(handle, FOREGROUND_BLUE);
    cout << "Blue    " << flush;
    SetConsoleTextAttribute(handle, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
    cout << "Blue" << endl;

    SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_GREEN);
    cout << "Yellow  " << flush;
    SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
    cout << "Yellow" << endl;

    SetConsoleTextAttribute(handle, FOREGROUND_GREEN | FOREGROUND_BLUE);
    cout << "Cyan    " << flush;
    SetConsoleTextAttribute(handle, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
    cout << "Cyan" << endl;

    SetConsoleTextAttribute(handle, FOREGROUND_BLUE | FOREGROUND_RED);
    cout << "Magenta " << flush;
    SetConsoleTextAttribute(handle, FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY);
    cout << "Magenta" << endl;

    SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
    cout << "White   " << flush;
    SetConsoleTextAttribute(handle, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
    cout << "White" << endl;
    system("pause");
    return 0;
}

#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);

    SetConsoleTextAttribute(handle, BACKGROUND_RED);
    cout << "Red     " << flush;
    SetConsoleTextAttribute(handle, BACKGROUND_RED | BACKGROUND_INTENSITY);
    cout << "Red     " << endl;

    SetConsoleTextAttribute(handle, BACKGROUND_GREEN);
    cout << "Green   " << flush;
    SetConsoleTextAttribute(handle, BACKGROUND_GREEN | BACKGROUND_INTENSITY);
    cout << "Green   " << endl;

    SetConsoleTextAttribute(handle, BACKGROUND_BLUE);
    cout << "Blue    " << flush;
    SetConsoleTextAttribute(handle, BACKGROUND_BLUE | BACKGROUND_INTENSITY);
    cout << "Blue    " << endl;

    SetConsoleTextAttribute(handle, BACKGROUND_RED | BACKGROUND_GREEN);
    cout << "Yellow  " << flush;
    SetConsoleTextAttribute(handle, BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY);
    cout << "Yellow  " << endl;

    SetConsoleTextAttribute(handle, BACKGROUND_GREEN | BACKGROUND_BLUE);
    cout << "Cyan    " << flush;
    SetConsoleTextAttribute(handle, BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
    cout << "Cyan    " << endl;

    SetConsoleTextAttribute(handle, BACKGROUND_BLUE | BACKGROUND_RED);
    cout << "Magenta " << flush;
    SetConsoleTextAttribute(handle, BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY);
    cout << "Magenta " << endl;

    SetConsoleTextAttribute(handle, BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
    cout << "White   " << flush;
    SetConsoleTextAttribute(handle, BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
    cout << "White   " << endl;
    system("pause");
    return 0;
}

常用的文本输出函数

BOOL FillConsoleOutputAttribute(   // 填充字符属性
    HANDLE hConsoleOutput,           // 句柄
    WORD wAttribute,               // 文本属性
    DWORD nLength,                   // 个数
    COORD dwWriteCoord,               // 开始位置
    LPDWORD lpNumberOfAttrsWritten // 返回填充的个数
);
BOOL FillConsoleOutputCharacter(   // 填充指定数据的字符
    HANDLE hConsoleOutput,           // 句柄
    TCHAR cCharacter,               // 字符
    DWORD nLength,                   // 字符个数
    COORD dwWriteCoord,               // 起始位置
    LPDWORD lpNumberOfCharsWritten // 已写个数
);
BOOL WriteConsoleOutputCharacter(  // 在指定位置处插入指定数量的字符
    HANDLE hConsoleOutput,           // 句柄
    LPCTSTR lpCharacter,           // 字符串
    DWORD nLength,                   // 字符个数
    COORD dwWriteCoord,               // 起始位置
    LPDWORD lpNumberOfCharsWritten // 已写个数
);

 举个例子:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <conio.h>

int main()
{
    char *str = "Hello World!"; //定义输出信息
    int len = strlen(str), i;
    WORD shadow = BACKGROUND_INTENSITY;                     //阴影属性
    WORD text = BACKGROUND_GREEN | BACKGROUND_INTENSITY; //文本属性
    HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
    CONSOLE_SCREEN_BUFFER_INFO csbi;                     //定义窗口缓冲区信息结构体
    GetConsoleScreenBufferInfo(handle_out, &csbi);         //获得窗口缓冲区信息
    SMALL_RECT rc;                                         //定义一个文本框输出区域
    COORD posText;                                         //定义文本框的起始坐标
    COORD posShadow;                                     //定义阴影框的起始坐标
    //确定区域的边界
    rc.Top = 8;                                 //上边界
    rc.Bottom = rc.Top + 4;                     //下边界
    rc.Left = (csbi.dwSize.X - len) / 2 - 2; //左边界,为了让输出的字符串居中
    rc.Right = rc.Left + len + 4;             //右边界
    //确定文本框起始坐标
    posText.X = rc.Left;
    posText.Y = rc.Top;
    //确定阴影框的起始坐标
    posShadow.X = posText.X + 1;
    posShadow.Y = posText.Y + 1;
    for (i = 0; i < 5; ++i) //先输出阴影框
    {
        FillConsoleOutputAttribute(handle_out, shadow, len + 4, posShadow, NULL);
        posShadow.Y++;
    }
    for (i = 0; i < 5; ++i) //在输出文本框,其中与阴影框重合的部分会被覆盖掉
    {
        FillConsoleOutputAttribute(handle_out, text, len + 4, posText, NULL);
        posText.Y++;
    }
    //设置文本输出处的坐标
    posText.X = rc.Left + 2;
    posText.Y = rc.Top + 2;
    WriteConsoleOutputCharacter(handle_out, str, len, posText, NULL); //输出字符串
    SetConsoleTextAttribute(handle_out, csbi.wAttributes);              // 恢复原来的属性
    CloseHandle(handle_out);
    return 0;
}

控制文本移动的函数

BOOL ScrollConsoleScreenBuffer(             //文本移动函数
    HANDLE hConsoleOutput,                 //句柄
    const SMALL_RECT *lpScrollRectangle, //移动区域
    const SMALL_RECT *lpClipRectangle,     //裁剪区域,如果为NULL,那么将代表整个屏幕缓冲区
    COORD dwDestinationOrigin,             //移动到的位置,这个点将成为移动区域的左上顶点
    const CHAR_INFO *lpFill                 //空出区域的填充字符
);

举个例子:

#include <stdio.h>
#include <conio.h>
#include <Windows.h>
#include <stdlib.h>
int main()
{
    HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
    CONSOLE_SCREEN_BUFFER_INFO csbi;                     //定义窗口缓冲区信息结构体
    SMALL_RECT scroll;                                     //定义移动区域
    COORD pos = {0, 5};                                     //移动位置
    CHAR_INFO chFill;                                     //定义填充字符
    GetConsoleScreenBufferInfo(handle_out, &csbi);         //获得窗口缓冲区信息
    //定义填充字符的各个参数及属性
    chFill.Char.AsciiChar = ' ';
    chFill.Attributes = csbi.wAttributes;
    //输出文本
    printf("00000000000000000000000000000\n");
    printf("11111111111111111111111111111\n");
    printf("22222222222222222222222222222\n");
    printf("33333333333333333333333333333\n");
    //确定区域
    scroll.Left = 1;
    scroll.Top = 1;
    scroll.Right = 10;
    scroll.Bottom = 2;
    ScrollConsoleScreenBuffer(handle_out, &scroll, NULL, pos, &chFill); //移动文本
    return 0;
}

 在上面的样例程序中,裁剪区域是整个控制台窗口的屏幕缓冲区,现在如果我们把裁剪区域设定为与移动区域一样,也就是说ScrollConsoleScreenBuffer函数的第三个参数也改成&scroll,那么结果会怎么样呢?

 现在我们应该可以猜想出结论了,别急,再做一个实验,现在我们将裁减区域又重新改为整个屏幕缓冲区,看看会有什么样的现象发生?

 再来最后一个实验,我们将裁减区域减小为移动区域的上半部分,继续执行下移一行的操作,看看最终结果会怎么样?

 好了,现在我们通过归纳可以得出几个结论了,那就是

  • 裁减区域以外的区域不会受文本移动的影响。具体是:
  1. 裁减区域以外的区域不会被移动过来的区域覆盖,
  2. 裁减区域以外的区域被移动到他处之后原区域不发生变化,因此不需要填充字符。

总的归纳来说也就是原来是什么样子,文本移动后还是什么样子,不会改变。

  • 裁减区域以内的区域受文本移动的影响。具体是:
  1. 当裁减区域以内的区域被移动到他处造成该区域为空时会被设定的字符填充,
  2. 裁减区域以内的区域会被移动过来的区域覆盖。

总的归纳来说也就是完全受文本移动的影响,移动过来就被覆盖,被移走就由设定的字符来填充。

当然移动文本还有很多好玩的操作,比如说和sleep() 结合在一起做成控制台小动画。

#include <iostream>
#include <algorithm>
#include <windows.h>
#include <iomanip>
#include <conio.h>
#include "date.cpp"
#define stoptimeshort 40
#define stoptimelong 100
using namespace std;
int main()
{
    string elemode[2] = {"██████████████████████████████", "██                                                    ██"};
    for (int i = 0; i < 30; i++)
    {
        cout << elemode[1] << endl;
    }
    cout << elemode[0] << endl;
    HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;               //定义窗口缓冲区信息结构体
    SMALL_RECT scroll;                             //定义移动区域
    COORD pos = {26, 0};                           //移动位置
    CHAR_INFO chFill;                              //定义填充字符
    GetConsoleScreenBufferInfo(handle_out, &csbi); //获得窗口缓冲区信息
    //定义填充字符的各个参数及属性
    chFill.Char.AsciiChar = ' ';
    chFill.Attributes = csbi.wAttributes;
    for (int i = 2; i < 28; i += 2)
    {
        Sleep(stoptimelong);
        pos = {i + 2, 0};
        scroll.Left = i;
        scroll.Top = 0;
        scroll.Right = i + 1;
        scroll.Bottom = 29;
        ScrollConsoleScreenBuffer(handle_out, &scroll, NULL, pos, &chFill); //移动文本
        pos = {56 - i, 0};
        scroll.Left = 58 - i;
        scroll.Top = 0;
        scroll.Right = 59 - i;
        scroll.Bottom = 29;
        ScrollConsoleScreenBuffer(handle_out, &scroll, NULL, pos, &chFill); //移动文本
    }
    //关闭标准输出设备句柄
    CloseHandle(handle_out);
    system("pause");
    return 0;
}

 控制光标位置的函数

BOOL SetConsoleCursorPosition( //设置光标位置
    HANDLE hConsoleOutput,       //句柄
    COORD dwCursorPosition       //坐标
);                               //若函数调用成功则返回非0值
BOOL GetConsoleCursorInfo(                     //获得光标信息
    HANDLE hConsoleOutput,                     //句柄
    PCONSOLE_CURSOR_INFO lpConsoleCursorInfo //光标信息,注意这是个指针类型
);
BOOL SetConsoleCursorInfo(                           //设置光标信息
    HANDLE hConsoleOutput,                           //句柄
    const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo //光标信息
);

举个例子:

#include <stdio.h>
#include <Windows.h>
#include <conio.h>
#include <stdlib.h>
int main()
{
    HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
    CONSOLE_CURSOR_INFO cci;                             //定义光标信息结构体
    GetConsoleCursorInfo(handle_out, &cci);                 //获得当前光标信息
    cci.dwSize = 100; //设置光标尺寸为100
    SetConsoleCursorInfo(handle_out, &cci);
    _getch();
    cci.bVisible = false; //设置光标为不可见
    SetConsoleCursorInfo(handle_out, &cci);
    _getch();
    return 0;
}

键盘事件函数

BOOL ReadConsoleInput(             //读取输入信息
    HANDLE hConsoleInput,         //句柄
    PINPUT_RECORD lpBuffer,         //输入事件结构体的指针
    DWORD nLength,                 //要读取的记录数
    LPDWORD lpNumberOfEventsRead //用来接受成功读取记录数的指针
);                                 //如果该函数成功调用,返回非零值
                                 //输入事件结构体的指针可以是结构体数组的首地址,这样就可以一次性读取多个记录数。

COORD坐标结构体)

typedef struct _COORD
{
    SHORT X;
    SHORT Y;
} COORD;

CONSOLE_SCREEN_BUFFER_ INFO控制台窗口信息结构体

typedef struct _CONSOLE_SCREEN_BUFFER_INFO
{
    COORD dwSize;               //缓冲区大小
    COORD dwCursorPosition;       //当前光标位置
    WORD wAttributes;           //字符属性
    SMALL_RECT srWindow;       //当前窗口显示的大小和位置
    COORD dwMaximumWindowSize; // 最大的窗口缓冲区大小
} CONSOLE_SCREEN_BUFFER_INFO;

_SMALL_RECT(表示矩形区域的结构体)

typedef struct _SMALL_RECT //表示矩形区域的结构体
{
    SHORT Left;      //左边界
    SHORT Top;      //上边界
    SHORT Right;  //右边界
    SHORT Bottom; //下边界
} SMALL_RECT;
/* 
微软官方的说法是 
Left    区域的左上顶点的X坐标 
Top     区域的左上顶点的Y坐标 
Right   区域的右下顶点的X坐标 
Bottom  区域的右下顶点的Y坐标 
*/

_CONSOLE_CURSOR_INFO(光标信息结构体)

typedef struct _CONSOLE_CURSOR_INFO //光标信息结构体
{
    DWORD dwSize;  //光标尺寸大小,范围是1~100
    BOOL bVisible; //表示光标是否可见,true表示可见
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;

_INPUT_RECORD(输入事件结构体)

typedef struct _INPUT_RECORD //输入事件结构体
{
    WORD EventType; //事件类型
    union {
        KEY_EVENT_RECORD KeyEvent;       //按键事件
        MOUSE_EVENT_RECORD MouseEvent; //鼠标事件
        WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
        MENU_EVENT_RECORD MenuEvent;
        FOCUS_EVENT_RECORD FocusEvent;
    } Event; //具体的事件
} INPUT_RECORD;
/* 
其中事件类型EventType的值有5种 
KEY_EVENT                   代表Event包含一个KEY_EVENT_RECODE结构体 
MOUSE_EVENT                 代表Event包含一个MOUSE_EVENT_RECODE结构体 
WINDOW_BUFFER_SIZE_EVENT    代表Event包含一个WINDOW_BUFFER_SIZE_EVENT_RECORD结构体 
MENU_EVENT                  代表Event包含一个MENU_EVENT_RECORD结构体 
FOCUS_EVENT                 代表Event包含一个FOCUS_EVENT_RECORD结构体 
*/

_KEY_EVENT_RECORD(键盘事件结构体)

typedef struct _KEY_EVENT_RECORD //键盘事件结构体
{
    BOOL bKeyDown;           //按键状态,true代表键按下,false代表键释放
    WORD wRepeatCount;       //按键次数
    WORD wVirtualKeyCode;  //虚拟键
    WORD wVirtualScanCode; //虚拟键扫描码
    union {
        WCHAR UnicodeChar; //解释成Unicode宽字符
        CHAR AsciiChar;       //解释成ASCII码字符
    } uChar;
    DWORD dwControlKeyState; //控制键状态
} KEY_EVENT_RECORD;
/* 
控制键各状态的值 
ENHANCED_KEY        扩展键被按下 
LEFT_ALT_PRESSED    左Alt键被按下 
LEFT_CTRL_PRESSED   左Ctrl键被按下 
RIGHT_ALT_PRESSED   右Alt键被按下 
RIGHT_CTRL_PRESSED  右Ctrl键被按下 
NUMLOCK_ON          数字锁定被打开 
SCROLLLOCK_ON       滚动锁定被打开 
CAPSLOCK_ON         大写锁定被打开 
SHIFT_PRESSED       Shift键被按下 
*/

虚拟键代码表:

/* 
虚拟键代码      值          键名称 
-----------------------------------------------------             
VK_BACK         0x08        退格键 
VK_TAB          0x09        Tab键 
VK_RETURN       0x0D        回车键 
VK_SHIFT        0x10        Shift键 
VK_LSHIFT       0xA0        左Shift键 
VK_RSHIFT       0xA1        右Shift键 
VK_CONTROL      0x11        Ctrl键 
VK_LCONTROL     0xA2        左Ctrl键 
VK_RCONTROL     0xA3        右Ctrl键 
VK_MENU         0x12        Alt键 
VK_LMENU        0xA4        左Alt键 
VK_RMENU        0xA5        右Alt键 
VK_PAUSE        0x13        Pause键 
VK_CAPITAL      0x14        Caps Lock键 
VK_NUMLOCK      0x90        Num Lock键 
VK_SCROLL       0x91        Scroll Lock键 
VK_ESCAPE       0x1B        Esc键 
VK_SPACE        0x20        空格键 
VK_PRIOR        0x21        Page Up键 
VK_NEXT         0x22        Page Down键 
VK_END          0x23        End键 
VK_HOME         0x24        Home键 
VK_LEFT         0x25        左方向键 
VK_UP           0x26        上方向键 
VK_RIGHT        0x27        右方向键 
VK_DOWN         0x28        下方向键 
VK_DELETE       0x2E        Delete键 
VK_INSERT       0x2D        Insert键 
'0'             0x30        0键(非小键盘) 
'1'             0x31        1键(非小键盘) 
'2'             0x32        2键(非小键盘) 
...             ...         ... 
'9'             0x39        9键(非小键盘) 
'A'             0x41        A键 
'B'             0x42        B键 
...             ...         ... 
'Z'             0x5A        Z键 
VK_SLEEP        0x5F        Sleep键 
VK_NUMPAD0      0x60        小键盘0键 
VK_NUMPAD1      0x61        小键盘1键 
VK_NUMPAD2      0x62        小键盘2键 
...             ...         ... 
VK_NUMPAD9      0x69        小键盘9键 
VK_MULTIPLY     0x6A        小键盘乘键* 
VK_ADD          0x6B        小键盘加键+ 
VK_SUBTRACT     0x6D        小键盘减键- 
VK_DIVIDE       0x6F        小键盘除键/ 
VK_DECIMAL      0x6E        小键盘点键. 
VK_F1           0x70        F1键 
VK_F2           0x71        F2键 
...             ...         ... 
VK_F12          0x7B        F12键 
VK_F13          0x7C        F13键      注:别问我,我也不知道什么电脑有这么多键 
...             ...         ... 
VK_F24          0x87        F24键 
VK_OEM_1        0xBA        ;:键 
VK_OEM_2        0xBF        /?键 
VK_OEM_3        0xC0        ·~键 
VK_OEM_4        0xDB        [{键 
VK_OEM_5        0xDC        \|键 
VK_OEM_6        0xDD        ]}键 
VK_OEM_7        0xDE        '"键 
VK_OEM_PLUS     0xBB        =+键 
VK_OEM_MINUS    0xBD        -_键 
VK_OEM_COMMA    0xBC        ,<键 
VK_OEM_PERIOD   0xBE        .>键  
*/

猜你喜欢

转载自www.cnblogs.com/stu-jyj3621/p/12956366.html