usar teclas lenguaje imprimir especiales como codigo caracteres cadena c# winforms logging character-encoding keycode

c# - teclas - imprimir char en c



Caracteres dobles que se muestran al escribir caracteres especiales mientras se registran las teclas en c# (2)

Tengo una aplicación que registra lo que sea que presione el usuario, pero cuando ´´a caracteres especiales como ´ con a , para obtener á , obtengo ´´a ; Lo mismo cuando quiero obtener à , entonces obtengo ``a , de modo que todos los caracteres especiales se mecanografían dos veces y luego se escribe el caracter normal.

He buscado por siempre y no puedo encontrar nada realmente. Pero me he dado cuenta de que el problema está en el método ToAscii , sin que los caracteres estén escritos correctamente.

public string GetString(IntPtr lParam, int vCode) { try { bool shift = Keys.Shift == Control.ModifierKeys || Console.CapsLock; string value = ""; KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure( lParam, typeof(KeyboardHookStruct)); byte[] keyState = new byte[256]; byte[] inBuffer = new byte[2]; DllClass.GetKeyboardState(keyState); var ascii= DllClass.ToAscii( MyKeyboardHookStruct.vkCode, MyKeyboardHookStruct.scanCode, keyState, inBuffer, MyKeyboardHookStruct.flags ); if (ascii == 1) { char key = (char)inBuffer[0]; if ((shift) && Char.IsLetter(key)) key = Char.ToUpper(key); value = key.ToString(); } return value; } catch (Exception) { return ""; } }

¿Me estoy perdiendo algo o estoy haciendo algo mal? Todos los demás personajes funcionan a la perfección, pero son los personajes especiales los que aparecen como dobles caracteres.

EDITAR:

Probando con ToUnicode en ToUnicode lugar.

[DllImport("USER32.DLL", CharSet = CharSet.Unicode)] public static extern int ToUnicode( uint virtualKey, uint scanCode, byte[] keyStates, [MarshalAs(UnmanagedType.LPArray)] [Out] char[] chars, int charMaxCount, uint flags); public string GetString(IntPtr lParam, int vCode) { try { bool shift = Keys.Shift == Control.ModifierKeys || Console.CapsLock; string value = ""; KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure( lParam, typeof(KeyboardHookStruct)); byte[] keyState = new byte[256]; byte[] inBuffer = new byte[2]; char[] chars = new char[2]; DllClass.GetKeyboardState(keyState); int val = 0; val = ToUnicode( (uint)MyKeyboardHookStruct.vkCode, (uint)MyKeyboardHookStruct.scanCode, keyState, chars, chars.Length, 0 ); val = ToUnicode( (uint)MyKeyboardHookStruct.vkCode, (uint)MyKeyboardHookStruct.scanCode, keyState, chars, chars.Length, 0 ); if (val == 1) { char key = (char)chars[0]; if ((shift) && Char.IsLetter(key)) key = Char.ToUpper(key); value = key.ToString(); } return value; } catch (Exception) { return ""; } }

Alguien POR FAVOR ayúdenme, realmente necesito resolver esto =/ .

EDITAR:

int val = -1; if (IsDeadKey((uint)vCode)) { while (val == -1) { val = ToUnicode( (uint)MyKeyboardHookStruct.vkCode, (uint)MyKeyboardHookStruct.scanCode, keyState, chars, chars.Length, 0 ); } } else val = ToUnicode( (uint)MyKeyboardHookStruct.vkCode, (uint)MyKeyboardHookStruct.scanCode, keyState, chars, chars.Length, 0 );

Así que ahora he intentado llamar a ToAscii o ToUnicode un par de veces para ToUnicode el personaje real pero sin éxito. ¿Lo estoy haciendo mal?

Al igual que para ASCII, primero llame para ´ Tengo -1 , así que lo llamo de nuevo, luego obtengo 1 ; y luego presiono como a , para obtener á , pero luego solo obtengo a . Lo mismo si uso ToUnicode dos veces ToUnicode , obtengo solo a lugar de á , y así sucesivamente ...


Pero me he dado cuenta de que el problema está en el método ToAsciii, sin que los caracteres estén escritos correctamente.

Eso es exactamente lo que estaba por adivinar. ¡Aprecio que hayas hecho el trabajo de campo por mí! :-)

El problema es que estos caracteres "especiales" no son caracteres ASCII. Es decir, en realidad son algunos tipos de caracteres Unicode de fantasía que no forman parte del juego de caracteres ASCII.

Cuando intenta convertirlos en caracteres ASCII, la función presumiblemente lo hace lo mejor que puede, descomponiendo los puntos de código que componen á en los caracteres separados ´ y a .

Obviamente eso no es lo que quieres. Desea tratar á como un solo carácter, por lo que debe usar Unicode. Eso no es realmente un problema: Windows ha sido internamente Unicode durante al menos una década. ToAscii la anticuada función ToAscii ; en su lugar, querrá usar MapVirtualKey o MapVirtualKeyEx para convertir el código de la tecla virtual que está obteniendo a través del gancho de teclado de bajo nivel en un valor de carácter.


  • El mito sobre ToAscii y ToUnicode

    En la pregunta, usted mencionó que probó ToAscii y ToUnicode sin éxito. Y también busqué una pregunta que es relativa:

    ToAscii / ToUnicode en un gancho de teclado destruye las llaves muertas

    No estoy diciendo que ninguna respuesta sea correcta o incorrecta. Sin embargo, podemos pensar en:

    • Un juego (no tan complicado)

      En este juego, le doy al jugador una moneda aleatoria de 50 centavos a la vez. Uno puede desafiar a obtener un billete de un dólar de mí, si quien recogió un par de monedas de 50 centavos con uno es una cabeza y otra es una cola .

      Si uno se dio por vencido para desafiar, entonces quién puede reservar ese 50 centavos, y el juego se reinicia. Si quien intentó pero no coleccionó dos cumple con la regla, entonces pido que me devuelva los que he dado.

      ¿Cómo se puede obtener un billete de un dólar sin perder ninguna moneda?

    Tal vez un viaje en el tiempo ..

