Captura de toques de teclado
Atalhos de Teclado
Na seção Widgets: Atalhos de Teclado vimos como capturar a interação do usuário com o aplicativo através de eventos de teclados. A captura de eventos produzidos pelo teclado se dá através do evento page.on_keyboard_event, que gerencia o pressionamento de teclas de letras em combinação com teclas de controle. Esse evento passa o parâmetro e que é uma instância da classe KeyboardEvent, e tem as seguintes propriedades:
e.key |
Representação textual da tecla pressionada. |
e.shift |
Booleano: True se a tecla “Shift” foi pressionada. |
e.ctrl |
Booleano: True se a tecla “Control” foi pressionada. |
e.alt |
Booleano: True se a tecla “Alt” foi pressionada. |
e.meta |
Booleano: True se a tecla “Meta” foi pressionada††. |
Desta forma conseguimos capturar o pressionamento de uma única letra, além de Enter, Backspace, F1 … F12, Escape, Insert, Page Down, Pause, etc, ou de combinações como Ctrl-F ou Ctrl-Shift-Enter.
Como exemplo adicional vamos exibir o código de um jogo que captura a interação com o teclado. Uma combinação de teclas como Ctrl-H ou SHIFT-L é exibida em um container que desce do topo da página. Se o usuário digita a mesma combinação ele pontua (10 pontos de cada vez) e nova combinação é exibida.
1 import flet as ft 2 import time, random, string 3 4 cores = ["#FFC6C6", "#A8DCEA", "#BAF3E4", "#F1E9AF", 5 "#CBB1CE", "#B2C9F3", "#F0DCBE", "#F1D7B3"] 6 7 def main(page: ft.Page): 8 def sortear(): 9 ct.top = 10 10 ct.left = random.randrange(100, 1000) 11 ct.height=80 12 t1 = ["Shift", "Alt", "Ctrl"][random.randrange(0, 3)] 13 t2 = random.choice(string.ascii_letters).upper() 14 ct.content = ft.Text(f"{t1}-{t2}", size=20) 15 ct.bgcolor = cores[random.randrange(0, 8)] 16 ct.visible = True 17 18 def fim(e): 19 page.window_destroy() 20 21 def inicio(e): 22 while True: 23 sortear() 24 while ct.top < 400: 25 time.sleep(.3) 26 ct.top += 10 27 page.update() 28 inicio(e) 29 30 def teclou(e): 31 txt = "Shift" if e.shift else "Alt" if e.alt else "Ctrl" if e.ctrl else "" 32 txt = f"{txt}-{e.key}" 33 34 if ct.content.value == txt: 35 pts = int(txtPontos.value.split(":")[1]) + 10 36 txtPontos.value = f"Sua pontuação: {str(pts)}" 37 ct.bgcolor = "red" 38 while ct.top < 400: 39 time.sleep(.01) 40 ct.top += 10 41 ct.height -= 3 42 page.update() 43 44 ct = ft.Container(padding = 15, width=180, alignment = ft.alignment.center, 45 border = ft.border.all(2, "black"), 46 border_radius = ft.border_radius.all(15), 47 blur=90, visible = False) 48 49 btInicio = ft.ElevatedButton("Começar Jogo", bgcolor="white", 50 width=180, height= 40, on_click=inicio) 51 btFim = ft.ElevatedButton("Terminar Jogo", bgcolor="white", 52 width=180, height= 40, on_click=fim) 53 txtPontos = ft.Text("Sua pontuação: 0", size=27, weight=ft.FontWeight.BOLD) 54 lin = ft.Text("Acerte a combinação de teclas mostrada na tela (Ctrl, Shift, Alt) + Letra", 55 size=27) 56 linha1 = ft.Row([lin], alignment=ft.MainAxisAlignment.SPACE_EVENLY) 57 linha2 = ft.Row([btInicio, txtPontos, btFim], 58 alignment=ft.MainAxisAlignment.SPACE_EVENLY) 59 60 page.add(linha1, linha2, ft.Stack([ct])) 61 page.on_keyboard_event = teclou 62 63 ft.app(target=main)
O início do jogo ocorre quando se clica o botão btInicio que dispara a função inicio(). Dentro dela um loop infinito promove várias interações do container descendo a tela (o que é obtido com container.top += 10). Quando o container chega em seu valor máximo estabelecido, no caso ct.top < 400
, novos valores são sorteados como suas propriedades e o container e redesenhado no topo.
O sorteio define a posição (top) inicial, uma cor aleatória escolhida dentro de uma lista de cores (linha 15) e monta uma string para representar uma combinação de teclado (linhas 12 a 14). A linha 13 usa random.choice()
para escolher aleatoriamente um dos caracteres de string.ascii_letters
, e torná-lo maísculo. Esse carater é juntando à um controle. A tecla de controle Meta (Windows) não foi usada pois é comum que ela esteja associada a atalhos globais do computador, em algumas instalações.
A interação do usuário é capturada em teclou que compara a combinação sorteada com aquela teclada pelo usuário. Se ocorreu um acerto ela incrementa a pontuação, derruba o container (acelerando sua queda) e sorteia nova combinação. O loop infinito iniciado na linha 22 só é terminado com o evento btFim.on_click
.
Captura de teclas no Python
Claro que podemos capturar o pressionamento de tecla no Python, sem usar os métodos do Flet. Para isso podemos instalar, entre outras escolhas, o módulo keyboard, que funciona em sistemas operacionais Windows e Linux.
# Instale o módulo de teclado usando PIP: pip install keyboard # No Python 3 instale usando o comando: pip3 install keyboard
Para detectar pressionamentos de teclas podemos usar a função is_pressed(). Esse método recebe um caractere como entrada e retorna True se essa tecla foi pressionada. O exemplo seguinte usa um loop que só é terminado com o pressionamento da tecla f.
import keyboard print("Pressione 'f' para terminar.") while True: if keyboard.is_pressed("a"): print("A tecla 'f' foi pressionada!") break
A função keyboard.is_pressed("f")
retorna False se qualquer outra tecla fopr pressionada.
Também podemos usar a função read_key() para capturar pressionamentos de teclas. Essa função retorna a tecla pressionada pelo usuário.
import keyboard while True: print(keyboard.read_key()) if keyboard.read_key() == "f": print("Você terminou o loop pressionando 'f'.") break
Esse código exibe na tela todas as teclas pressionadas até que se tecle “f”.
Outra forma de captura de pressionamento de teclas usa a função wait(), que recebe um caractere como entrada. Quando executado o programa é pausado até que seja pressionada a tecla passada como argumento para a função.
import keyboard keyboard.wait("f") print("Você digitou 'f'.")
Nesse último exemplo fica dispensado o uso de um loop para suspender a execução do código.
Bibiografia
- Python for Beginners: How to Detect Keypress in Python
- Alura: Convenções de nomenclatura: Camel, Pascal, Kebab e Snake case.