Ubuntu终端键盘输入采样(python实现)

1、设置终端为 raw mode:

import sys
from termios import *
_old_settings = tcgetattr(sys.stdin.fileno())
IFLAG, OFLAG, CFLAG, LFLAG, ISPEED, OSPEED, CC = 0, 1, 2, 3, 4, 5, 6
def setraw_input(fd, when=TCSAFLUSH):
    """Put the input of the terminal into a raw mode."""
    mode = tcgetattr(fd)
    mode[IFLAG] = mode[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON)
    # mode[OFLAG] = mode[OFLAG] & ~(OPOST)
    mode[CFLAG] = mode[CFLAG] & ~(CSIZE | PARENB)
    mode[CFLAG] = mode[CFLAG] | CS8
    mode[LFLAG] = mode[LFLAG] & ~(ECHO | ICANON | IEXTEN | ISIG)
    mode[CC][VMIN] = 1
    mode[CC][VTIME] = 0
    tcsetattr(fd, when, mode)
    return

  setraw_input 方法参考 python 中的 tty.setraw 方法实现,仅仅取消 OFLAG 的改变,使得终端能够继续处理输出中的特殊字符,以避免输出乱码。

2、键盘输入采样:

import select
def _get_key():
    key ''
    for index in range(0, 10):
        rlist, _, _ = select.select([sys.stdin], [], [], 0)
        if rlist:
            key = sys.stdin.read(1)
    return key
 
 
import threading, traceback
_timer = None
from functools import wraps
def input_wrap(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            key = _get_key()
            func(key)
            if key == '\x03':
                print("ctrl + c")
                raise Exception("ctrl + c")
            global _timer
            _timer = threading.Timer(0.1, wrapper)
            _timer.start()
        except Exception:
            input_wrap_reset()
        return
    return wrapper

  键盘输入采样频率为 10Hz (0.1s), _get_key 方法中的 for 循环次数计算如下:

假设键盘输入速率 25char/s (长按不放)
10 (循环次数) = 25 (输入速率) x 2 (采样定理) x 2 (安全系数) / 10 (采样频率)

3、自定义键盘输入处理方法:

@input_wrap
def print_key(key):
    if key != "":
        print(key)
    return

4、完整代码:

  input_wrap.py

#!/usr/bin/env python
 
 
import sys
from termios import *
_old_settings = tcgetattr(sys.stdin.fileno())
IFLAG, OFLAG, CFLAG, LFLAG, ISPEED, OSPEED, CC = 0, 1, 2, 3, 4, 5, 6
def setraw_input(fd, when=TCSAFLUSH):
    """Put the input of the terminal into a raw mode."""
    mode = tcgetattr(fd)
    mode[IFLAG] = mode[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON)
    # mode[OFLAG] = mode[OFLAG] & ~(OPOST)
    mode[CFLAG] = mode[CFLAG] & ~(CSIZE | PARENB)
    mode[CFLAG] = mode[CFLAG] | CS8
    mode[LFLAG] = mode[LFLAG] & ~(ECHO | ICANON | IEXTEN | ISIG)
    mode[CC][VMIN] = 1
    mode[CC][VTIME] = 0
    tcsetattr(fd, when, mode)
    return
 
 
def input_wrap_set():
    setraw_input(sys.stdin.fileno())
    return
 
 
def input_wrap_reset():
    tcsetattr(sys.stdin.fileno(), TCSAFLUSH, _old_settings)
    return
 
 
import select
def _get_key():
    key ''
    for index in range(0, 10):
        rlist, _, _ = select.select([sys.stdin], [], [], 0)
        if rlist:
            key = sys.stdin.read(1)
    return key
 
 
import threading, traceback
_timer = None
from functools import wraps
def input_wrap(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            key = _get_key()
            func(key)
            if key == '\x03':
                print("ctrl + c")
                raise Exception("ctrl + c")
            global _timer
            _timer = threading.Timer(0.1, wrapper)
            _timer.start()
        except Exception:
            input_wrap_reset()
        return
    return wrapper
 
 
@input_wrap
def print_key(key):
    if key != "":
        print(key)
    return
 
 
if __name__ == "__main__":
    input_wrap_set()
    print("hello, world!\thello, world!")
    print_key()
    import time
    try:
        while True:
            time.sleep(1)
    except:
        pass
    finally:
        input_wrap_reset()
    print("hello, world!\thello, world!")

猜你喜欢

转载自www.cnblogs.com/Ezekiel/p/9067359.html
今日推荐