
Introdução
Para digitar no teclado, sente-se ou fique parado. Os gamepads, por outro lado, são portáteis e compactos. Ao controlá-los, você pode caminhar pela sala ou deitar no sofá.
Devido ao pequeno número de botões no gamepad, ninguém os considerava um meio de inserir textos volumosos, por exemplo, na programação.
No entanto, os joysticks analógicos (e muitos gamepads têm dois) têm o potencial de fornecer opções de entrada infinitas. A questão se resume a escolher os gestos certos para obter eficiência máxima e tensão mínima nos polegares.
Existem muitas maneiras de inserir texto em gamepads. Se você já jogou jogos de console, provavelmente já usou alguns deles.

Entrada de texto na tela em Legend of Zelda
Em Legend of Zelda, o jogador deve se revezar selecionando letras usando o direcional com setas e pressionando o botão confirmar para adicionar uma letra ao campo de entrada de texto.
Desde então, métodos de entrada mais eficientes foram desenvolvidos. Se você estiver interessado, leia o artigo sobre Gamasutra .
Infelizmente, todos os métodos de entrada que encontrei têm duas falhas principais que os tornam inadequados para um trabalho sério:
- Eles não são rápidos o suficiente
- Eles exigem feedback visual
A necessidade de velocidade é clara. O feedback visual é inaceitável porque ocupa um espaço valioso na tela e distrai o usuário, o que pode interferir no fluxo e diminuir a velocidade.
No entanto, na ausência de feedback, todos os gestos devem ser memorizados e praticados até que você possa inseri-los com precisão suficiente. Os videogames provavelmente não forçarão o usuário a passar algumas semanas aprendendo como inserir texto, mas para uma maneira de inserir texto que pode ser usado em qualquer programa, o preço é aceitável e o treinamento em si é como dominar a entrada de toque.
Nesta postagem, vou percorrer brevemente as etapas envolvidas na criação de um sistema de entrada de texto para gamepads que seja adequado como um substituto para entrada de teclado volumétrico.
Decidindo sobre os gestos
Para começar, criei uma ferramenta para visualizar o movimento de joysticks analógicos de gamepad baseada na
pygame
linguagem Python. Para maior clareza, complementei a ferramenta para que ela não apenas mostre as posições atuais dos bastões, mas também as posições anteriores de tons cada vez mais claros de cinza, para que você possa ver os caminhos ao longo dos quais os bastões se movem.
A figura abaixo mostra os movimentos simultâneos de ambas as alavancas analógicas para dentro, para cima, para fora, para baixo, para dentro novamente e de volta ao centro.

Visualizando padrões de movimento de manípulos analógicos
A primeira coisa que notei é que, uma vez que o estado neutro do gamepad é localizar os manípulos no centro, todas as opções de entrada devem ser alcançáveis a partir desse estado neutro e todas devem ser concluídas retornando os manípulos ao centro.
Com essas limitações em mente, descobri que a entrada mais simples possível seria mover uma das baquetas em qualquer direção e de volta ao centro.

O controle esquerdo se moveu para cima e de volta ao centro.
Quantas direções e exatamente quais direções você pode selecionar às cegas? Considere o seguinte exemplo.

O controle esquerdo se moveu para cima, para baixo, no centro, para a esquerda e para a direita, e o controle direito moveu-se diagonalmente
. Alguns minutos de experimentação mostraram que era possível selecionar com precisão as direções ao longo dos eixos, e a entrada em outras direções era muito menos precisa (como visto na imagem anterior).
Os próximos métodos de entrada mais simples encontrados foram movimentos circulares de um e dois estágios.

O manípulo esquerdo foi movido para cima, para a esquerda e de volta ao centro

O controle esquerdo moveu-se para cima, para a esquerda, para baixo e de volta ao centro.
Levando em consideração todos os gestos inventados até agora, obtivemos 4 + 8 + 8 = 20 opções de entrada em cada controle.
Claro, os dois manípulos podem ser movidos ao mesmo tempo, criando gestos de entrada combinados.

Ambos os manípulos movem-se para cima e para trás ao mesmo tempo. A combinação de
gestos dá um total de 20 * 20 + 20 + 20 = 440 opções de entrada, o que, na minha opinião, é mais do que suficiente.
Gestos de codificação
Dividi o espaço de entrada de cada stick em 4 setores e atribuí um número a cada setor.

Espaços de entrada divididos em setores
Em seguida, defino uma área limite ao redor do centro para ajudar a determinar se o manche está na posição neutra ou em um dos setores.

Peitoril circular em torno do centro
Como você pode ver, o raio do peitoril é bastante grande. Por meio da experimentação, determinei que este é o melhor raio que fornece a menor quantidade de erro.
Quando qualquer um dos manípulos está fora do centro, cruzando a área limite, a sequência de entrada começa. Quando ambas as baquetas retornam ao centro dentro da área limite, a sequência é considerada completa e é convertida em um par de tuplas que descreve o movimento das baquetas.

