linux - 如何检测连续按下按钮的频率?

标签 linux multithreading bash

我想监视一个命令的输出,该命令一直无限运行并时不时打印一行。它显示硬件按钮的事件,每行表示一次按下。

我的脚本应该在收到行时运行其他命令,但问题是决定必须运行哪个命令的不是这些行的内容,而是给定延迟内的行数。

换句话说,用户可能会多次按下这个受监控的按钮,并且会根据按下按钮的频率执行不同的命令。在根据连续按下的次数选择命令之前,用户在两次按下之间有 2 秒的时间。

我目前有一个具有这种结构的 Bash 脚本:

#!/bin/bash
lasttouch="0"

MONITORING_COMMAND
| while read line; do     
    if [ $(date +%s --date="2 seconds ago") -lt $lasttouch ]       
    then
        COMMAND2
    else
        lasttouch=$(date +%s)
        COMMAND1
    fi    
done

然而,这只会处理最多两次连续的按下,并且它会在每个事件上执行 COMMAND1,即使随后的按下及时发生并且 COMMAND2 应该运行。

我实际上不知道如何在 Bash 中正确地实现它。我想我需要某种多线程,一个线程监听传入线路并增加一个计数器,另一个线程在每个事件后运行 2 秒的倒计时并重置计数器并在倒计时超时后执行适当的命令而没有其他事件。

最佳答案

您可以为单次推送设置一个函数,在执行 COMMAND1 之前等待所需的时间,用 $! 记录它的 pid,并在您实际收到双倍时杀死它在要求的时间之前推送。

这是一个延迟 700 毫秒的例子:

#!/bin/bash

MONITORING_COMMAND="your monitoring command here"
PUSH_NUM=1         #1 => until double push detection | 2 => until triple push detection etc...
MAX_DELAY=700      #the delay in between push in milliseconds

inc=0
remaining_delay=0

# wait_push <command value> <time left to sleep before taking the push>
wait_push()
{
    if [ ! -z "$2" ]; then
        sleep $2
    fi
    inc=0
    #switch between all your command here
    #COMMAND0 : normal push
    #COMMAND1 : double push
    #COMMAND2 : triple push etc..
    echo "push is detected here: execute $1 here"
    pid=""
    lasttouch=""
}

$MONITORING_COMMAND | while read line ; do 

    current=$(($(date +%s%N)/1000000))

    if [ ! -z "$lasttouch" ]; then

        diff=`expr $current - $lasttouch`

        if test $diff -lt $MAX_DELAY
        then

            inc=$((inc+1))

            if [ "$inc" -lt $PUSH_NUM ]; then

                if [ ! -z "$pid" ]; then
                    kill $pid 2>/dev/null
                    wait $pid 2>/dev/null
                fi
                remaining_delay=$((remaining_delay-diff))
                time=`awk -v delay=$remaining_delay 'BEGIN { print (delay / 1000) }'`
                #normal push
                wait_push "COMMAND${inc}" $time &
                pid=$!
                continue

            elif  [ "$inc" == $PUSH_NUM ]; then

                if [ ! -z "$pid" ]; then
                    kill $pid 2>/dev/null
                    wait $pid 2>/dev/null
                fi
                wait_push "COMMAND${inc}"
                continue

            fi
        else
            inc=0
        fi
    fi

    if [ "$inc" == 0 ]; then
        remaining_delay=$MAX_DELAY
        time=`awk -v delay=$MAX_DELAY 'BEGIN { print (delay / 1000) }'`
        #normal push
        wait_push "COMMAND${inc}" $time &
        pid=$!
    fi

    lasttouch=$current
done

你可以增加推送数量编辑变量PUSH_NUM :

  • 双推:PUSH_NUM=1
  • 三推:PUSH_NUM=2
  • 等等

您将在 wait_push 函数中进行所有命令处理。这考虑了所有连续推送事件之间的剩余时间(不超过 MAX_DELAY 毫秒)

关于linux - 如何检测连续按下按钮的频率?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38373112/

相关文章:

php - 从 Linux、PHP 连接到 SQL Server

c# - Task.Yield、Task.Run 和 ConfigureAwait(false) 之间有什么区别?

c++ - 从不同线程调用的 XInputGetState 和 XInputSetState

bash - 查找重复的嵌套目录

linux - 在 Linux 中的 awk 命令中使用 tr 命令

linux - 创建永久可执行别名

c - scanf 中断,printf 在线程中

linux - 如何为从源安装的程序创建终端命令

c# - 在 C# 中锁定线程

bash - 内置的 csh 'where' 的 bash 等价物是什么?