Как мне запрограммировать нажатие двойной клавиши, чтобы немодифицирующая клавиша в моей программе работала как клавиша-модификатор?

Я пишу программу ввода текста, которая включает в себя гораздо больше символов, чем доступно на стандартной клавиатуре. Для этого мне нужно преобразовать некоторые из букв алфавита в клавиши-модификаторы CTRL + A. Например, F + J будет выводить a, Печатание f тогда j медленно для пользователя, мне нужно, чтобы они могли одновременно нажимать f и j и получать один вывод. Это нормально (даже предпочтительнее), если некоторые нормальные функции клавиатуры останавливаются во время работы программы.

Я посмотрел в Pygame Keydown, но кажется, что он имеет функции для увеличения повторения клавиш, а не остановки вывода клавиш. Pyglet также возможен, но у него нет точной документации о том, как я мог бы сделать дополнительные клавиши-модификаторы. Единственный способ, которым я могу понять, - это постоянно сканировать всю клавиатуру, чтобы увидеть, нажаты ли какие-либо клавиши, но это не определит порядок нажатия клавиш и создаст ошибки для пользователя, так как пользователь нажимает клавишу f j будет читаться так же, как пользователь нажимает j, затем f, и мне нужно, чтобы система воспринимала только комбинацию f и j как нажатие клавиши.

2 ответа

Вот простой код для быстрой печати клавиш, написанных на Python 2. Его можно легко модифицировать в соответствии с вашими потребностями:

import pygame, sys
pygame.init()
screen = pygame.display.set_mode([500,500])
clock = pygame.time.Clock()

combokeys = []
timer = 0
ACCEPTABLE_DELAY = 30 #0.5 seconds

while 1:
    clock.tick(60)
    timer += 1
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if timer <= ACCEPTABLE_DELAY:
                combokeys.append(event.unicode)
            else:
                combokeys = [event.unicode]
            timer = 0
            print combokeys

Я не смог протестировать этот код (работает на школьном компьютере), поэтому, пожалуйста, сообщите мне в комментариях, если что-то не работает, чтобы я мог это исправить.

Вы можете изменить значение, указанное для ACCEPTABLE_DELAY, чтобы изменить задержку, прежде чем что-то будет считаться другой комбинацией клавиш. Задержка должна составлять (ACCEPTABLE_DELAY/60) секунд.

Вот версия Pyglet о том, как вы можете это сделать.
Я основал его на общем классе GUI, который я часто использую здесь, на SO, потому что он модульный и его легче построить, не запутавшись в коде после 40 строк.

import pyglet
from pyglet.gl import *

key = pyglet.window.key

class main(pyglet.window.Window):
    def __init__ (self):
        super(main, self).__init__(800, 800, fullscreen = False)
        self.x, self.y = 0, 0

        #self.bg = Spr('background.jpg')
        self.output = pyglet.text.Label('',
                          font_size=14,
                          x=self.width//2, y=self.height//2,
                          anchor_x='center', anchor_y='center')

        self.alive = 1
        self.pressed = []
        self.key_table = {213 : 'a'}

    def on_draw(self):
        self.render()

    def on_close(self):
        self.alive = 0

    def on_key_release(self, symbol, modifiers):
        if symbol == key.LCTRL:
            pass # Again, here's how you modify based on Left CTRL for instance

        ## All key presses represents a integer, a=97, b=98 etc.
        ## What we do here is have a custom key_table, representing combinations.
        ## If the sum of two pressed matches to our table, we add that to our label.
        ## - If no match was found, we add the character representing each press instead. 
        ##   This way we support multiple presses but joined ones still takes priority.

        key_values = sum(self.pressed)
        if key_values in self.key_table:
            self.output.text += self.key_table[key_values]
        else:
            for i in self.pressed:
                self.output.text += chr(i)
        self.pressed = []

    def on_key_press(self, symbol, modifiers):
        if symbol == key.ESCAPE: # [ESC]
            self.alive = 0
        elif symbol == key.LCTRL:
            pass # Modify based on left control for instance
        else:
            self.pressed.append(symbol)

    def render(self):
        self.clear()
        #self.bg.draw()

        self.output.draw()

        self.flip()

    def run(self):
        while self.alive == 1:
            self.render()

            # -----------> This is key <----------
            # This is what replaces pyglet.app.run()
            # but is required for the GUI to not freeze
            #
            event = self.dispatch_events()

x = main()
x.run()

Это может выглядеть как много кода, особенно для ответа Pygame. Но вы также можете сократить это до ~15 строк, но, опять же, код станет запутанным, если вы попытаетесь использовать его дальше.

Надеюсь, это работает. Теперь я не продумал математическую схему этого вопроса. Возможно, две дублированные комбинации клавиш приведут к тому же значению, что и другое представление ключа, просто замените ключи словаря. 213 например, с ключом кортежа, таким как self.key_table = {(107, 106) : 'a'} который будет представлять K+J

Несколько преимуществ:

  • Нет необходимости отслеживать задержки
  • Быстро и отзывчиво
  • Любую клавишу можно превратить в модификатор или сопоставить с пользовательскими раскладками клавиатуры, что означает, что вы можете превратить QWERTY в DWORAK только для этого приложения. Не уверен, почему вы этого хотите, но эй.. Это не мое дело:D
  • Переопределяет ввод с клавиатуры по умолчанию, поэтому вы можете перехватывать их и делать с ними все, что захотите.

Редактировать: одна интересная особенность - зарегистрировать каждую клавишу вниз, но заменить последний символ объединенной комбинацией. Опять же, это все ручные работы, поскольку клавиатура не предназначена для представления двойных клавиш, и это скорее графический идея.. Но было бы круто:)

Другие вопросы по тегам