// an alternative to these will be needed if not under Windows. They are needed in frmMain.SimulateKey; other uses might be avoidable public static Keys ToKeyData(this char ch) { int VK = Windows.VkKeyScan(ch); // bottom byte returns the VK code; top byte it is: 1 = Shift, 2 = Control, 4 =Alt (8 = Hankaku - but I think I can ignore that one!) Keys eKey = (Keys)(VK & 255); if ((VK & 0x100) > 0) { eKey |= Keys.Shift; } if ((VK & 0x200) > 0) { eKey |= Keys.Control; } if ((VK & 0x400) > 0) { eKey |= Keys.Alt; } return(eKey); }
/// <summary>Sends the given key sequence, in either new or GIDEI format (former if enclosed in '' or contains <?new?></summary> public bool SendStringKeys(string send, int delay) { Debug.WriteLine("SendKeys: " + send); lock (this) { try { bool newMode = false; // true if we've encountered <?new?> which forces into new only mode <esc> then acts as a key not a GIDEI if (send.StartsWith("'") && send.EndsWith("'")) { send = send.Substring(1, send.Length - 2); newMode = true; } m_Send = send; m_Output.Clear(); // returns true if all succeeded. strSend can be coded using GIDEI or "new" SAW codes while (!string.IsNullOrEmpty(m_Send)) // m_Send is reduced as chars are pulled from it { bool validToken = false; if (m_Send[0] == '<' && m_Send.Length >= 2 && m_Send[1] != ' ') // ignores any < immediately followed by space { // introduces all sorts of codes var token = GetToken(1, false, '>')?.ToLower(); // returns null if invalid if (!string.IsNullOrEmpty(token)) { validToken = true; m_Send = m_Send.Substring(token.Length + 2); if (token == GIDEI_EscapeCode && !newMode) { ProcessGIDEI(); } else if (token == "?new?") { newMode = true; } else if (token == "less") { validToken = false; m_Send = "<" + m_Send; // will cause the character to be emitted in next branch } else // is one of the new codes { ProcessNew(token); } } } if (!validToken) // is not an escape sequence starting with < { char character = m_Send[0]; if (m_Held.Any()) // following something like <Ctrl> we don't want to interpret a capital as meaning shift is also pressed { character = char.ToLower(character); } byte[] intVirtual = BitConverter.GetBytes(Windows.VkKeyScan(character)); // VkKeyScan does not return an Int16 compatible with Windows.Forms.Keys // rather the bottom byte is the key code, and the top byte is the modifier state if (intVirtual[0] == 0 || intVirtual[0] == 255 || (intVirtual[0] == m_QuestionVirtualKey[0] && intVirtual[1] == m_QuestionVirtualKey[1] && character != '?')) // failed - no key found for this char // last condition checks for "?" returned, but character requested was not "?". Windows does seem to return a valid response of Shift+OemQuestion for chars in very different languages { AddAltKey(character); } else { // valid key - queue any modifiers first if ((intVirtual[1] & 1) > 0 && !m_Locked.Contains(Keys.ShiftKey)) { AddCommand(Modes.Hold, Keys.ShiftKey); } if ((intVirtual[1] & 2) > 0 && !m_Locked.Contains(Keys.ControlKey)) { AddCommand(Modes.Hold, Keys.ControlKey); // Not sure how many plain characters need to be typed using control! } if ((intVirtual[1] & 4) > 0 && !m_Locked.Contains(Keys.LMenu)) { AddCommand(Modes.Hold, Keys.LMenu); } AddCommand(Modes.Press, (Keys)intVirtual[0]); } m_Send = m_Send.Substring(1); } if (m_Output.Any() && delay > 0) { // with a delay between keys, they need to be sent now SendQueuedOutput(); Thread.Sleep(delay); } } if (m_SendFromRepeat != null) { throw new UserException("Invalid key command: no <END_REPEAT> following <REPEAT n>"); } //AddReleaseHeld(); return(SendQueuedOutput()); } finally { m_Output.Clear(); } } }
private KeySend() { m_QuestionVirtualKey = BitConverter.GetBytes(Windows.VkKeyScan('?')); LockCode = Strings.Item("KeyScript__Lock").ToLower(); HoldCode = Strings.Item("KeyScript__Hold").ToLower(); PressCode = Strings.Item("KeyScript__Press").ToLower(); ReleaseCode = Strings.Item("KeyScript__Release").ToLower(); UnlockCode = Strings.Item("KeyScript__Unlock").ToLower(); GIDEI_EscapeCode = Strings.Item("KeyScript__GIDEI_Escape").ToLower(); OnCode = Strings.Item("KeyScript__On").ToLower(); OffCode = Strings.Item("KeyScript__Off").ToLower(); RepeatCode = Strings.Item("KeyScript__Repeat").ToLower() + " "; // note this includes the space (will have been trimmed by Strings even if in file) EndRepeatCode = Strings.Item("KeyScript__EndRepeat").ToLower(); DelayCode = Strings.Item("KeyScript__Delay").ToLower(); foreach (string key in Strings.Keys) // Bit naff scanning them all, but I'd rather just keep them all in the same text file as usual { if (key.StartsWith("KeyScript_")) { string right = key.Substring(10); // 10 = "KeyScript_".Length // After this should either be GIDEI_xyz or NEW_xyz or _whatever (last is for any text which is not a key, but needed here) if (right.StartsWith("GIDEI_")) { right = right.Substring(6); // the rest of the name is the keycode. The text is the user text // text system won't allow 2 lines with the same ID, so single apostrophes can be appended to the ID, and these are removed here to get the actual key name Keys keyCode = (Keys)Enum.Parse(typeof(Keys), right.Trim('\'')); string name = Strings.Item(key).ToLower(); m_GIDEICodes.Add(name, keyCode); } else if (right.StartsWith("NEW_")) { right = right.Substring(4); // the rest of the name is the keycode. The text is the user text Keys keyCode = (Keys)Enum.Parse(typeof(Keys), right.Trim('\'')); // permits the ' as above, but shouldn't be needed? string name = Strings.Item(key).ToLower(); m_NewCodes.Add(name, keyCode); if (!m_NewCodesReverse.ContainsKey(keyCode)) { m_NewCodesReverse.Add(keyCode, name); } } } } foreach (Keys key in Enum.GetValues(typeof(Keys))) { string name = key.ToString(); string lower = name.ToLower(); if (name.Length > 1) // ignore single letters! { if (!m_NewCodes.ContainsKey(lower)) { // and keys in translations have priority m_NewCodes.Add(lower, key); if (!m_NewCodesReverse.ContainsKey(key)) { m_NewCodesReverse.Add(key, name); } } if (!m_GIDEICodes.ContainsKey(lower)) { m_GIDEICodes.Add(lower, key); } } } }
public int GetKeyboardCode(char value) { byte[] scan = BitConverter.GetBytes(Windows.VkKeyScan(value)); return(scan[0]); }