📄 key.c
字号:
//----------------------------------------------------
//Copyright (C), 2004-2009, lst.
//版权所有 (C), 2004-2009, lst.
//所属模块:键盘
//作者:lst
//版本:V1.1.0
//文件描述: 提供键盘设备管理功能的公共部分,移植需要修改的见key_xxx.c文件
//其他说明:
//修订历史:
// 2. 日期:20090131
// 作者:lst
// 新版本号:v1.1.0
// 修改说明:
// 1.把硬件相关的函数key_scan_hard移到key_xxx.c中.
// 2.增加key_read函数和key_read_direct函数
// 1. 日期:20090104
// 作者:lst
// 新版本号:v1.0.0
// 修改说明:原始版本
//------------------------------------------------------
#include "inc_os.h"
#include "key.h"
static struct key_script tg_key_buf[cn_key_buf_len];
static struct ring_buf tg_key_queue;
static struct pan_device *pg_key_dev;
static struct dev_handle *pg_key_rhdl;
static struct dev_handle *pg_key_lhdl;
static uint16_t u16g_evtt_key;
static struct semaphore_LCB *pg_key_semp;
//建立这样的表是必要的,可以使应用程序摆脱对特定硬件的依赖
//PC键盘扫描码是广泛使用的,就以PC键盘为基准吧.本表现在是随便填充,应用时应该改
//为与实际键盘定义对应。
uint16_t u16g_key_table[] =
{
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
};
//----初始化按键设备----------------------------------------------------------
//功能: 初始化键盘模块,包括:创建键盘根设备;创建键盘信号量;登记键盘扫描事件
// 类型;pop键盘扫描事件以启动扫描(实际扫描工作要等多线程启动后才开始)
//参数: 无
//返回: true=成功初始化,false=初始化失败,一般是资源(内存)不足引起
//----------------------------------------------------------------------------
bool_t module_init_keyboard(void)
{
ring_init(&tg_key_queue,(uint8_t*)tg_key_buf,
sizeof(struct key_script)*cn_key_buf_len);
//以下建立key设备,该设备支持左手读、右手写和公共控制操作
//设备并无信号量保护,也就是说,键盘设备允许无穷多重并发访问。
//但是,按键缓冲区被信号量pg_key_semp保护,如果发生并发访问且缓冲区中没有按
//键,则部分访问的线程将按优先级在该信号量的同步队列中等候。
pg_key_dev = dev_add_root_device("key",
NULL,NULL, //无信号量保护
(dev_write_func) key_right_write ,
(dev_read_func ) NULL_func,
(dev_ctrl_func ) key_ctrl ,
(dev_write_func ) NULL_func ,
(dev_read_func ) key_left_read ,
(dev_ctrl_func ) key_ctrl
); //"key"是一个根设备
if(pg_key_dev == NULL)
goto exit_from_add_dev;
pg_key_semp = semp_create(cn_key_buf_len,0,"read_key");
if(pg_key_semp == NULL)
goto exit_from_semp;
//tg_key_queue是key设备私有数据
pg_key_dev->private_tag = (ptu32_t)(&tg_key_queue);
pg_key_rhdl = dev_open_right("key",0);
if(pg_key_rhdl == NULL)
goto exit_from_rhdl;
pg_key_lhdl = dev_open_left("key",0);
if(pg_key_lhdl == NULL)
goto exit_from_lhdl;
//无需判断y_evtt_regist函数的返回值,如果返回false,那么随后的y_event_pop也
//会返回false,可以一并判断。
u16g_evtt_key = y_evtt_regist(true,false,cn_prio_RRS,10,key_scan,512,NULL);
if(u16g_evtt_key == cn_invalid_evtt_id)
goto exit_from_regist;
if(y_event_pop(u16g_evtt_key,0,0,0) == (uint16_t)cn_invalid_event_id)
{
goto exit_from_pop;
}
return true;
exit_from_pop:
y_evtt_unregist(u16g_evtt_key);
exit_from_regist:
exit_from_lhdl:
exit_from_rhdl:
semp_delete(pg_key_semp);
exit_from_semp:
dev_delete_device(pg_key_dev);
exit_from_add_dev:
return false;
}
//----右手写键盘--------------------------------------------------------------
//功能: 往按键队列中写入一个按键
//参数: key_rhdl,键盘右手设备指针
// pt_key,键值,struct key_script *指针
// 其他参数: dev_write系统调用的填充物
//返回: 成功写入的按键数量(0或1)
//----------------------------------------------------------------------------
ptu32_t key_right_write(struct dev_handle *key_rhdl,ptu32_t pt_key,
ptu32_t res1,ptu32_t res2)
{
uint16_t len;
if((struct key_script *)pt_key == NULL)
return 0;
int_save_asyn_signal();
//把按键写入键盘设备的按键缓冲区中,读出时按原样读出,故无需考虑字节序和
//对齐问题。
len = ring_write(&tg_key_queue,(uint8_t *)pt_key,sizeof(struct key_script));
if(len != 0) //按键写入队列,缓冲区满会造成写不进去
{
//若有事件在等待,则唤醒。若有多个事件在等待队列中,唤醒优先级最高的,而
//不是最先挂起的。多个线程共享键盘输入时,就有可能出现多个事件同时挂起
//在按键信号量队列中的情况。
semp_post(pg_key_semp);
}
int_restore_asyn_signal();
return 1;
}
//----左手读键盘--------------------------------------------------------------
//功能: 从按键队列中读取一个按键
//参数: key_lhdl,按键的左手操作指针
// pt_key,保存键值的指针,转成struct key_script *类型访问
// mode,读模式,cn_key_mode_sch=无按键则阻塞,1=不阻塞,直接返回.
// timeout,当mode==cn_key_mode_sch时,timeout设定等待超时时间,毫秒数,
// 将被向上取整为cn_tick_ms的整数倍。
//返回:
//----------------------------------------------------------------------------
ptu32_t key_left_read(struct dev_handle *key_lhdl,ptu32_t pt_key,
ptu32_t mode,ptu32_t timeout)
{
uint16_t len;
if((uint8_t *)pt_key == NULL)
return 0;
int_save_asyn_signal();
re_read_key:
//从键盘设备的按键缓冲区中读一个按键,有按键则返回sizeof(struct key_script)
//无按键返回0
len = ring_read(&tg_key_queue,(uint8_t *)pt_key,sizeof(struct key_script));
if(len == 0) //队列中没有按键
{
if(mode == cn_key_mode_sch)
{
int_restore_asyn_signal(); //阻塞前必须开中断,否则会死掉
if(semp_pend(pg_key_semp,timeout)) //进入等待队列
goto re_read_key; //取得信号量返回,再次读按键
else
; //超时返回,退出
}
}
int_restore_asyn_signal();
return (len!=0);
}
//----键盘设备控制------------------------------------------------------------
//功能:
//参数:
//返回:
//----------------------------------------------------------------------------
ptu32_t key_ctrl(struct dev_handle *key_devio,uint32_t cmd,
ptu32_t res1,ptu32_t res2)
{
return 0;
}
//----键盘扫描任务-------------------------------------------------------------
//功能: 周期性地调用硬件扫描程序,获取用户敲击信息,合成标准键盘码,从右手写入
// 键盘设备。键盘码按照PS/2标准扫描码。扫描码有两种不同的类型:通码
// (make code)和断码(break code)。当一个键被按下或持续按住时,就产生一个通
// 码;而当一个键被释放时,就产生一个断码。根据键盘按键扫描码的不同,可将按键
// 分为如下几类:
// 第一类键,通码为1字节,断码为0xF0+通码。如A键,通码为0x1C,断码为0xF0 0x1C。
// 第二类键,通码为2字节0xE0+0xXX形式,断码为0xE0+0xF0+0xXX形式。如right ctrl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -