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
yToUnicode
En la pregunta, usted mencionó que probó
ToAscii
yToUnicode
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étodoKeyboardHookProc
.Luego, puede guardar el código anterior en un archivo nuevo, como
HookManager.Modified.cs
y agregarlo en el proyectoGma.UserActivityMonitor
, o simplemente pegarlo en la parte posterior deHookManager.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
oToLower
para obtener un caso opuesto conǸ
yǹ
, incluso probéToUpperInvariant
yToLowerInvariant
. Por lo tanto, elijo usar una secuencia codificada enAccentFormatter
, 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.