本期教程主要跟大家讲解键盘输入,这里我们通过开发板上面带的按键进行相关的操作,在后面会专门的做一期PS2键盘的教程。

描述

键盘输入设备使用ASCII字符编码,以便区分不同的字符。例如,键盘上只有一个“A”键,但大写的“A”与小写的“a”拥有不同的ASCII编码 (分别为0x41和0x61)

STemWin预定义字符编码

STemWin 同时定义了其他“虚拟”键盘操作的字符编码。这些编码如下表所示,由GUI.h中的标识符表中定义。因此,在emWin中,字符编码可以是任意扩展ASCII字符值,也可以是任意下列预定义的emWin值。

预定义的虚拟键盘码 描述
GUI_KEY_BACKSPACE 退格键
GUI_KEY_TAB 制表键
GUI_KEY_ENTER 回车键
GUI_KEY_LEFT 左箭头键
GUI_KEY_UP 上箭头键
GUI_KEY_RIGHT 右箭头键
GUI_KEY_DOWN 下箭头键
GUI_KEY_HOME 本位键(移至当前行的开头)
GUI_KEY_END 结束键(移至当前行的末尾)
GUI_KEY_SHIFT 换挡键
GUI_KEY_CONTROL 控制键
GUI_KEY_ESCAPE 换码键
GUI_KEY_INSERT 插入键
GUI_KEY_DELETE 删除键

驱动层API

键盘驱动层处理键盘消息函数。这些程序会在具体键 (或组合键)被按下或松开时通知窗口管理器。

下表按字母顺序列出了驱动层键盘程序。
详细描述

程序 描述
GUI_StoreKeyMsg() 把消息存储于指定键
GUI_SendKeyMsg() 把消息发送至指定键。

函数GUI_StoreKeyMsg()

把消息数据(Key, PressedCnt)存进键盘缓冲器,Key表示可以是任意扩展ASCII字符 (范围为0x20至0xFF)或者任意预定义的emWin字符编码。PressedCnt表示松开或者未按下的状态。

该函数可从中断服务程序调用。STemWin的键盘输入管理器含有一个FIFO缓冲器,默认情况下最多可以保存10个键盘事件。如果需要不同的尺寸,可以更改该值。

函数GUI_SendKeyMsg()

把键盘数据发送到输入焦点所在窗口。如果没有窗口有输入焦点,则调用GUI_StoreKeyMsg()函数将数据存储至输入缓冲器之中。该函数不可从中断服务程序调用。该函数的参数和上面函数的参数是一样的。

应用层的如下几个函数就先不做介绍了,使用到的时候再做介绍:

实体按键操作

下面给大家讲解一下通过开发板上面带的按键来操作控件。按键的驱动请看安富莱STM32-V5开发板_用户手册的第20章:按键FIFO教程。此工程主要分为两部分:

Ø 按键任务

Ø STemWin主任务

按键任务:


static void AppTaskUserIF(void *p_arg)
{
    uint8_t ucKeyCode;
    (void)p_arg;
    while (1)
    {
        bsp_KeyScan();
        ucKeyCode = bsp_GetKey();
        if(ucKeyCode != KEY_NONE)
        {
            switch (ucKeyCode)
            {
            case KEY_DOWN_K1:
                BSP_OS_SemPost(&SEM_SYNCH);
                break;
            case KEY_DOWN_K2:
                GUI_SendKeyMsg(GUI_KEY_TAB, 1);
                break;
            case KEY_DOWN_K3:
                GUI_SendKeyMsg(GUI_KEY_ESCAPE, 1);
                break;
            case JOY_DOWN_U:
                GUI_SendKeyMsg(GUI_KEY_DELETE, 1);
                break;
            case JOY_DOWN_D:
                GUI_SendKeyMsg(GUI_KEY_BACKSPACE, 1);
                break;
            case JOY_DOWN_L:
                GUI_SendKeyMsg(GUI_KEY_LEFT, 1);
                break;
            case JOY_DOWN_R:
                GUI_SendKeyMsg(GUI_KEY_RIGHT, 1);
                break;
            case JOY_DOWN_OK:
                GUI_SendKeyMsg(GUI_KEY_ENTER, 1);
                break;
            default:
                break;
            }
        }
        BSP_OS_TimeDlyMs(10);
    }
}
  1. 按下按键1实现截图功能。

  2. 实现TAB按键的功能。

  3. 实现CANCEL的功能

  4. 实现删除字符的功能,注意和BACKSPACE回个的区别。

  5. 实现删除字符

  6. 实现光标左移。

  7. 实现光标右移。

  8. 实现OK键功能。

