1 key按键

按键单双多击、长按、多按知识层

这个主题解决什么问题

按键单双多击、长按、多按解决的是“同一个按键输入在时间和组合关系上表达不同含义”的问题。

普通按键只关心按下瞬间;复杂按键需要进一步识别:

  • 多个键是否同时按下

  • 某个键按住了多久

  • 某个键在时间窗口内点击了几次

  • 长按和单击、双击是否需要互斥

因此它的核心不是多写几个 if,而是理解按键状态、边沿、持续时间、时间窗口之间的关系。

按键状态的三种基础信号

复杂按键识别通常依赖三类基础信号:

  • key_val:当前正在按住的键值,表示持续状态

  • key_down:本轮新按下的键,表示按下边沿

  • key_up:本轮刚松开的键,表示释放边沿

三者职责不同:

  • 判断“是否正在长按”时看 key_val

  • 判断“一次按下动作发生了”时看 key_down

  • 判断“一次完整点击结束了”时看 key_up

原始笔记中长按计时使用 key_val == 32,而不是 key_down == 32,这点很关键。key_down 只会在按下边沿出现一次,不能表示持续按住。

多按的知识点

多按本质上是按键值的组合判断。

例如原始笔记中:

 if (key_down == 48)
 {
     num--;
 }

这里的 48 不是魔法数,而是两个按键的组合值。若 S8 和 S9 分别对应 1632,同时按下时组合结果就是 16 + 32 = 48

多按的稳定知识是:

  • 按键底层返回值通常是位掩码或组合码

  • 同时按下多个键时,结果会表现为多个按键值叠加

  • 调试显示 key_val 可以反推出组合值

长按的知识点

长按识别由两个动作组成:

  • 按住期间持续计时

  • 松手时根据累计时间决定是短按还是长按

原始笔记中的核心关系是:

 if (key_val == 32)
 {
     key_val_32_time++;
 }
 ​
 if (key_up == 32)
 {
     if (key_val_32_time > 1000)
     {
         num--;
     }
     else
     {
         num++;
     }
     key_val_32_time = 0;
 }

这里的稳定知识是:

  • 长按计时应绑定“当前按住状态”

  • 动作执行应放在松手边沿,避免按住期间反复触发

  • 计时变量在松手后必须清零

如果 1ms 调用一次计时逻辑,1000 就约等于 1s。若计时逻辑不在 1ms 基准下运行,阈值含义会改变。

多击的知识点

多击识别依赖一个“等待窗口”。

每次松手后:

  • 点击次数加 1

  • 重置一个倒计时窗口,例如 300ms

当 300ms 窗口归零,并且点击次数大于 0 时,再统一判断单击、双击、三击等动作。

原始笔记中的核心关系是:

 if (key_up == 32)
 {
     key_32_click_cnt++;
     key_32_click_time300ms = 300;
 }
 ​
 if ((key_32_click_time300ms == 0) && (key_32_click_cnt > 0))
 {
     /* 根据 click_cnt 执行动作 */
     key_32_click_cnt = 0;
 }

这背后的稳定知识是:

  • 多击不能在第一次松手时立刻判定单击

  • 必须等待一个时间窗口,确认后面没有第二击或第三击

  • click_cnt > 0 是防止没有点击时误执行逻辑

  • 执行动作后必须把点击次数清零

长按和多击共存的关系

长按和多击共存时,最关键的是互斥。

原始笔记中的逻辑是:

  • 松手时先判断是否超过长按阈值

  • 如果是长按,直接执行长按动作

  • 如果不是长按,才纳入点击次数统计

这说明:

  • 长按不应该再被当成一次单击

  • 单击、双击、三击属于短按序列

  • 长按计时变量和点击计数变量都需要在合适时机回正

依赖的前置知识

要稳定使用复杂按键,需要先理解:

  • 矩阵键盘或独立按键的基础扫描结果

  • key_val / key_down / key_up 三类信号的区别

  • 1ms 系统节拍和减速计数

  • 位掩码或组合键值的含义

其中最容易混淆的是:按住计时看 key_val,动作结算多看 key_up

常见错误

  • key_down 做长按计时,导致只加一次计数

  • 松手后忘记清零长按计时变量,下一次短按被误判为长按

  • 多击动作不等待窗口归零,导致双击先触发一次单击

  • 执行多击动作后忘记清零 click_cnt

  • 长按和单击没有互斥,长按松手后又被算作一次点击

  • 只记住组合键数值,不理解它来自按键位值叠加

这份知识层的边界

这份笔记只说明复杂按键识别中的状态、边沿、计时窗口和互斥关系。

暂时不展开:

  • 每个按键的可复用结构体封装

  • 多个按键同时支持长按和多击的通用框架

  • 比赛现场如何根据题意选择短按、长按或双击

  • 完整执行层代码模板

这些内容后续应继续放到:

  • 03-决策层

  • 04-执行层

  • 05-练习层

超短复习卡

  • key_val 看持续按住,key_down 看按下边沿,key_up 看松手边沿

  • 多按 = 按键组合值,常通过调试显示确认

  • 长按 = 按住计时,松手结算,结算后清零

  • 多击 = 松手计数,等待窗口归零后统一判定

  • 长按和多击共存时,长按优先,短按才进入点击计数