Base en [ Procesamiento global de mouse y ganchos de teclado en C # ] en CodeProject

y mi muy antigua respuesta: Código de Konami en C #

Hice algunas modificaciones para responder tu pregunta.

  • Código

    namespace Gma.UserActivityMonitor { using System.Diagnostics; using System.Windows.Forms; using System.Collections.Generic; using System.Linq; partial class HookManager { private static int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam) { // indicates if any of underlaing events set e.Handled flag bool handled=false; if(nCode>=0) { // read structure KeyboardHookStruct at lParam var MyKeyboardHookStruct= (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); // raise KeyDown if(s_KeyDown!=null&&(wParam==WM_KEYDOWN||wParam==WM_SYSKEYDOWN)) { Keys keyData=(Keys)MyKeyboardHookStruct.VirtualKeyCode; KeyEventArgs e=new KeyEventArgs(keyData); s_KeyDown.Invoke(null, e); handled=e.Handled; } // raise KeyPress if(s_KeyPress!=null&&wParam==WM_KEYDOWN) { var keyText=GetString(lParam, nCode, ref handled); if(""!=keyText) { var keyChar=keyText.First(); Debug.Print("keyText => {0}", keyText); #if false if(AccentFormatter.Combination.Values.Contains(keyChar)) { SendKeys.Send("/b"+keyText); return -1; } #endif } } // raise KeyUp if(s_KeyUp!=null&&(wParam==WM_KEYUP||wParam==WM_SYSKEYUP)) { Keys keyData=(Keys)MyKeyboardHookStruct.VirtualKeyCode; KeyEventArgs e=new KeyEventArgs(keyData); s_KeyUp.Invoke(null, e); handled=handled||e.Handled; } } // if event handled in application do not handoff to other listeners if(handled) return -1; // forward to other application return CallNextHookEx(s_KeyboardHookHandle, nCode, wParam, lParam); } public static String GetString(IntPtr lParam, int vCode, ref bool handled) { var MyKeyboardHookStruct= (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); bool isDownShift=((GetKeyState(VK_SHIFT)&0x80)==0x80?true:false); bool isDownCapslock=(GetKeyState(VK_CAPITAL)!=0?true:false); byte[] keyState=new byte[256]; GetKeyboardState(keyState); byte[] inBuffer=new byte[2]; var keyText=""; var ascii= ToAscii( MyKeyboardHookStruct.VirtualKeyCode, MyKeyboardHookStruct.ScanCode, keyState, inBuffer, MyKeyboardHookStruct.Flags ); if(ascii==1) { char key=(char)inBuffer[0]; if((isDownCapslock^isDownShift)&&Char.IsLetter(key)) key=Char.ToUpper(key); KeyPressEventArgs e=new KeyPressEventArgs(key); s_KeyPress.Invoke(null, e); handled=handled||e.Handled; keyText=new String(new[] { e.KeyChar }); var sequence=KeySequence.Captured(e.KeyChar); if(null!=sequence) keyText=sequence.ToString(AccentFormatter.Default); } return keyText; } } public class KeySequence { public String ToString(IFormatProvider provider) { return null==provider ?new String(Sequence.Select(x => (char)x).ToArray()) :String.Format(provider, "{0}", Sequence); } public override String ToString() { return this.ToString(default(IFormatProvider)); } public bool Captures(int keyValue) { for(var i=Sequence.Length; i-->0; ) { if(Sequence[i]!=keyValue) { if(0==i) Count=0; continue; } if(Count!=i) continue; ++Count; break; } var x=Sequence.Length==Count; Count=x?0:Count; return x; } public KeySequence(int[] newSequence) { Sequence=newSequence; } public static KeySequence Captured(int keyValue) { return m_List.FirstOrDefault(x => x.Captures(keyValue)); } public int Count { private set; get; } public int[] Sequence { set; get; } static KeySequence() { m_List.AddRange( from x in AccentFormatter.Combination.Keys let intArray=x.Select(c => (int)c).ToArray() select new KeySequence(intArray) ); } static readonly List<KeySequence> m_List=new List<KeySequence>(); } public class AccentFormatter: IFormatProvider, ICustomFormatter { String ICustomFormatter.Format(String format, object arg, IFormatProvider formatProvider) { return GetAccent(new String((arg as int[]).Select(x => (char)x).ToArray())); } object IFormatProvider.GetFormat(Type formatType) { return typeof(ICustomFormatter)!=formatType?null:this; } public static String GetAccent(String input) { return Combination.Keys.Contains(input, StringComparer.OrdinalIgnoreCase) ?Combination[input].ToString() :""; } static AccentFormatter() { AcuteSymbol=((char)0xb4).ToString(); GraveSymbol=(''`'').ToString(); var ae=(char)0xe6; var oe=(char)0xf8; AcuteCandidates="acegiklmnoprsuwyz".ToArray().Concat(new[] { ae, oe }).ToArray(); GraveCandidates="aeinouwy".ToArray(); var lowerAcuteAccents=( new[] { 0xe1, 0x107, 0xe9, 0x1f5, 0xed, 0x1e31, 0x13a, 0x1e3f, 0x144, 0xf3, 0x1e55, 0x155, 0x15b, 0xfa, 0x1e83, 0xfd, 0x17a, 0x1fd, 0x1ff } ).Select( (x, i) => new { Key=AcuteSymbol+AcuteCandidates[i], Value=(char)x } ); var upperAcuteAccents=( new[] { 0xc1, 0x106, 0xc9, 0x1f4, 0xcd, 0x1e30, 0x139, 0x1e3e, 0x143, 0xd3, 0x1e54, 0x154, 0x15a, 0xda, 0x1e82, 0xdd, 0x179, 0x1fc, 0x1fe } ).Select( (x, i) => new { Key=AcuteSymbol+char.ToUpper(AcuteCandidates[i]), Value=(char)x } ); var lowerGraveAccents=( new[] { 0xe0, 0xe8, 0xec, 0x1f9, 0xf2, 0xf9, 0x1e81, 0x1ef3 } ).Select( (x, i) => new { Key=GraveSymbol+GraveCandidates[i], Value=(char)x } ); var upperGraveAccents=( new[] { 0xc0, 0xc8, 0xcc, 0x1f8, 0xd2, 0xd9, 0x1e80, 0x1ef2 } ).Select( (x, i) => new { Key=GraveSymbol+char.ToUpper(GraveCandidates[i]), Value=(char)x } ); Combination= lowerAcuteAccents .Concat(upperAcuteAccents) .Concat(lowerGraveAccents) .Concat(upperGraveAccents) .ToDictionary(x => x.Key, x => x.Value); } public static readonly Dictionary<String, char> Combination; public static readonly String AcuteSymbol, GraveSymbol; public static readonly char[] AcuteCandidates, GraveCandidates; public static readonly AccentFormatter Default=new AccentFormatter(); } }

    Primero, con el código descargado de CodeProject, encuentre HookManager.Callbacks.cs y elimine todo el método KeyboardHookProc .

    Luego, puede guardar el código anterior en un archivo nuevo, como HookManager.Modified.cs y agregarlo en el proyecto Gma.UserActivityMonitor , o simplemente pegarlo en la parte posterior de HookManager.Callbacks.cs .

    Recuerde establecer Gma.UserActivityMonitorDemo como proyecto de inicio . Se estableció el marco de destino en 2.0, y es posible que desee establecerlo en un nivel superior.

  • Entrada → Salida

  • Sobre el acento

    Cuando busqué hay dos tipos de acento general, son acento grave y acento agudo .
    La diacrítica del acento agudo es ´ , y las posibles letras son áǽćéǵíḱĺḿńóǿṕŕśúẃýź .
    La diacrítica del acento grave es `` , and the possible letters are àèìǹòùẁỳ`.

    Ambos son posibles en mayúsculas o minúsculas, pero no encontré una manera fácil de trabajar con ellos en las clases que están integradas en el marco. Por ejemplo, no puedo usar ToUpper o ToLower para obtener un caso opuesto con Ǹ y ǹ , incluso probé ToUpperInvariant y ToLowerInvariant . Por lo tanto, elijo usar una secuencia codificada en AccentFormatter , y puede cambiarla a lectura desde archivos, o implementar otro formateador personalizado usted mismo.

  • Arreglo de matriz de representación hexadecimal

    En el código, organicé la secuencia de acento aguda como:

    0xc1, 0x106, 0xc9, 0x1f4, 0xcd, 0x1e30, 0x139, 0x1e3e, 0x143, 0xd3, 0x1e54, 0x154, 0x15a, 0xda, 0x1e82, 0xdd, 0x179, 0x1fc, 0x1fe

    cual es:

    ÁĆ ÉǴ ÍḰĹḾŃ ÓṔŔŚ ÚẂÝŹ ǼǾ

    Los Ǽ y Ǿ se ponen en la parte posterior porque Æ y Ø no tienen un carácter correspondiente en ASCII (no extendido).

    Prefiero guardar el código en ANSI con una página de códigos predeterminada, ya que tengo un CultureInfo diferente de los idiomas que están en alfabeto. Y es posible que desee cambiarlos por caracteres exactos para poder leerlos.

  • Enviar claves a la aplicación activa

    Si desea enviar la clave a la aplicación activa, realice el siguiente cambio en el código:

    cambio

    #if false

    a

    #if !false

    Dentro del bloque de compilación condicional, el fragmento de código es

    if(AccentFormatter.Combination.Values.Contains(keyChar)) { SendKeys.Send("/b"+keyText); return -1; }

    Utiliza un carácter de retroceso para borrar el tipo anterior `` o''` una vez que reconoce como una combinación específica. Retroceso aquí es la máquina del tiempo ..

Después de esta demostración, supongo que sabrá cómo modificarlos para combinarlos en su código.