/// <summary> /// Converts a list of hook events to string /// </summary> /// <param name="args">List of HookEventArgs objects</param> /// <returns>String representing the list of events</returns> public static string HookEventsToString(HookEventArgs[] args) { string eventStr = ""; foreach (HookEventArgs arg in args) { string str = ""; if ((arg as MouseHookEventArgsEx) != null) { MouseHookEventArgsEx e = arg as MouseHookEventArgsEx; switch (e.Type) { case HookEventCodec.EventType.MouseDown: str = String.Format("[Mouse Down: {0} | {1},{2} : {3}]", e.Button.ToString(), e.Location.X, e.Location.Y, HookEventHelper.GetModifierString(e)); break; case HookEventCodec.EventType.MouseClick: str = String.Format("[Mouse Click: {0}#{1} | {2},{3} : {4}]", e.Button.ToString(), e.ClickCount, e.Location.X, e.Location.Y, HookEventHelper.GetModifierString(e)); break; case HookEventCodec.EventType.MouseDoubleClick: str = String.Format("[Double Click: {0} | {1},{2} : {3}]", e.Button.ToString(), e.Location.X, e.Location.Y, HookEventHelper.GetModifierString(e)); break; case HookEventCodec.EventType.MouseUp: str = String.Format("[Mouse Up: {0} | {1},{2} : {3}]", e.Button.ToString(), e.Location.X, e.Location.Y, HookEventHelper.GetModifierString(e)); break; case HookEventCodec.EventType.MouseMove: str = String.Format("[Mouse Move | {0},{1} : {2}]", e.Location.X, e.Location.Y, HookEventHelper.GetModifierString(e)); break; case HookEventCodec.EventType.MouseWheel: str = String.Format("[Mouse Scroll: {0} | {1},{2} : {3}]", e.ScrollAmount, e.Location.X, e.Location.Y, HookEventHelper.GetModifierString(e)); break; } } else if ((arg as KeyHookEventArgsEx) != null) { KeyHookEventArgsEx e = arg as KeyHookEventArgsEx; List<string> pKeys = new List<string>(); foreach (byte b in e.PressedKeys) if (b != 0) pKeys.Add(((Keys)b).ToString()); switch (e.Type) { case HookEventCodec.EventType.KeyDown: str = String.Format("[Down: {0} : {1}]", String.Join(" + ", pKeys.ToArray()), HookEventHelper.GetModifierString(e)); break; case HookEventCodec.EventType.KeyPress: str = String.Format("[{0} : {1}]", String.Join(" + ", pKeys.ToArray()), HookEventHelper.GetModifierString(e)); break; case HookEventCodec.EventType.KeyUp: str = String.Format("[Up: {0} : {1}]", String.Join(" + ", pKeys.ToArray()), HookEventHelper.GetModifierString(e)); break; } if (e.KeyChar != '\0') str += e.KeyChar; } str.Trim(); if (str != "") eventStr += str + Environment.NewLine; } return eventStr.Trim(); }
/// <summary> /// Serializes the header byte /// </summary> /// <param name="ec">Event class</param> /// <param name="et">Event type</param> /// <param name="ha">Event args</param> /// <returns>Header byte</returns> private static byte GetHeaderByte(EventClass ec, EventType et, HookEventArgs ha) { byte head = 0; if (ec == EventClass.MouseEvent) { head = 0x80; } head |= (byte)((uint)et << 4); if (ha.Alt) { head |= 0x08; } if (ha.Control) { head |= 0x04; } if (ha.Shift) { head |= 0x02; } if (ha.CapsLock) { head |= 0x01; } return(head); }
/// <summary> /// Serializes the events /// </summary> /// <param name="eventClass">Event class</param> /// <param name="type">Type of event</param> /// <param name="args">KeyHookEventArgs or MouseHookEventArgs object</param> /// <param name="pressedKeys">Upto 3 consecutively pressed keys</param> /// <param name="pressedChar">Pressed character</param> /// <returns>Data bytes</returns> public static byte[] GetEncodedData(EventClass eventClass, EventType type, HookEventArgs args, int[] pressedKeys = null, char pressedChar = '\0') { byte[] data = null; using (MemoryStream ms = new MemoryStream()) { ms.WriteByte(GetHeaderByte(eventClass, type, args)); if (eventClass == EventClass.MouseEvent) { MouseHookEventArgs me = args as MouseHookEventArgs; ms.Write(BitConverter.GetBytes((ushort)me.Location.X), 0, 2); ms.Write(BitConverter.GetBytes((ushort)me.Location.Y), 0, 2); //ms.WriteByte((byte)me.Location.X); //ms.WriteByte((byte)me.Location.Y); //System.Windows.Forms.MouseButtons.Right; ms.WriteByte((byte)((int)me.Button >> 20)); byte extra = 0; switch (type) { case EventType.MouseClick: case EventType.MouseDoubleClick: extra = (byte)me.ClickCount; break; case EventType.MouseWheel: extra = (byte)Math.Abs(me.ScrollAmount); if (me.ScrollAmount < 0) { extra |= 0x80; } break; } ms.WriteByte(extra); } else { KeyHookEventArgs ke = args as KeyHookEventArgs; byte[] pKeys = { 0, 0, 0 }; if (pressedKeys == null || pressedKeys.Length == 0) { throw new ArgumentException("Atleast one key should be in pressed keys."); } int len = Math.Min(3, pressedKeys.Length); for (int i = 0; i < len; i++) { pKeys[i] = (byte)pressedKeys[i]; } ms.Write(pKeys, 0, 3); ms.WriteByte((byte)pressedChar); } data = ms.ToArray(); } return(data); }
/// <summary> /// Get modifier string consisting of Alt, Ctrl, Shift and Caps Lock /// </summary> /// <param name="ha">HookEventArgs object</param> /// <returns>Modifier string</returns> public static string GetModifierString(HookEventArgs ha) { string str = ""; if (ha.Alt) str += "Alt + "; if (ha.Control) str += "Ctrl + "; if (ha.Shift) str += "Shift + "; if (ha.CapsLock) str += "CapsLock + "; return str.TrimEnd(new char[] { ' ', '+' }); }
/// <summary> /// Deserializes the header byte /// </summary> /// <param name="head">Received byte</param> /// <param name="ec">Decoded event class</param> /// <param name="et">Decoded event type</param> /// <param name="ha">Decoded event args</param> private static void FromHeaderByte(byte head, out EventClass ec, out EventType et, out HookEventArgs ha) { if ((head & 0x80) == 0x80) { ec = EventClass.MouseEvent; } else { ec = EventClass.KeyEvent; } et = (EventType)((head & 0x70) >> 4); ha = new HookEventArgs((head & 0x08) == 0x08, (head & 0x04) == 0x04, (head & 0x02) == 0x02, (head & 0x01) == 0x01, false, false); }
/// <summary> /// Deserializes the data bytes /// </summary> /// <param name="offset">Starting position in stream</param> /// <param name="data">Received Data bytes</param> /// <param name="eventClass">Decoded event class</param> /// <param name="type">Decoded event type</param> /// <param name="args">Decoded HookEventArgs</param> /// <param name="pressedKeys">Upto 3 consecutively pressed decoded keys</param> /// <param name="pressedChar">Decoded pressed character</param> /// <returns>True if stream is not empty, else false</returns> public static bool GetDecodedData(int offset, byte[] data, out EventClass eventClass, out EventType type, out HookEventArgs args, out byte[] pressedKeys, out char pressedChar) { using (MemoryStream ms = new MemoryStream(data)) { // Set Offset ms.Position = offset; // Assign pressedKeys = null; pressedChar = '\0'; eventClass = EventClass.None; type = EventType.None; args = null; // Check if (ms.Position < ms.Length) { FromHeaderByte((byte)ms.ReadByte(), out eventClass, out type, out args); pressedKeys = new byte[3] { 0, 0, 0 }; if (eventClass == EventClass.MouseEvent) { //int x = ms.ReadByte(); //int y = ms.ReadByte(); byte[] loc = new byte[2]; ms.Read(loc, 0, 2); int x = BitConverter.ToInt16(loc, 0); ms.Read(loc, 0, 2); int y = BitConverter.ToInt16(loc, 0); System.Windows.Forms.MouseButtons button = System.Windows.Forms.MouseButtons.None; switch (ms.ReadByte()) { case 1: button = System.Windows.Forms.MouseButtons.Left; break; case 2: button = System.Windows.Forms.MouseButtons.Right; break; case 4: button = System.Windows.Forms.MouseButtons.Middle; break; case 8: button = System.Windows.Forms.MouseButtons.XButton1; break; case 16: button = System.Windows.Forms.MouseButtons.XButton2; break; } int extra = ms.ReadByte(); int click = 0; int scroll = 0; switch (type) { case EventType.MouseClick: case EventType.MouseDoubleClick: click = extra; break; case EventType.MouseWheel: if ((extra & 0x80) == 0x80) { scroll = -1; } else { scroll = 1; } extra &= 0x7F; scroll = scroll * extra * 120; //Delta break; } args = new MouseHookEventArgs(false, button, click, x, y, scroll, args.Alt, args.Control, args.Shift, args.CapsLock, args.NumLock, args.ScrollLock); } else { ms.Read(pressedKeys, 0, 3); pressedChar = (char)ms.ReadByte(); args = new KeyHookEventArgs(pressedKeys[0], pressedChar, false, args.Alt, args.Control, args.Shift, args.CapsLock, args.NumLock, args.ScrollLock); } return(true); } } return(false); }