### STemWin主任务:
#include "includes.h"
#include "MainTask.h"
static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] =
{
{ FRAMEWIN_CreateIndirect, "Edit winmode", 0,         90,  90, 140, 130, FRAMEWIN_CF_MOVEABLE},
{ EDIT_CreateIndirect,     NULL,     GUI_ID_EDIT0,    10,  10, 110,  20, 0, 15},
{ EDIT_CreateIndirect,     NULL,     GUI_ID_EDIT1,    10,  40, 110,  20, 0, 15},
{ BUTTON_CreateIndirect,   "Ok",     GUI_ID_OK,       10,  80,  50,  20 },
{ BUTTON_CreateIndirect,   "Cancel", GUI_ID_CANCEL,   70,  80,  50,  20 },
};
static char * _apExplain[] =
{
"This sample shows how to use edit widgets with a",
"user defined callback function and how to set a",
"user defined AddKey function. It selects the",
"contents of the edit field on receiving the focus",
"and overwrites the contents if a key other than",
"a cursor key is pressed."
};
static void _cbDialog(WM_MESSAGE * pMsg)
{
int     i;
int     NCode;
int     Id;
WM_HWIN hDlg;
WM_HWIN hItem;
hDlg = pMsg->hWin;
switch (pMsg->MsgId)
{
case WM_INIT_DIALOG:
    FRAMEWIN_SetFont(pMsg->hWin, &GUI_Font13_ASCII);
    FRAMEWIN_SetTextAlign(pMsg->hWin, GUI_TA_HCENTER);
    for (i = 0; i < 2; i++)
    {
        hItem = WM_GetDialogItem(hDlg, GUI_ID_EDIT0 + i);// Get the handle of the edit widget
    }
    break;
case WM_KEY:
    switch (((WM_KEY_INFO*)(pMsg->Data.p))->Key)
    {
    case GUI_KEY_ESCAPE:
        GUI_EndDialog(hDlg, 1);
        break;
    case GUI_KEY_ENTER:
        GUI_EndDialog(hDlg, 0);
        break;
    }
    break;
case WM_NOTIFY_PARENT:
    Id    = WM_GetId(pMsg->hWinSrc);      // Id of widget
    NCode = pMsg->Data.v;                 // Notification code
    switch (NCode)
    {
    case WM_NOTIFICATION_RELEASED:      // React only if released
        if (Id == GUI_ID_OK)
        {
            // OK Button
            GUI_EndDialog(hDlg, 0);
        }
        if (Id == GUI_ID_CANCEL)
        {
// Cancel Button
            GUI_EndDialog(hDlg, 1);
        }
        break;
    }
    break;
default:
    WM_DefaultProc(pMsg);
}
}
static void _cbDesktop(WM_MESSAGE * pMsg)
{
unsigned i;
switch (pMsg->MsgId)
{
case WM_PAINT:
    GUI_SetBkColor(GUI_RED);
    GUI_Clear();
    GUI_SetFont(&GUI_Font24_ASCII);
    GUI_DispStringHCenterAt("WIDGET_EditWinmode", 160, 5);
    GUI_DispNextLine();
    GUI_SetFont(GUI_DEFAULT_FONT);
    GUI_DispNextLine();
    for (i = 0; i < GUI_COUNTOF(_apExplain); i++)
    {
        GUI_DispStringHCenterAt(_apExplain[i], 160, GUI_GetDispPosY());
        GUI_DispNextLine();
    }
    break;
}
}
void MainTask(void)
{
GUI_Init();
WM_SetCallback(WM_HBKWIN, _cbDesktop);
while(1)
{
    GUI_ExecDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), &_cbDialog, 0, 0, 0);
    GUI_Delay(1000);
}
}
  1. 上面的程序比较简单,主要是在对话框上面显示一个编辑框(初学的不要担心,后面教程会有这些控件的讲解)。

  2. K1按键实现的是TAB键的功能,主要是实现对话框上面控件的聚焦切换。

其余的按键功能比较简单,实际操作下就明白了,上面的代码中也有相应的注释。

尝试了一下自定义按键消息没有成功,后面再试试。

  1. 按键具体的通讯机制会在后面的教程中再跟大家讲解。

实际的显示效果如下:

总结

本期教程就跟大家讲这么多,主要是想通过本期教程让大家对实体按键操作控件有一个了解。这个过程还需要大家对通信机制有所了解。在后面的教程中会跟大家详细讲解通信机制这块。