Na verdade, me deparei com esse dilema com a entrada do Xbox Controller. Embora não seja exatamente o mesmo, é bem parecido. Você pode alterar o código no meu exemplo para atender às suas necessidades.
Edit: Sua situação usaria isso ->
https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-tagrawmouse
E você pode aprender como criar uma classe de entrada bruta via ->
https://docs.microsoft.com/en-us/windows/desktop/inputdev/raw-input
Mas .. agora no algoritmo super impressionante ... não realmente, mas ei .. é muito legal :)
* Então ... podemos armazenar os estados de cada botão e quais são Pressionados, Liberados e Retidos !!! Também podemos verificar o tempo de espera, mas isso requer uma única declaração if e pode verificar qualquer número de botões, mas existem algumas regras, veja abaixo para obter essas informações.
Obviamente, se quisermos verificar se alguma coisa foi pressionada, liberada, etc. você faria "If (This) {}", mas isso está mostrando como podemos obter o estado da impressora e depois desligá-lo no próximo quadro para que você " ismousepressed "será realmente falso na próxima vez que você verificar.
Código completo aqui:
https://github.com/JeremyDX/DX_B/blob/master/DX_B/XGameInput.cpp
Como funciona..
Portanto, não tenho certeza dos valores que você recebe quando mostra se um botão é pressionado ou não, mas basicamente quando carrego no XInput, recebo um valor de 16 bits entre 0 e 65535, que possui estados possíveis de 15 bits para "Pressed".
O problema era que toda vez que eu checava isso, simplesmente me informava o estado atual das informações. Eu precisava de uma maneira de converter o estado atual em valores pressionados, liberados e retidos.
Então, o que eu fiz é o seguinte.
Primeiro, criamos uma variável "CURRENT". Toda vez que verificamos esses dados, configuramos o "CURRENT" como uma variável "ANTERIOR" e, em seguida, armazenamos os novos dados em "Atual", como visto aqui ->
uint64_t LAST = CURRENT;
CURRENT = gamepad.wButtons;
Com essas informações, é aqui que fica emocionante !!
Agora podemos descobrir se um botão está sendo pressionado!
BUTTONS_HOLD = LAST & CURRENT;
O que isso faz é basicamente comparar os dois valores e qualquer pressionamento de botão mostrado em ambos permanecerá 1 e todo o resto definido como 0.
Ou seja, (1 | 2 | 4) e (2 | 4 | 8) produzirão (2 | 4).
Agora que temos quais botões estão "pressionados". Nós podemos descansar.
Pressionado é simples. Pegamos nosso estado "ATUAL" e removemos todos os botões pressionados.
BUTTONS_PRESSED = CURRENT ^ BUTTONS_HOLD;
Liberado é o mesmo, apenas o comparamos ao nosso último estado.
BUTTONS_RELEASED = LAST ^ BUTTONS_HOLD;
Então, olhando para a situação Pressed. Se vamos dizer que atualmente tivemos 2 | 4 8 pressionado. Descobrimos que 2 | 4 onde realizada. Quando removemos os Bits Retidos, ficamos com apenas 8. Este é o bit recém-pressionado para este ciclo.
O mesmo pode ser aplicado para Liberado. Nesse cenário "ÚLTIMO" foi definido como 1 | 2 4. Então, quando removemos o 2 | 4 bits. Ficamos com 1. Portanto, o botão 1 foi liberado desde o último quadro.
Esse cenário acima é provavelmente a situação mais ideal que você pode oferecer para comparação de bits e fornece 3 níveis de dados sem instruções if ou para loops apenas 3 cálculos rápidos de bits.
Eu também queria documentar dados de retenção, por isso, embora minha situação não seja perfeita ... o que faz é basicamente definir os valores de retenção que queremos verificar.
Portanto, toda vez que configuramos nossos dados de Imprensa / Liberação / Espera, verificamos se os dados de retenção ainda são iguais à atual verificação de bits de retenção. Caso contrário, redefinimos a hora para a hora atual. No meu caso, estou configurando-o para índices de quadros, para que eu saiba quantos quadros foram retidos.
A desvantagem dessa abordagem é que não posso obter tempos de espera individuais, mas você pode verificar vários bits ao mesmo tempo. Ou seja, se eu definir o bit de espera como 1 | 16 se 1 ou 16 não forem mantidos, isso falhará. Portanto, é necessário que TODOS esses botões sejam pressionados para continuar marcando.
Então, se você olhar no código, verá todas as chamadas de função.
Portanto, seu exemplo seria reduzido a simplesmente verificar se um pressionamento de botão ocorreu e um pressionamento de botão pode ocorrer apenas uma vez com esse algoritmo. Na próxima verificação para pressionar, ele não existirá, pois você não pode pressionar mais do que uma vez, pois seria necessário soltar antes de pressionar novamente.