private static void SendString(string str) { List <VK> modifiers = new List <VK>(); bool use_gtk_hack = false, use_office_hack = false; const int len = 256; StringBuilder buf = new StringBuilder(len); var hwnd = NativeMethods.GetForegroundWindow(); if (NativeMethods.GetClassName(hwnd, buf, len) > 0) { string wclass = buf.ToString(); /* HACK: GTK+ applications behave differently with Unicode, and some * applications such as XChat for Windows rename their own top-level * window, so we parse through the names we know in order to detect * a GTK+ application. */ if (wclass == "gdkWindowToplevel" || wclass == "xchatWindowToplevel") { use_gtk_hack = true; } /* HACK: in MS Office, some symbol insertions change the text font * without returning to the original font. To avoid this, we output * a space character, then go left, insert our actual symbol, then * go right and backspace. */ /* These are the actual window class names for Outlook and Word… * TODO: PowerPoint ("PP(7|97|9|10)FrameClass") */ if (wclass == "rctrl_renwnd32" || wclass == "OpusApp") { use_office_hack = true && Settings.InsertZwsp.Value; } } /* Clear keyboard modifiers if we need one of our custom hacks */ if (use_gtk_hack || use_office_hack) { VK[] all_modifiers = new VK[] { VK.LSHIFT, VK.RSHIFT, VK.LCONTROL, VK.RCONTROL, VK.LMENU, VK.RMENU, }; foreach (VK vk in all_modifiers) { if ((NativeMethods.GetKeyState(vk) & 0x80) == 0x80) { modifiers.Add(vk); } } foreach (VK vk in modifiers) { SendKeyUp(vk); } } if (use_gtk_hack) { /* Wikipedia says Ctrl+Shift+u, release, then type the four hex * digits, and press Enter. * (http://en.wikipedia.org/wiki/Unicode_input). */ SendKeyDown(VK.LCONTROL); SendKeyDown(VK.LSHIFT); SendKeyPress((VK)'U'); SendKeyUp(VK.LSHIFT); SendKeyUp(VK.LCONTROL); foreach (var ch in str) { foreach (var key in String.Format("{0:X04} ", (short)ch)) { SendKeyPress((VK)key); } } } else { InputSequence Seq = new InputSequence(); if (use_office_hack) { Seq.Add((ScanCodeShort)'\u200b'); Seq.Add((VirtualKeyShort)VK.LEFT); } for (int i = 0; i < str.Length; i++) { Seq.Add((ScanCodeShort)str[i]); } if (use_office_hack) { Seq.Add((VirtualKeyShort)VK.RIGHT); } Seq.Send(); } /* Restore keyboard modifiers if we needed one of our custom hacks */ if (use_gtk_hack || use_office_hack) { foreach (VK vk in modifiers) { SendKeyDown(vk); } } }
private static void SendString(string str) { List<VK> modifiers = new List<VK>(); /* HACK: GTK+ applications behave differently with Unicode, and some * applications such as XChat for Windows rename their own top-level * window, so we parse through the names we know in order to detect * a GTK+ application. */ bool use_gtk_hack = m_window_is_gtk; /* HACK: in MS Office, some symbol insertions change the text font * without returning to the original font. To avoid this, we output * a space character, then go left, insert our actual symbol, then * go right and backspace. */ /* These are the actual window class names for Outlook and Word… * TODO: PowerPoint ("PP(7|97|9|10)FrameClass") */ bool use_office_hack = m_window_is_office && Settings.InsertZwsp.Value; /* Clear keyboard modifiers if we need one of our custom hacks */ if (use_gtk_hack || use_office_hack) { VK[] all_modifiers = new VK[] { VK.LSHIFT, VK.RSHIFT, VK.LCONTROL, VK.RCONTROL, VK.LMENU, VK.RMENU, /* Needs to be released, too, otherwise Caps Lock + é on * a French keyboard will print garbage if Caps Lock is * not released soon enough. See note below. */ VK.CAPITAL, }; foreach (VK vk in all_modifiers) if ((NativeMethods.GetKeyState(vk) & 0x80) == 0x80) modifiers.Add(vk); foreach (VK vk in modifiers) SendKeyUp(vk); } if (use_gtk_hack) { /* XXX: We need to disable caps lock because GTK’s Shift-Ctrl-U * input mode (see below) doesn’t work when Caps Lock is on. */ bool has_capslock = NativeMethods.GetKeyState(VK.CAPITAL) != 0; if (has_capslock) SendKeyPress(VK.CAPITAL); foreach (var ch in str) { if (false) { /* FIXME: there is a possible optimisation here where we do * not have to send the whole unicode sequence for regular * ASCII characters. However, SendKeyPress() needs a VK, so * we need an ASCII to VK conversion method, together with * the proper keyboard modifiers. Maybe not worth it. * Also, we cannot use KeySequence because GTK+ seems to * ignore SendInput(). */ //SendKeyPress((VK)char.ToUpper(ch)); } else { /* Wikipedia says Ctrl+Shift+u, release, then type the four * hex digits, and press Enter. * (http://en.wikipedia.org/wiki/Unicode_input). */ SendKeyDown(VK.LCONTROL); SendKeyDown(VK.LSHIFT); SendKeyPress((VK)'U'); SendKeyUp(VK.LSHIFT); SendKeyUp(VK.LCONTROL); foreach (var key in String.Format("{0:X04} ", (short)ch)) SendKeyPress((VK)key); } } if (has_capslock) SendKeyPress(VK.CAPITAL); } else { InputSequence Seq = new InputSequence(); if (use_office_hack) { Seq.AddInput((ScanCodeShort)'\u200b'); Seq.AddInput((VirtualKeyShort)VK.LEFT); } foreach (char ch in str) { Seq.AddInput((ScanCodeShort)ch); } if (use_office_hack) { Seq.AddInput((VirtualKeyShort)VK.RIGHT); } Seq.Send(); } /* Restore keyboard modifiers if we needed one of our custom hacks */ if (use_gtk_hack || use_office_hack) { foreach (VK vk in modifiers) SendKeyDown(vk); } }
private static void SendString(string str) { List <VK> modifiers = new List <VK>(); /* HACK: GTK+ applications behave differently with Unicode, and some * applications such as XChat for Windows rename their own top-level * window, so we parse through the names we know in order to detect * a GTK+ application. */ bool use_gtk_hack = m_window_is_gtk; /* HACK: in MS Office, some symbol insertions change the text font * without returning to the original font. To avoid this, we output * a space character, then go left, insert our actual symbol, then * go right and backspace. */ /* These are the actual window class names for Outlook and Word… * TODO: PowerPoint ("PP(7|97|9|10)FrameClass") */ bool use_office_hack = m_window_is_office && Settings.InsertZwsp.Value; /* Clear keyboard modifiers if we need one of our custom hacks */ if (use_gtk_hack || use_office_hack) { VK[] all_modifiers = new VK[] { VK.LSHIFT, VK.RSHIFT, VK.LCONTROL, VK.RCONTROL, VK.LMENU, VK.RMENU, /* Needs to be released, too, otherwise Caps Lock + é on * a French keyboard will print garbage if Caps Lock is * not released soon enough. See note below. */ VK.CAPITAL, }; foreach (VK vk in all_modifiers) { if ((NativeMethods.GetKeyState(vk) & 0x80) == 0x80) { modifiers.Add(vk); } } foreach (VK vk in modifiers) { SendKeyUp(vk); } } if (use_gtk_hack) { /* XXX: We need to disable caps lock because GTK’s Shift-Ctrl-U * input mode (see below) doesn’t work when Caps Lock is on. */ bool has_capslock = NativeMethods.GetKeyState(VK.CAPITAL) != 0; if (has_capslock) { SendKeyPress(VK.CAPITAL); } foreach (var ch in str) { if (false) { /* FIXME: there is a possible optimisation here where we do * not have to send the whole unicode sequence for regular * ASCII characters. However, SendKeyPress() needs a VK, so * we need an ASCII to VK conversion method, together with * the proper keyboard modifiers. Maybe not worth it. * Also, we cannot use KeySequence because GTK+ seems to * ignore SendInput(). */ //SendKeyPress((VK)char.ToUpper(ch)); } else { /* Wikipedia says Ctrl+Shift+u, release, then type the four * hex digits, and press Enter. * (http://en.wikipedia.org/wiki/Unicode_input). */ SendKeyDown(VK.LCONTROL); SendKeyDown(VK.LSHIFT); SendKeyPress((VK)'U'); SendKeyUp(VK.LSHIFT); SendKeyUp(VK.LCONTROL); foreach (var key in String.Format("{0:X04} ", (short)ch)) { SendKeyPress((VK)key); } } } if (has_capslock) { SendKeyPress(VK.CAPITAL); } } else { InputSequence Seq = new InputSequence(); if (use_office_hack) { Seq.AddInput((ScanCodeShort)'\u200b'); Seq.AddInput((VirtualKeyShort)VK.LEFT); } foreach (char ch in str) { Seq.AddInput((ScanCodeShort)ch); } if (use_office_hack) { Seq.AddInput((VirtualKeyShort)VK.RIGHT); } Seq.Send(); } /* Restore keyboard modifiers if we needed one of our custom hacks */ if (use_gtk_hack || use_office_hack) { foreach (VK vk in modifiers) { SendKeyDown(vk); } } }
private static void SendString(string str) { List<VK> modifiers = new List<VK>(); bool use_gtk_hack = false, use_office_hack = false; const int len = 256; StringBuilder buf = new StringBuilder(len); var hwnd = NativeMethods.GetForegroundWindow(); if (NativeMethods.GetClassName(hwnd, buf, len) > 0) { string wclass = buf.ToString(); /* HACK: GTK+ applications behave differently with Unicode, and some * applications such as XChat for Windows rename their own top-level * window, so we parse through the names we know in order to detect * a GTK+ application. */ if (wclass == "gdkWindowToplevel" || wclass == "xchatWindowToplevel") use_gtk_hack = true; /* HACK: in MS Office, some symbol insertions change the text font * without returning to the original font. To avoid this, we output * a space character, then go left, insert our actual symbol, then * go right and backspace. */ /* These are the actual window class names for Outlook and Word… * TODO: PowerPoint ("PP(7|97|9|10)FrameClass") */ if (wclass == "rctrl_renwnd32" || wclass == "OpusApp") use_office_hack = true && Settings.InsertZwsp.Value; } /* Clear keyboard modifiers if we need one of our custom hacks */ if (use_gtk_hack || use_office_hack) { VK[] all_modifiers = new VK[] { VK.LSHIFT, VK.RSHIFT, VK.LCONTROL, VK.RCONTROL, VK.LMENU, VK.RMENU, }; foreach (VK vk in all_modifiers) if ((NativeMethods.GetKeyState(vk) & 0x80) == 0x80) modifiers.Add(vk); foreach (VK vk in modifiers) SendKeyUp(vk); } if (use_gtk_hack) { foreach (var ch in str) { if (false) { /* FIXME: there is a possible optimisation here where we do * not have to send the whole unicode sequence for regular * ASCII characters. However, SendKeyPress() needs a VK, so * we need an ASCII to VK conversion method, together with * the proper keyboard modifiers. Maybe not worth it. * Also, we cannot use KeySequence because GTK+ seems to * ignore SendInput(). */ //SendKeyPress((VK)char.ToUpper(ch)); } else { /* Wikipedia says Ctrl+Shift+u, release, then type the four * hex digits, and press Enter. * (http://en.wikipedia.org/wiki/Unicode_input). */ SendKeyDown(VK.LCONTROL); SendKeyDown(VK.LSHIFT); SendKeyPress((VK)'U'); SendKeyUp(VK.LSHIFT); SendKeyUp(VK.LCONTROL); foreach (var key in String.Format("{0:X04} ", (short)ch)) SendKeyPress((VK)key); } } } else { InputSequence Seq = new InputSequence(); if (use_office_hack) { Seq.AddInput((ScanCodeShort)'\u200b'); Seq.AddInput((VirtualKeyShort)VK.LEFT); } foreach (char ch in str) { Seq.AddInput((ScanCodeShort)ch); } if (use_office_hack) { Seq.AddInput((VirtualKeyShort)VK.RIGHT); } Seq.Send(); } /* Restore keyboard modifiers if we needed one of our custom hacks */ if (use_gtk_hack || use_office_hack) { foreach (VK vk in modifiers) SendKeyDown(vk); } }
private static void SendString(string str) { List <VK> modifiers = new List <VK>(); /* HACK: GTK+ applications behave differently with Unicode, and some * applications such as XChat for Windows rename their own top-level * window, so we parse through the names we know in order to detect * a GTK+ application. */ bool use_gtk_hack = KeyboardLayout.Window.IsGtk; /* HACK: Notepad++ and LibreOffice are unable to output high plane * Unicode characters, so we rely on clipboard hacking when the * composed string contains such characters. */ bool use_clipboard_hack = KeyboardLayout.Window.IsNPPOrLO && HasSurrogates(str); /* HACK: in MS Office, some symbol insertions change the text font * without returning to the original font. To avoid this, we output * a space character, then go left, insert our actual symbol, then * go right and backspace. */ /* These are the actual window class names for Outlook and Word… * TODO: PowerPoint ("PP(7|97|9|10)FrameClass") */ bool use_office_hack = KeyboardLayout.Window.IsOffice && Settings.InsertZwsp.Value; /* Clear keyboard modifiers if we need one of our custom hacks */ if (use_gtk_hack || use_office_hack) { VK[] all_modifiers = { VK.LSHIFT, VK.RSHIFT, VK.LCONTROL, VK.RCONTROL, VK.LMENU, VK.RMENU, /* Needs to be released, too, otherwise Caps Lock + é on * a French keyboard will print garbage if Caps Lock is * not released soon enough. See note below. */ VK.CAPITAL, }; foreach (VK vk in all_modifiers) { if ((NativeMethods.GetKeyState(vk) & 0x80) == 0x80) { modifiers.Add(vk); } } foreach (VK vk in modifiers) { SendKeyUp(vk); } } if (use_gtk_hack) { /* XXX: We need to disable caps lock because GTK’s Shift-Ctrl-U * input mode (see below) doesn’t work when Caps Lock is on. */ bool has_capslock = NativeMethods.GetKeyState(VK.CAPITAL) != 0; if (has_capslock) { SendKeyPress(VK.CAPITAL); } foreach (var ch in str) { if (false) { /* FIXME: there is a possible optimisation here where we do * not have to send the whole unicode sequence for regular * ASCII characters. However, SendKeyPress() needs a VK, so * we need an ASCII to VK conversion method, together with * the proper keyboard modifiers. Maybe not worth it. * Also, we cannot use KeySequence because GTK+ seems to * ignore SendInput(). */ //SendKeyPress((VK)char.ToUpper(ch)); } else { /* Wikipedia says Ctrl+Shift+u, release, then type the four * hex digits, and press Enter. * (http://en.wikipedia.org/wiki/Unicode_input). */ SendKeyDown(VK.LCONTROL); SendKeyDown(VK.LSHIFT); SendKeyPress((VK)'U'); SendKeyUp(VK.LSHIFT); SendKeyUp(VK.LCONTROL); foreach (var key in $"{(short)ch:X04} ") { SendKeyPress((VK)key); } } } if (has_capslock) { SendKeyPress(VK.CAPITAL); } } else if (use_clipboard_hack) { // We do not use Clipboard.GetDataObject because I have been // unable to restore the clipboard properly. This is reasonable // and has been tested with several clipboard content types. var backup_text = Clipboard.GetText(); var backup_image = Clipboard.GetImage(); var backup_audio = Clipboard.GetAudioStream(); var backup_files = Clipboard.GetFileDropList(); // Use Shift+Insert instead of Ctrl-V because Ctrl-V will misbehave // if a Shift key is held down. Using Shift+Insert even works if the // compose key is Insert. Clipboard.SetText(str); SendKeyDown(VK.SHIFT); SendKeyPress(VK.INSERT); SendKeyUp(VK.SHIFT); Clipboard.Clear(); if (!string.IsNullOrEmpty(backup_text)) { Clipboard.SetText(backup_text); } if (backup_image != null) { Clipboard.SetImage(backup_image); } if (backup_audio != null) { Clipboard.SetAudio(backup_audio); } if (backup_files != null && backup_files.Count > 0) { Clipboard.SetFileDropList(backup_files); } } else { InputSequence Seq = new InputSequence(); if (use_office_hack) { Seq.AddInput((ScanCodeShort)'\u200b'); Seq.AddInput((VirtualKeyShort)VK.LEFT); } foreach (char ch in str) { Seq.AddInput((ScanCodeShort)ch); } if (use_office_hack) { Seq.AddInput((VirtualKeyShort)VK.RIGHT); } Seq.Send(); } /* Restore keyboard modifiers if we needed one of our custom hacks */ if (use_gtk_hack || use_office_hack) { foreach (VK vk in modifiers) { SendKeyDown(vk); } } }
private static void SendString(string str) { List <VK> modifiers = new List <VK>(); // HACK: GTK+ applications will crash when receiving surrogate pairs through VK.PACKET, // so we use the Ctrl-Shift-u special sequence. bool use_gtk_hack = KeyboardLayout.Window.IsGtk && str.Any(x => char.IsSurrogate(x)); // HACK: in MS Office, some symbol insertions change the text font // without returning to the original font. To avoid this, we output // a space character, then go left, insert our actual symbol, then // go right and backspace. // These are the actual window class names for Outlook and Word… // TODO: PowerPoint ("PP(7|97|9|10)FrameClass") bool use_office_hack = KeyboardLayout.Window.IsOffice && Settings.InsertZwsp.Value; InputSequence seq = new InputSequence(); // Clear keyboard modifiers if we need one of our custom hacks if (use_gtk_hack || use_office_hack) { VK[] all_modifiers = { VK.LSHIFT, VK.RSHIFT, VK.LCONTROL, VK.RCONTROL, VK.LMENU, VK.RMENU, // Needs to be released, too, otherwise Caps Lock + é on // a French keyboard will print garbage if Caps Lock is // not released soon enough. See note below. VK.CAPITAL, }; modifiers = all_modifiers.Where(x => (NativeMethods.GetKeyState(x) & 0x80) == 0x80) .ToList(); modifiers.ForEach(vk => seq.AddKeyEvent(EventType.KeyUp, vk)); } if (use_office_hack) { seq.AddUnicodeInput('\u200b'); seq.AddKeyEvent(EventType.KeyUpDown, VK.LEFT); } for (int i = 0; i < str.Length; ++i) { char ch = str[i]; if (ch == '\n' || ch == '\r') { // On some applications (e.g. Chrome or PowerPoint), \n cannot be injected // through its scancode, so we send the virtual key instead. seq.AddKeyEvent(EventType.KeyUpDown, VK.RETURN); } else if (use_gtk_hack && char.IsSurrogate(ch)) { // Sanity check if (i + 1 >= str.Length || !char.IsHighSurrogate(ch) || !char.IsLowSurrogate(str, i + 1)) { continue; } var codepoint = char.ConvertToUtf32(ch, str[++i]); // GTK+ hack: // - We need to disable Caps Lock // - Wikipedia says Ctrl+Shift+u, release, then type the four hex digits, // and press Enter (http://en.wikipedia.org/wiki/Unicode_input). // - The Gimp accepts either Enter or Space but stops immediately in both // cases. // - Inkscape stops after Enter, but allows to chain sequences using Space. bool has_capslock = NativeMethods.GetKeyState(VK.CAPITAL) != 0; if (has_capslock) { seq.AddKeyEvent(EventType.KeyUpDown, VK.CAPITAL); } seq.AddKeyEvent(EventType.KeyDown, VK.LCONTROL); seq.AddKeyEvent(EventType.KeyDown, VK.LSHIFT); seq.AddKeyEvent(EventType.KeyUpDown, VK.U); seq.AddKeyEvent(EventType.KeyUp, VK.LSHIFT); seq.AddKeyEvent(EventType.KeyUp, VK.LCONTROL); foreach (var key in $"{codepoint:X04}") { seq.AddKeyEvent(EventType.KeyUpDown, (VK)key); } seq.AddKeyEvent(EventType.KeyUpDown, VK.RETURN); if (has_capslock) { seq.AddKeyEvent(EventType.KeyUpDown, VK.CAPITAL); } } else { seq.AddUnicodeInput(ch); } } if (use_office_hack) { seq.AddKeyEvent(EventType.KeyUpDown, VK.RIGHT); } // Restore keyboard modifier state if we needed one of our custom hacks modifiers.ForEach(vk => seq.AddKeyEvent(EventType.KeyDown, vk)); // Send the whole keyboard sequence seq.Send(); }