簡體   English   中英

如何接受箭頭鍵輸入或接受方向輸入?

[英]How do I accept input from arrow keys, or accept directional input?

這可能是一個xy問題,但我正在嘗試構建一個基於內核的文本編輯器,類似於vimnano ,我知道如何使用轉義字符清除屏幕,然后重新打印,我可以讓它接受字符,但我不知道如何讓它接受箭頭輸入導航。 我認為它們有ASCII值,但顯然不是。 有沒有辦法使用箭頭,還是我必須進行導航模式和插入模式像vim

我也曾簡短地玩curses ,但這是令人望而卻步的,因為據我所知,必須為它打開一個全新的窗口,這與我所擁有的單個終端窗口的視覺不兼容。

編輯: curses也是禁止,因為它清除了窗口,我不想要。

curses 正是你想要的。 事實上,我相信vim實現了與curses的接口。

嘗試將以下代碼放入名為test_curses.py的文件中:

import curses

screen = curses.initscr()
screen.addstr("Hello World!!!")
screen.refresh()
screen.getch()
curses.endwin()

現在打開一個終端 (不是IDLE!一個真正的終端!)並通過以下方式運行它:

python test_curses.py

你應該看到終端被清除了, Hello World!!! 寫作出現了。 按任意鍵,程序將停止,恢復舊的終端內容。

請注意, curses庫並不像您習慣的那樣簡單且“用戶友好”。 我建議閱讀教程 (不幸的是C語言,但python接口大致相同)

我結束使用此問題的代碼,並修改__init__語句,使其在列表中最多接受3個字符。

import sys

class _Getch:
   """Gets a single character from standard input.  Does not echo to the
screen."""
   def __init__(self):
      self.impl = _GetchUnix()

   def __call__(self):# return self.impl()
      charlist = []
      counter = 0
      for i in range(3):
         try:charlist.append(self.impl())
         except:pass
         if charlist[i] not in [chr(27),chr(91)]:#TODO sort out escape vs arrow duh use len()
            break
         if len(charlist) > 1:
            if charlist == [chr(27),chr(27)]:
               break
      if len(charlist) == 3:
         if charlist[2] == 'a'
            return 'u-arr'
         if charlist[2] == 'b'
            return 'd-arr'
         if charlist[2] == 'c'
            return 'r-arr'
         if charlist[2] == 'd'
            return 'l-arr'
      if len(charlist == 2):
         if charlist == [chr(27),chr(27)]
            return chr(27)
      if len(charlist == 1)
         return charlist[0]
      return ''

class _GetchUnix:
   def __init__(self):
      import tty, sys

   def __call__(self):
      import sys, tty, termios
      fd = sys.stdin.fileno()
      old_settings = termios.tcgetattr(fd)
      try:
         tty.setraw(sys.stdin.fileno())
         ch = sys.stdin.read(1)
      finally:
         termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
      return ch

這允許我從編輯器的鍵盤獲取箭頭鍵以及所有其他字符和轉義序列。 它使得“Getch”類不是嚴格意義上的get char克隆,因為它返回一個字符串,但它更有用。

用於構建命令行客戶端的Python包click還附帶了一個允許您獲取按鍵事件的實現:

import click

key = click.getchar()

它將鍵表示作為Unicode字符返回,並且“箭頭鍵之類的東西將以平台的本機轉義格式顯示。”

這是直接來自getchar單擊文檔的示例:

import click

click.echo('Continue? [yn] ', nl=False)
c = click.getchar()
click.echo()
if c == 'y':
    click.echo('We will go on')
elif c == 'n':
    click.echo('Abort!')
else:
    click.echo('Invalid input :(')

按箭頭鍵或按下時的任何其他鍵執行所需操作

# key_event_handler.py

import sys
import select
import pty
import os
import time
import fcntl
import tty
import termios
def __select( iwtd, owtd, ewtd, timeout=None):

   '''This is a wrapper around select.select() that ignores signals. If
   select.select raises a select.error exception and errno is an EINTR
   error then it is ignored. Mainly this is used to ignore sigwinch
   (terminal resize). '''

   # if select() is interrupted by a signal (errno==EINTR) then
   # we loop back and enter the select() again.
   if timeout is not None:
       end_time = time.time() + timeout
   while True:
       try:
           return select.select(iwtd, owtd, ewtd, timeout)
       except select.error:
           err = sys.exc_info()[1]
           if err.args[0] == errno.EINTR:
               # if we loop back we have to subtract the
               # amount of time we already waited.
               if timeout is not None:
                   timeout = end_time - time.time()
                   if timeout < 0:
                       return([], [], [])
           else:
               # something else caused the select.error, so
               # this actually is an exception.
               raise

STDIN_FILENO=pty.STDIN_FILENO
STDOUT_FILENO=pty.STDOUT_FILENO
string_type=bytes
sys.stdout.write(string_type())
sys.stdout.flush()
buffer = string_type()
mode = tty.tcgetattr(STDIN_FILENO)
tty.setraw(STDIN_FILENO)
try:
    while True:
        r, w, e = __select([STDIN_FILENO], [], [],timeout=1)
        if STDIN_FILENO in r:
            #It accepts all keys from keyboard 
            data=os.read(STDIN_FILENO, 1)
            #Bellow line returns ASCII value of a charector
            ascii_value=ord(data[0])
            ##########################################################################
            ##                      Your code goes here                             ## 
            ##                                                                      ##
            # Do some action here by matching the ASCII value                        #
            # you can handle your program by making use of special keys like         #
            # Backspace, Ctrl, Ctrl+A,Ctrl+B, Ctrl+C, ...Ctrl+Z, Esc,F1, ...,F12 ....#
            # Tab,Enter,Arrow keys,Alphabetic and Numeric keys are also supported    #  
            ##########################################################################
            #                                                                        #
            #To Print use bellow line rather than print or sys.stdout.write(data)    #
            #os.write(STDOUT_FILENO,data)                                            #
            ##                                                                       #
            ##########################################################################


finally:
    tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode) 

然后打開終端並運行key_event_handler.py


這個程序主要是捕獲按鍵和按下ascii鍵,這個程序也可以用於多線程應用程序中的非阻塞I / O

我知道我遲到了,但我真的很喜歡@elbaschid提到的click包。 我不知道為什么他沒有被投票 - 也許是因為他的例子沒有顯示如何處理專門的光標鍵。

這是我的0.02美元:

#!/usr/bin/python

import click

printable = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'

while True:
    click.echo('Continue? [yn] ', nl=False)
    c = click.getchar()
    click.echo()
    if c == 'y':
        click.echo('We will go on')
    elif c == 'n':
        click.echo('Abort!')
        break
    elif c == '\x1b[D':
        click.echo('Left arrow <-')
    elif c == '\x1b[C':
        click.echo('Right arrow ->')
    else:
        click.echo('Invalid input :(')
        click.echo('You pressed: "' + ''.join([ '\\'+hex(ord(i))[1:] if i not in printable else i for i in c ]) +'"' )

這會處理光標鍵,並作為獎勵打印它尚未識別的任何鍵盤快捷鍵的py-string表示。 例如,Ctrl-s是"\\x13" 您可以稍后在另一個內部使用它

elif c == ??

我試圖將編輯添加到@elbaschid的答案,但它被拒絕了¯\\ _(ツ)_ /¯。 如果你也喜歡我的答案,請給他信任

令人敬畏的庫,用於快速命令行原型設計。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM