Answers:
从根本上讲,您不能这样做。组合键需要排序,排序需要事件。
您可以做的是通过比较每个帧的键状态并根据差异生成事后的键上/键下事件,将轮询转换为事件。它不那么可靠,因为您丢失了“本机”事件系统提供的时间戳和其他帧内排序,但是它使您可以检测和排序每帧至少一个键。
一旦有了这些顺序事件,就可以使用有限状态机或其他工具将它们与您的移动列表进行匹配,并执行正确的事件。
一种方法是存储当前和先前的输入状态,并在每次轮询输入时进行比较。
对于每个可以按下的键,存储一个对象,该对象的时间戳为该键从按下状态切换到按下状态的最后时间。
通过在每次轮询中执行以下操作来更新这些对象:
void update(){
some_key_has_been_pressed = false;
foreach(key in keys){
if(previous_input[key].Down && current_input[key].Up){
keys[key].up_timestamp = current_time();
}
if(current_input[key].Down){
keys[key].down_timestamp = current_time();
some_key_has_been_pressed = true;
}
}
}
现在,您可以根据的内容对组合进行模式匹配keys
。
每个组合都有一个组合对象,并在每次轮询时对每个组合对象调用update()。
组合对象的update()方法将对组合进行模式匹配,并检查此轮询是否满足组合的所有必要条件。也就是说,到目前为止,该组合的所有键时间戳都是正确的,并且没有其他可能破坏组合的键被按下此框。对于满足的每个条件,将组合对象中的计数器增加到下一个要检查的条件。当组合中满足所有条件时,调用组合应执行的方法。如果some_key_has_been_pressed == true
但尚未按下组合的下一个条件键,则将组合的满足条件计数器重置为0。
上面是我的首选方法,因为它易于实现,易于维护,高效且高度模块化。
但是,对于另一种好的方法,请查看用C#编写的XNA输入序列样本,并且该逻辑可能可以转移到您使用的语言。
if(current_input[key].down){
您是否还不想检查密钥是否在该previous_input
状态下?照我所写,我认为它将不断更新一个持有的钥匙down_timestamp
。
堆叠最后的X个按键事件,为每个按键事件添加一个带有按键和按下/释放时间的对象,然后检查堆栈中的最后一个成员是否与特殊模式匹配,以及是否按下这些键的速度足够快以至于算作一个组合。最后,从堆栈中删除最旧的对象。