2012-08-25 17 views
7

He visto una serie de respuestas que sugieren el uso de Keyboard.Modifiers para determinar si un evento KeyDown es para una clave que tiene un conjunto de modificadores. Desafortunadamente, dado que Keyboard.Modifiers devuelve el estado actual de los modificadores (en lugar del estado del modificador cuando se presionó la tecla), esto resulta en un error intermitente realmente molesto para los mecanógrafos rápidos.¿Cómo recuperar correctamente las teclas modificadoras en un evento WPF KeyDown?

Específicamente, imagine que alguien presiona Ctrl + A, y suelta Ctrl solo unos pocos milisegundos después de presionar A. Ahora imagine que el sistema estaba bajo mucha carga; el manejador de claves comenzó a ejecutarse, pero se adelantó durante 50 ms. En el momento en que el controlador de clave se está ejecutando de nuevo, el estado actual de Ctrl se "libera". El controlador de teclas ahora pensará que se presionó "A" sin Ctrl, y esto es malo.

Del mismo modo, si un mecanógrafo rápido entra A, Ctrl + Fin y mi aplicación utiliza Keyboard.Modifiers, en su lugar podría terminar observando Ctrl + A ...

En WinForms, el evento KeyDown me dice que el estado de Ctrl exactamente, incluso si ya se ha liberado cuando se procesa el evento. ¿Cómo puedo obtener este mismo comportamiento en WPF?

Editar: es posible que Keyboard.Modifiers en realidad no recupere las teclas modificadoras "actuales", sino las teclas modificadoras relacionadas con el mensaje de reducción de teclas que se está procesando actualmente. En WinAPI, esta fue la distinción entre funciones de estado de la tecla "asíncrona" y no asíncrona. Desafortunadamente, the documentation no menciona qué significa exactamente "actual". Si alguien sabe, por favor dígalo.

+0

¿estás seguro? no encuentro ninguna pista sobre msdn, eso probará su teoría ... sería realmente extraño, que los argumentos del controlador no incluyan las teclas ORIGINALMENTE presionadas ... si se une a "onkeyDown" y el usuario presiona CONTROL (mantener) y luego a, luego suelta CONTROL, ¡el evento se disparará 2 veces! primero con "Control" solamente, luego con CONTROL + A ... un poco extraño - en mi humilde opinión, que podría darse cuenta de eso fácilmente con Thread.Sleep ... ¿Tengo que arrancar VS ¿ahora mismo? ;) – TheHe

+1

@TheHe Los argumentos del manejador incluyen la _key_ presionada originalmente, pero no la información de la tecla modificadora. En el viejo y viejo WinAPI, las claves modificadoras se pasan junto con el mensaje. Lo mismo sucede en WinForms. La documentación en realidad le advierte que no intente procesar el estado _current_; por ejemplo, si la aplicación no responde por alguna razón (por ejemplo, agolpamiento de HDD), el manejador puede invocarse _segundos_ después del hecho. –

Respuesta

3

Como no parece haber ninguna información de modificación en el evento args, usted podría realizar un seguimiento del estado usted mismo en algunos campos y manejar KeyUp y KeyDown para actualizarlos en consecuencia.

p. Ej.

private bool ctrl = false; 
private void This_KeyDown(object sender, KeyEventArgs e) 
{ 
    if (e.Key == Key.LeftCtrl) //or switch, also: `LeftCtrl` & `RightCtrl` are treated as separate keys 
     ctrl = true; 
    //etc.. 
} 

private void This_KeyUp(object sender, KeyEventArgs e) 
{ 
    if (e.Key == Key.LeftCtrl) 
     ctrl = false; 
    //etc.. 
} 

Si esto es realmente una buena idea, no puedo decir ...


Si desea manejar gestos claves se recomienda usar métodos dedicados como KeyBindings sólo deben incendio cuando ocurrió el gesto . Para otras entradas, también puede echarle un vistazo al TextInput que es más abstracto y devuelve el texto al que se traduce la entrada.

+0

Buen punto sobre KeyBindings; investigará eso. –

+0

sry por mi doble respuesta: ¡lo he sobrehendido por completo! – TheHe

2

pena por esta respuesta destructiva, pero ...

después de un poco de la investigación se pone de manifiesto a mí ... el evento se llama "KeyDown" no "KeyCombinationDown" por lo que es totalmente independiente de cualquier Modificadores presionados ANTES ...

Actualmente existe una manera correcta de lograr su objetivo: Usando el Commanding-Pattern.

Defina un COMANDO (vea google para WPF-Commanding) y agregue un KeyBinding a su aplicación, donde definirá la clave o las teclas/combinación de teclas que activará el comando ...

Véase el ejemplo aquí: http://msdn.microsoft.com/en-us/library/system.windows.input.keybinding.aspx

en mi humilde opinión, esta es la forma única y semánticamente más elegante, también.

(si este patrón no funciona para usted, en general, tal vez tenga que usar api nativo con pinvoke).

aplausos.

+0

No veo esto como destructivo. Sugieres una alternativa, después de todo. Es solo que si buscas en Google, solo verás "usar Keyboard.Modifiers", de ahí esta pregunta ... –

+0

Desafortunadamente, esto tiene un efecto secundario (¿error?): Cuando el enlace de teclas coincide, el evento de tecla abajo es * siempre * marcado como manejado, incluso si el comando no se puede ejecutar. Entonces, en ese caso, la pulsación de tecla nunca se traducirá a un TextInput. –

Cuestiones relacionadas