Mova os manípulos para entrada ((0,), (2, 3))
Vinculando gestos a ações
Nesse caso, as ações são apenas teclas do teclado. Os botões de disparo do gamepad podem ser vinculados às teclas Shift, Ctrl, Alt e Super, o que é conveniente porque essas teclas são usadas em combinações (por exemplo, Ctrl-C).
Para determinar a combinação ideal do gesto e da tecla inseridos, usei um keylogger para registrar todas as teclas digitadas e analisei a frequência de cada tecla por várias semanas.
As teclas pressionadas com mais frequência devem estar associadas aos gestos mais simples (e, portanto, os mais rápidos). Estimei a complexidade do gesto adicionando os comprimentos das entradas de cada stick. Por exemplo, a entrada mostrada acima ((0,), (2, 3)) tem complexidade 1 + 2 = 3.
Neste caso, ao entrar de um stick, o uso alternado de dois stick será mais rápido do que várias entradas do mesmo stick, por isso é geralmente melhor ligar as teclas a serem digitadas em diferentes sticks.
Seguindo essa lógica, primeiro gerei todas as opções de entrada possíveis de um stick e as agrupei por dificuldade. Contei o número de entradas em cada grupo de dificuldade e peguei o número de chaves de uma lista ordenada das chaves mais frequentes.
Meu objetivo era dividir essas teclas em dois grupos, um para entrada do controle esquerdo e outro para o controle direito. Para encontrar grupos ideais, criei um gráfico no qual os nós eram as chaves e as arestas ponderadas eram as frequências das combinações de chaves.
Eu removi ciclicamente a borda de menor peso até que o gráfico se tornasse bipartido. Se o gráfico se desconectou, apliquei recursivamente o algoritmo de particionamento aos componentes conectados e, finalmente, combinei os grupos em conjuntos independentes.
Considere o seguinte exemplo. O primeiro grupo de complexidade consiste em todas as entradas com complexidade 1, ou seja
((0,), ()), ((1,), ()), ((2,), ()), ((3,), ()), ((), (0,)), ((), (1,)), ((), (2,)), ((), (3,))
.
Existem 8 entradas neste grupo, portanto, pegamos as 8 chaves mais frequentes da lista classificada. Isso é
'e', 'o', 't', 'a', 'i', 's', 'j', 'r'
. Crie um gráfico com essas chaves como nós e atribua pesos às arestas entre esses nós de acordo com a frequência de cada combinação de teclas.

As teclas e e r são mais frequentemente combinadas, portanto, devem ser fixadas em diferentes palitos.
Ao remover as bordas fracas do gráfico, mais cedo ou mais tarde ele se tornará desvinculado.

A tecla j é comum, mas está isolada.
Você pode estar se perguntando por que a tecla
j
é uma das 8 teclas mais frequentes, mas tem ligações tão fracas com o resto das teclas frequentes. A razão é que ele é j
usado ativamente ao trabalhar com o VIM plus, no meu sistema isso faz parte de uma combinação de teclas de atalho para alternar entre janelas. Portanto, é mais frequentemente usado isoladamente do que no texto.
Como o gráfico está desconectado, continuo a aplicar o algoritmo aos componentes conectados. Um subgráfico consistindo apenas de um nó
j
já é bipartido ( j
+ conjunto vazio). Estou aplicando recursivamente o algoritmo a outro componente.

Depois de remover as arestas mais fracas, o componente se torna bipartido.
O componente pode então ser facilmente dividido em dois grupos, sem arestas entre os nós do grupo.

Esquema de componentes bipartidos
No final, eu combino os conjuntos bipartidos.

O agrupamento obtido para as primeiras 8 teclas
Como você pode ver, os links mais fortes (os atalhos de teclado mais frequentes) estão localizados entre os nós em lados diferentes, que é exatamente o que eu queria.
Repeti esse processo para os outros grupos de dificuldade (entradas de um stick apenas). Em seguida, gerei todas as entradas combinadas possíveis, agrupei-as novamente por dificuldade e atribuí as teclas restantes a essas opções de entrada. Como as entradas combinadas requerem o uso de ambas as baquetas, o problema de dividir as chaves em dois grupos não surge aqui.
Usei o pacote
pyautogui
Python para gerar eventos de teclado quando ações são acionadas.
Prática
Usei o mesmo treinador de toque que
ktouch
já usava para ensinar datilografia há quase duas décadas. Para isso, criei aulas especializadas.

Praticar entrada analógica em um gamepad no ktouch
Observações
- Embora o processo Python que executa esse sistema de entrada normalmente não consuma mais do que 10% dos recursos da CPU, se ele tivesse que ser executado constantemente em segundo plano, eu o reimplementaria e o otimizaria em uma linguagem de nível inferior para que o processador possa fazer mais tarefas caras.
- Depois de comprar um gamepad DualShock4, percebi que posso fazer entradas diagonais com bastante precisão. A integração da entrada diagonal reduzirá o número de opções de entrada mais complexas e, portanto, aumentará a velocidade.
- , . , . , , , .
- , . , , .
- . .
Em apenas alguns dias, criei um sistema de entrada eficiente para gamepads. Existem muitas melhorias que podem ser feitas, mas esta verificação de conceito demonstra que a digitação eficiente do gamepad é possível. O código do projeto está postado no github .