Execute actions in response to events.

master
Pacman Ghost 7 years ago
parent 48f326c5f3
commit c71ebadc51
  1. 46
      MainApp/AppConfig.cs
  2. 10
      MainApp/Utils.cs
  3. 153
      MouseDll/actions.cpp
  4. 52
      MouseDll/actions.hpp
  5. 3
      MouseDll/api.hpp
  6. 61
      MouseDll/appProfile.cpp
  7. 7
      MouseDll/appProfile.hpp
  8. 191
      MouseDll/core2.cpp
  9. 16
      MouseDll/device.cpp
  10. 12
      MouseDll/deviceConfig.cpp
  11. 59
      MouseDll/event.cpp
  12. 17
      MouseDll/event.hpp
  13. 32
      MouseDll/globals.cpp
  14. 8
      MouseDll/globals.hpp
  15. 8
      MouseDll/mouse.vcproj
  16. 171
      MouseDll/sendInput.cpp
  17. 37
      MouseDll/sendInput.hpp

@ -18,6 +18,8 @@ namespace MouseInterception
// alignment issues. It's safer to send through a separate array for each type of struct, and then
// elements specify which ones they want via a start index and item count. Sigh...
public enum KeyModifiers { ctrl=0x0001 , alt=0x0002 , shift=0x0004 }
// --- SETTINGS: application settings ---
[StructLayout( LayoutKind.Sequential , CharSet=CharSet.Unicode , Pack=1 )]
public struct ApiSettings
@ -56,6 +58,8 @@ namespace MouseInterception
public struct ApiAppProfile
{
public string mApp ;
public int mSensitivityX ;
public int mSensitivityY ;
public int mEventStartIndex ;
public int mEventCount ;
}
@ -66,8 +70,10 @@ namespace MouseInterception
[StructLayout( LayoutKind.Sequential , CharSet=CharSet.Unicode , Pack=1 )]
public struct ApiEvent
{
public enum EventType { mouseLeft=1 , mouseRight=2 , mouseUp=3 , mouseDown=4 }
public enum KeyModifiers { ctrl=0x0001 , alt=0x0002 , shift=0x0004 }
public enum EventType {
mouseLeft=1 , mouseRight=2 , mouseUp=3 , mouseDown=4 ,
wheelLeft=5 , wheelRight=6 , wheelUp=7 , wheelDown=8
}
public int mEventType ;
public int mKeyModifiers ;
public int mActionStartIndex ;
@ -80,8 +86,12 @@ namespace MouseInterception
[StructLayout( LayoutKind.Sequential , CharSet=CharSet.Unicode , Pack=1 )]
public struct ApiAction
{
public enum ActionType { mouseLeft=1 , mouseRight=2 , mouseUp=3 , mouseDown=4 }
public enum ActionType {
mouseLeft=1 , mouseRight=2 , mouseUp=3 , mouseDown=4 ,
wheelLeft=5 , wheelRight=6 , wheelUp=7 , wheelDown=8
}
public int mActionType ;
public int mKeyModifiers ;
}
public ApiAction[] mActions ;
public ApiAction[] actions { get { return mActions ; } }
@ -142,7 +152,13 @@ namespace MouseInterception
foreach( XmlNode appProfileXmlNode in deviceConfigXmlNode.SelectNodes("appProfile") )
{
ApiAppProfile appProfile = new ApiAppProfile() ;
appProfile.mApp = Utils.getXmlAttr( appProfileXmlNode , "app" ) ;
appProfile.mApp = Utils.getXmlAttr( appProfileXmlNode , "app" , "" ) ;
XmlNode xn = appProfileXmlNode.SelectSingleNode( "sensitivity" ) ;
if ( xn != null )
{
appProfile.mSensitivityX = Utils.getXmlAttr( xn , "x" , 0 ) ;
appProfile.mSensitivityY = Utils.getXmlAttr( xn , "y" , 0 ) ;
}
appProfile.mEventStartIndex = events.Count ;
appProfile.mEventCount = 0 ;
// parse the events
@ -150,13 +166,7 @@ namespace MouseInterception
{
ApiEvent evt = new ApiEvent() ;
evt.mEventType = (int) Enum.Parse( typeof(ApiEvent.EventType) , eventXmlNode.Attributes["type"].Value , true ) ;
evt.mKeyModifiers = 0 ;
foreach( string km in Enum.GetNames(typeof(ApiEvent.KeyModifiers)) )
{
bool? keyState = Utils.getKeyState( eventXmlNode , km ) ;
if ( keyState.HasValue && (bool)keyState )
evt.mKeyModifiers += (int) Enum.Parse( typeof(ApiEvent.KeyModifiers) , km , true ) ;
}
evt.mKeyModifiers = getXmlNodeKeyModifiers( eventXmlNode ) ;
// parse the actions
evt.mActionStartIndex = actions.Count ;
evt.mActionCount = 0 ;
@ -164,6 +174,7 @@ namespace MouseInterception
{
ApiAction action = new ApiAction() ;
action.mActionType = (int) Enum.Parse( typeof(ApiAction.ActionType) , actionXmlNode.Attributes["type"].Value , true ) ;
action.mKeyModifiers = getXmlNodeKeyModifiers( actionXmlNode ) ;
actions.Add( action ) ;
evt.mActionCount ++ ;
}
@ -183,5 +194,18 @@ namespace MouseInterception
mActions = actions.ToArray() ;
}
private static int getXmlNodeKeyModifiers( XmlNode xmlNode )
{
// get the key modifiers
int keyModifiers = 0 ;
foreach( string km in Enum.GetNames(typeof(KeyModifiers)) )
{
bool? keyState = Utils.getKeyState( xmlNode , km ) ;
if ( keyState.HasValue && (bool)keyState )
keyModifiers += (int) Enum.Parse( typeof(KeyModifiers) , km , true ) ;
}
return keyModifiers ;
}
}
}

@ -65,7 +65,15 @@ namespace MouseInterception
return xmlAttr.Value ;
return defaultVal ;
}
public static string getXmlAttr( XmlNode xn , string s ) { return getXmlAttr(xn,s,"") ; }
public static int getXmlAttr( XmlNode xmlNode , string attrName , int defaultVal )
{
// get the attribute value
XmlAttribute xmlAttr = xmlNode.Attributes[ attrName ] ;
if ( xmlAttr != null )
return Int32.Parse( xmlAttr.Value ) ;
return defaultVal ;
}
public static IntPtr toUtf8( string val )
{

@ -1,4 +1,5 @@
#include "actions.hpp"
#include "sendInput.hpp"
#include "globals.hpp"
using namespace std ;
@ -6,12 +7,8 @@ using namespace std ;
// --- Action ---------------------------------------------------------
Action::Action( const ApiAction* pAction )
: mKeyModifiers( pAction->mKeyModifiers )
{
// NOTE: These relationships are not *necessary*, but let's keep things consistent.
assert( atMouseLeft == dLeft ) ;
assert( atMouseRight == dRight ) ;
assert( atMouseUp == dUp ) ;
assert( atMouseDown == dDown ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -25,6 +22,10 @@ Action::allocAction( const ApiAction* pAction )
case Action::atMouseRight: return new MouseRightAction(pAction) ;
case Action::atMouseUp: return new MouseUpAction(pAction) ;
case Action::atMouseDown: return new MouseDownAction(pAction) ;
case Action::atWheelLeft: return new WheelLeftAction(pAction) ;
case Action::atWheelRight: return new WheelRightAction(pAction) ;
case Action::atWheelUp: return new WheelUpAction(pAction) ;
case Action::atWheelDown: return new WheelDownAction(pAction) ;
default:
assert( false ) ;
return NULL ;
@ -33,6 +34,24 @@ Action::allocAction( const ApiAction* pAction )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string
Action::asString() const
{
// return the Action as a string
stringstream buf ;
buf << "<" << pActionName() ;
if ( keyModifiers() != 0 )
buf << ":" << keyModifiersString(keyModifiers()) ;
buf << ">" ;
return buf.str() ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int Action::keyModifiers() const { return mKeyModifiers ; }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ostream&
operator<<( ostream& os , const Action& action )
{
@ -51,14 +70,17 @@ MouseLeftAction::MouseLeftAction( const ApiAction* pAction )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
MouseLeftAction::doAction() const
MouseLeftAction::doAction( void* pInfo , CSendInput* pSendInput ) const
{
assert(0);//FIXME
// send a "mouse move left" event
int scrollSize = (int) pInfo ;
scrollSize = scrollSize / 100 ; // unscale the movement (100 = 1 unit)
pSendInput->sendMouseMoveInput( -scrollSize , 0 , keyModifiers() ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string MouseLeftAction::asString() const { return "<MouseLeftAction>" ; }
const char* MouseLeftAction::pActionName() const { return "MouseLeftAction" ; }
// --- MouseRightAction -----------------------------------------------
@ -70,14 +92,17 @@ MouseRightAction::MouseRightAction( const ApiAction* pAction )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
MouseRightAction::doAction() const
MouseRightAction::doAction( void* pInfo , CSendInput* pSendInput ) const
{
assert(0);//FIXME
// send a "mouse move right" event
int scrollSize = (int) pInfo ;
scrollSize = scrollSize / 100 ; // unscale the movement (100 = 1 unit)
pSendInput->sendMouseMoveInput( scrollSize , 0 , keyModifiers() ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string MouseRightAction::asString() const { return "<MouseRightAction>" ; }
const char* MouseRightAction::pActionName() const { return "MouseRightAction" ; }
// --- MouseUpAction --------------------------------------------------
@ -89,14 +114,17 @@ MouseUpAction::MouseUpAction( const ApiAction* pAction )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
MouseUpAction::doAction() const
MouseUpAction::doAction( void* pInfo , CSendInput* pSendInput ) const
{
assert(0);//FIXME
// send a "mouse move up" event
int scrollSize = (int) pInfo ;
scrollSize = scrollSize / 100 ; // unscale the movement (100 = 1 unit)
pSendInput->sendMouseMoveInput( 0 , -scrollSize , keyModifiers() ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string MouseUpAction::asString() const { return "<MouseUpAction>" ; }
const char* MouseUpAction::pActionName() const { return "MouseUpAction" ; }
// --- MouseDownAction ------------------------------------------------
@ -108,11 +136,102 @@ MouseDownAction::MouseDownAction( const ApiAction* pAction )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
MouseDownAction::doAction() const
MouseDownAction::doAction( void* pInfo , CSendInput* pSendInput ) const
{
// send a "mouse move down" event
int scrollSize = (int) pInfo ;
scrollSize = scrollSize / 100 ; // unscale the movement (100 = 1 unit)
pSendInput->sendMouseMoveInput( 0 , scrollSize , keyModifiers() ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* MouseDownAction::pActionName() const { return "MouseDownAction" ; }
// --- WheelLeftAction ------------------------------------------------
WheelLeftAction::WheelLeftAction( const ApiAction* pAction )
: Action( pAction )
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
WheelLeftAction::doAction( void* pInfo , CSendInput* pSendInput ) const
{
// send a "scroll wheel left" event
int scrollSize = (int) pInfo ;
scrollSize = WHEEL_DELTA * scrollSize / 100 ; // unscale the movement (100 = 1 unit)
pSendInput->sendHorzWheelInput( -scrollSize , keyModifiers() ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* WheelLeftAction::pActionName() const { return "WheelLeftAction" ; }
// --- WheelRightAction -----------------------------------------------
WheelRightAction::WheelRightAction( const ApiAction* pAction )
: Action( pAction )
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
WheelRightAction::doAction( void* pInfo , CSendInput* pSendInput ) const
{
// send a "scroll wheel left" event
int scrollSize = (int) pInfo ;
scrollSize = WHEEL_DELTA * scrollSize / 100 ; // unscale the movement (100 = 1 unit)
pSendInput->sendHorzWheelInput( scrollSize , keyModifiers() ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* WheelRightAction::pActionName() const { return "WheelRightAction" ; }
// --- WheelUpAction --------------------------------------------------
WheelUpAction::WheelUpAction( const ApiAction* pAction )
: Action( pAction )
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
WheelUpAction::doAction( void* pInfo , CSendInput* pSendInput ) const
{
// send a "scroll wheel up" event
int scrollSize = (int) pInfo ;
scrollSize = WHEEL_DELTA * scrollSize / 100 ; // unscale the movement (100 = 1 unit)
pSendInput->sendWheelInput( scrollSize , keyModifiers() ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* WheelUpAction::pActionName() const { return "WheelUpAction" ; }
// --- WheelDownAction ------------------------------------------------
WheelDownAction::WheelDownAction( const ApiAction* pAction )
: Action( pAction )
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
WheelDownAction::doAction( void* pInfo , CSendInput* pSendInput ) const
{
assert(0);//FIXME
// send a "scroll wheel down" event
int scrollSize = (int) pInfo ;
scrollSize = WHEEL_DELTA * scrollSize / 100 ; // unscale the movement (100 = 1 unit)
pSendInput->sendWheelInput( -scrollSize , keyModifiers() ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string MouseDownAction::asString() const { return "<MouseDownAction>" ; }
const char* WheelDownAction::pActionName() const { return "WheelDownAction" ; }

@ -4,6 +4,7 @@
#include "utils.hpp"
struct ApiAction ;
class CSendInput ;
// ---------------------------------------------------------------------
@ -12,7 +13,10 @@ class Action
// data types:
public:
enum eActionType { atMouseLeft=1 , atMouseRight=2 , atMouseUp=3 , atMouseDown=4 } ;
enum eActionType {
atMouseLeft=1 , atMouseRight=2 , atMouseUp=3 , atMouseDown=4 ,
atWheelLeft=5 , atWheelRight=6 , atWheelUp=7 , atWheelDown=8
} ;
// constructors/destructor:
public:
@ -22,11 +26,19 @@ protected:
DISABLE_COPY_ASSIGNMENT( Action ) ;
// action methods:
virtual void doAction() const = 0 ;
public:
virtual void doAction( void* pInfo , CSendInput* pSendInput ) const = 0 ;
// access methods:
public:
virtual std::string asString() const = 0 ;
int keyModifiers() const ;
virtual std::string asString() const ;
protected:
virtual const char* pActionName() const = 0 ;
// data members:
private:
int mKeyModifiers ;
} ;
@ -41,8 +53,8 @@ std::ostream& operator<<( std::ostream& , const Action& ) ;
public: \
ClassName( const ApiAction* pAction ) ; \
public: \
virtual std::string asString() const ; \
virtual void doAction() const ;
virtual void doAction( void* pInfo , CSendInput* pSendInput ) const ; \
virtual const char* pActionName() const ;
// ---------------------------------------------------------------------
@ -74,4 +86,32 @@ class MouseDownAction : public Action
// ---------------------------------------------------------------------
#endif // ACTIONS_HPP
class WheelLeftAction : public Action
{
DEFINE_ACTION_CLASS( WheelLeftAction ) ;
} ;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class WheelRightAction : public Action
{
DEFINE_ACTION_CLASS( WheelRightAction ) ;
} ;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class WheelUpAction : public Action
{
DEFINE_ACTION_CLASS( WheelUpAction ) ;
} ;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class WheelDownAction : public Action
{
DEFINE_ACTION_CLASS( WheelDownAction ) ;
} ;
// ---------------------------------------------------------------------
#endif // ACTIONS_HPP

@ -38,6 +38,8 @@ struct ApiDeviceConfig
struct ApiAppProfile
{
const wchar_t* mpApp ;
int mSensitivityX ;
int mSensitivityY ;
int mEventStartIndex ;
int mEventCount ;
} ;
@ -57,6 +59,7 @@ struct ApiEvent
struct ApiAction
{
int mActionType ;
int mKeyModifiers ;
} ;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

@ -13,6 +13,8 @@ AppProfile::AppProfile(
{
// initialize the Device
mApp = toUtf8( pAppProfile->mpApp ) ;
mSensitivityX = pAppProfile->mSensitivityX ;
mSensitivityY = pAppProfile->mSensitivityY ;
// initialize the Device
for ( int i=0 ; i < nEvents ; ++i )
@ -49,6 +51,59 @@ AppProfile::AppProfile(
// ---------------------------------------------------------------------
const Event*
AppProfile::findEvent( Event::eEventType eventType , int keyModifiers ) const
{
// find the specified event
for ( EventPtrVector::const_iterator it=events().begin() ; it != events().end() ; ++it )
{
const Event* pEvent = *it ;
// FIXME! if no key modifier events are configured, then ignore keyModifiers?
if ( pEvent->eventType() == eventType && pEvent->keyModifiers() == keyModifiers )
return pEvent ;
}
return NULL ;
}
// ---------------------------------------------------------------------
int
AppProfile::sensitivity( Event::eEventType eventType ) const
{
// convert the externally-configured values to internally-usable values
switch( eventType ) // FIXME! shouldn't have a switch
{
case Event::etMouseLeft:
case Event::etMouseRight:
return 5 - sensitivityX() ; // FIXME! base value s.b. configurable
break ;
case Event::etMouseUp:
case Event::etMouseDown:
return 5 - sensitivityY() ; // FIXME! base value s.b. configurable
break ;
case Event::etWheelLeft:
case Event::etWheelRight:
case Event::etWheelUp:
case Event::etWheelDown:
return 1 ;
break ;
default:
assert( false ) ;
return 1 ;
break ;
}
}
// ---------------------------------------------------------------------
const string& AppProfile::app() const { return mApp ; }
int AppProfile::sensitivityX() const { return mSensitivityX ; }
int AppProfile::sensitivityY() const { return mSensitivityY ; }
const EventPtrVector& AppProfile::events() const { return mEvents ; }
// ---------------------------------------------------------------------
void
AppProfile::dumpAppProfile( ostream& os , const char* pPrefix ) const
{
@ -56,6 +111,7 @@ AppProfile::dumpAppProfile( ostream& os , const char* pPrefix ) const
if ( pPrefix == NULL )
pPrefix = "" ;
os << pPrefix << "AppProfile: \"" << app() << "\"" << endl ;
os << " sensitivity: x=" << sensitivityX() << " ; y=" << sensitivityY() << endl ;
for ( EventPtrVector::const_iterator it=events().begin() ; it != events().end() ; ++it )
(*it)->dumpEvent( os , MAKE_CSTRING(pPrefix << " ") ) ;
}
@ -69,8 +125,3 @@ operator<<( ostream& os , const AppProfile& appProfile )
os << "[AppProfile:" << appProfile.app() << "]" ;
return os ;
}
// ---------------------------------------------------------------------
const string& AppProfile::app() const { return mApp ; }
const EventPtrVector& AppProfile::events() const { return mEvents ; }

@ -22,7 +22,12 @@ public:
// access methods:
public:
const std::string& app() const ;
int sensitivity( Event::eEventType eventType ) const ;
int sensitivityX() const ;
int sensitivityY() const ;
const EventPtrVector& events() const ;
public:
const Event* findEvent( Event::eEventType eventType , int keyModifiers ) const ;
// miscellaneous methods:
public:
@ -31,6 +36,8 @@ public:
// data members:
private:
std::string mApp ;
int mSensitivityX ;
int mSensitivityY ;
EventPtrVector mEvents ;
} ;

@ -1,6 +1,9 @@
#include <windows.h>
#include <psapi.h>
#include <deque>
#include "globals.hpp"
#include "sendInput.hpp"
using namespace std ;
@ -8,18 +11,22 @@ typedef pair< DWORD , InterceptionMouseStroke > TimestampMouseStrokePair ;
typedef deque<TimestampMouseStrokePair> MouseStrokeHistory ;
typedef map< InterceptionDevice , MouseStrokeHistory > MouseStrokeHistoryTable ;
typedef map< Event::eEventType , size_t > EventTypeSizetMap ;
typedef map< InterceptionDevice , EventTypeSizetMap > EventCountTable ;
// --- LOCAL DATA ------------------------------------------------------
#define MAX_STROKE_HISTORY 20
#define DEFAULT_STROKE_HISTORY_RESET_INTERVAL 100 // milliseconds
#define DIRN_DETECT_WINDOW_SIZE 10
#define DIRN_DETECT_HORZ_BIAS 1.2 // FIXME! s.b. configurable
#define DETECT_MOUSE_MOVE_WINDOW_SIZE 10
#define DETECT_MOUSE_MOVE_HORZ_BIAS 1.2 // FIXME! s.b. configurable
// local functions:
static void doRunMainLoop( int* pExitFlag ) ;
static bool detectDirn( const MouseStrokeHistory* pStrokeHistory , eDirn* pDirn , int* pMagnitude ) ;
static bool findDevice( InterceptionDevice hDevice , Device** ppDevice , DeviceConfig** ppDeviceConfig ) ;
static bool detectMouseMove( const MouseStrokeHistory* pStrokeHistory , Event::eEventType* pEventType , int* pMagnitude ) ;
static bool findDevice( InterceptionDevice hDevice , const Device** ppDevice , const DeviceConfig** ppDeviceConfig ) ;
static const AppProfile* findAppProfile( const DeviceConfig* pDeviceConfig, const AppProfile** ppDefaultAppProfile ) ;
// --- LOCAL DATA ------------------------------------------------------
@ -87,6 +94,7 @@ doRunMainLoop( int* pExitFlag )
// run the main loop
MouseStrokeHistoryTable mouseMovesHistoryTable ;
EventCountTable eventCounts ;
for ( ; ; )
{
// wait for the next event
@ -117,22 +125,16 @@ doRunMainLoop( int* pExitFlag )
else
strokeType = stMouseMove ;
string strokeTypeString = enumString( gStrokeTypeStringTable , strokeType ) ;
int keyModifiers = 0 ;
if ( GetAsyncKeyState(VK_CONTROL) < 0 )
keyModifiers |= Event::kmCtrl ;
if ( GetAsyncKeyState(VK_MENU) < 0 )
keyModifiers |= Event::kmAlt ;
if ( GetAsyncKeyState(VK_SHIFT) < 0 )
keyModifiers |= Event::kmShift ;
int keyModifiers = CSendInput::getKeyboardState() ;
// log the raw event
if ( isLoggingEnabled( "rawEvents" ) )
{
string keyModifiersString ;
if ( keyModifiers != 0 )
keyModifiersString = MAKE_STRING( " " << Event::keyModifiersString(keyModifiers) << " ;" ) ;
keyModifiersString = MAKE_STRING( " " << ::keyModifiersString(keyModifiers) << " ;" ) ;
LOG_MSG(
strokeTypeString << ": " << keyModifiersString
strokeTypeString << ":" << keyModifiersString
<< " hDevice=" << hDevice
<< " ; state=0x" << hexString(pStroke->state)
<< " ; flags=0x" << hexString(pStroke->flags)
@ -144,8 +146,8 @@ doRunMainLoop( int* pExitFlag )
}
// find the device that generated the event
Device* pDevice ;
DeviceConfig* pDeviceConfig ;
const Device* pDevice ;
const DeviceConfig* pDeviceConfig ;
if ( ! findDevice( hDevice , &pDevice , &pDeviceConfig ) )
{
// can't find the the device - check if we've seen it before
@ -172,7 +174,21 @@ doRunMainLoop( int* pExitFlag )
continue ;
}
// handle the event
// find the required AppProfile
const AppProfile* pDefaultAppProfile ;
const AppProfile* pAppProfile = findAppProfile( pDeviceConfig , &pDefaultAppProfile ) ;
if ( pAppProfile == NULL )
pAppProfile = pDefaultAppProfile ;
if ( pAppProfile == NULL )
{
// can't find one - just forward the event (for normal processing)
interception_send( hContext , hDevice ,&stroke , 1 ) ;
continue ;
}
// figure out what we should do
const Event* pEvent = NULL ;
void* pEventInfo = NULL ;
if ( strokeType == stMouseMove )
{
// record the stroke
@ -188,30 +204,73 @@ doRunMainLoop( int* pExitFlag )
pStrokeHistory->push_back( make_pair( strokeTimestamp , *pStroke ) ) ;
while ( pStrokeHistory->size() > MAX_STROKE_HISTORY )
pStrokeHistory->pop_front() ;
// figure out which way the mouse is moving
eDirn dirn ;
int dirnMagnitude ; // FIXME! scale this value?
if ( detectDirn( pStrokeHistory , &dirn , &dirnMagnitude ) )
LOG_CMSG( "events" , strokeTypeString << ": dirn=" << toString(dirn) << "/" << dirnMagnitude )
Event::eEventType eventType ;
int magnitude ;
if ( detectMouseMove( pStrokeHistory , &eventType , &magnitude ) )
LOG_CMSG( "events" , strokeTypeString << ": " << eventType << "/" << magnitude )
// check if this event has been configured
pEvent = pAppProfile->findEvent( eventType , keyModifiers ) ;
if ( pEvent == NULL && pAppProfile != pDefaultAppProfile )
pEvent = pDefaultAppProfile->findEvent( eventType , keyModifiers ) ;
// scale the movement (100 = 1 unit)
pEventInfo = (void*) (100 * magnitude) ;
}
else if ( strokeType == stMouseWheel )
{
eDirn dirn = (pStroke->rolling) < 0 ? dDown : dUp ;
int wheelSize = abs( pStroke->rolling ) ; // FIXME! scale this value?
LOG_CMSG( "events" , strokeTypeString << ": dirn=" << toString(dirn) << "/" << wheelSize ) ;
// figure out which way the wheel is moving
int dirn = (pStroke->rolling) < 0 ? -1 : +1 ;
int wheelSize = abs( pStroke->rolling ) ;
LOG_CMSG( "events" , strokeTypeString << ": " << (dirn < 0?"down":"up") << "/" << wheelSize ) ;
// check if this event has been configured
Event::eEventType eventType = (dirn < 0) ? Event::etWheelDown : Event::etWheelUp ;
pEvent = pAppProfile->findEvent( eventType , keyModifiers ) ;
if ( pEvent == NULL && pAppProfile != pDefaultAppProfile )
pEvent = pDefaultAppProfile->findEvent( eventType , keyModifiers ) ;
// scale the movement (100 = 1 unit)
pEventInfo = (void*) (100 * wheelSize / (WHEEL_DELTA/10)) ; // FIXME! scaling s.b. configurable
}
else if ( strokeType == stMouseHorzWheel )
{
eDirn dirn = (pStroke->rolling) < 0 ? dLeft : dRight ;
int wheelSize = abs( pStroke->rolling ) ; // FIXME! scale this value?
LOG_CMSG( "events" , strokeTypeString << ": dirn=" << toString(dirn) << "/" << wheelSize ) ;
// figure out which way the wheel is moving
int dirn = (pStroke->rolling) < 0 ? -1 : +1 ;
int wheelSize = abs( pStroke->rolling ) ;
LOG_CMSG( "events" , strokeTypeString << ": " << (dirn < 0?"left":"right") << "/" << wheelSize ) ;
// check if this event has been configured
Event::eEventType eventType = (dirn < 0) ? Event::etWheelLeft : Event::etWheelRight ;
pEvent = pAppProfile->findEvent( eventType , keyModifiers ) ;
if ( pEvent == NULL && pAppProfile != pDefaultAppProfile )
pEvent = pDefaultAppProfile->findEvent( eventType , keyModifiers ) ;
// scale the movement (100 = 1 unit)
pEventInfo = (void*) (100 * wheelSize / (WHEEL_DELTA/10)) ; // FIXME! scaling s.b. configurable
}
else
assert( false ) ;
// check for sensitivity
if ( pEvent != NULL )
{
// nb: we reduce sensitivity by ignoring events
int sensitivity = pAppProfile->sensitivity( pEvent->eventType() ) ;
if ( sensitivity > 0 && (++eventCounts[hDevice][pEvent->eventType()] % sensitivity) != 0 )
continue ; // nb: we don't forward the event
}
// handle the event
if ( pEvent != NULL )
{
CSendInput sendInput ;
for ( ActionPtrVector::const_iterator it=pEvent->actions().begin() ; it != pEvent->actions().end() ; ++it )
{
const Action* pAction = *it ;
LOG_CMSG( "actions" , "ACTION: " << *pAction ) ;
pAction->doAction( pEventInfo , &sendInput ) ;
}
continue ;
}
// the event wasn't handled - forward the event (for normal processing)
interception_send( hContext , hDevice ,&stroke , 1 ) ;
interception_send( hContext , hDevice , &stroke , 1 ) ;
}
// clean up
@ -224,39 +283,39 @@ doRunMainLoop( int* pExitFlag )
// ---------------------------------------------------------------------
static bool
detectDirn( const MouseStrokeHistory* pStrokeHistory , eDirn* pDirn , int* pDirnMagnitude )
detectMouseMove( const MouseStrokeHistory* pStrokeHistory , Event::eEventType* pEventType , int* pMagnitude )
{
// check if we have enough stroke history
if ( pStrokeHistory->size() < DIRN_DETECT_WINDOW_SIZE )
if ( pStrokeHistory->size() < DETECT_MOUSE_MOVE_WINDOW_SIZE )
return false ;
// figure out which direction the mouse is moving in
LOG_CMSG( "dirnDetect" , "DIRN DETECT: #=" << DIRN_DETECT_WINDOW_SIZE << "/" << pStrokeHistory->size() ) ;
LOG_CMSG( "detectMouseMove" , "DETECT MOUSE MOVE: #=" << DETECT_MOUSE_MOVE_WINDOW_SIZE << "/" << pStrokeHistory->size() ) ;
int cumX=0 , cumY=0 , nStrokes=0 ;
for ( MouseStrokeHistory::const_reverse_iterator it=pStrokeHistory->rbegin() ; it != pStrokeHistory->rend() ; ++it )
{
const InterceptionMouseStroke& stroke = (*it).second ;
cumX += stroke.x ;
cumY += stroke.y ;
LOG_CMSG( "dirnDetect" , " x=" << stroke.x << " ; y=" << stroke.y << " ; cum=" << cumX << "/" << cumY ) ;
if ( ++nStrokes >= DIRN_DETECT_WINDOW_SIZE )
LOG_CMSG( "detectMouseMove" , " x=" << stroke.x << " ; y=" << stroke.y << " ; cum=" << cumX << "/" << cumY ) ;
if ( ++nStrokes >= DETECT_MOUSE_MOVE_WINDOW_SIZE )
break ;
}
// NOTE: It's easier to move a device up/down without drifting left/right, so we bias left/right detection.
int biasedCumX = (int)(1000*cumX * DIRN_DETECT_HORZ_BIAS) / 1000 ;
int biasedCumX = (int)(1000*cumX * DETECT_MOUSE_MOVE_HORZ_BIAS) / 1000 ;
if ( abs(biasedCumX) >= abs(cumY) )
{
*pDirn = biasedCumX < 0 ? dLeft : dRight ;
*pDirnMagnitude = abs( biasedCumX / nStrokes ) ;
*pEventType = biasedCumX < 0 ? Event::etMouseLeft : Event::etMouseRight;
*pMagnitude = abs( biasedCumX / nStrokes ) ;
}
else
{
*pDirn = cumY < 0 ? dUp : dDown ;
*pDirnMagnitude = abs( cumY / nStrokes ) ;
*pEventType = cumY < 0 ? Event::etMouseUp : Event::etMouseDown ;
*pMagnitude = abs( cumY / nStrokes ) ;
}
LOG_CMSG( "dirnDetect" ,
LOG_CMSG( "detectMouseMove" ,
" cumX=" << biasedCumX << "(" << cumX << ") ; cumY=" << cumY
<< " ; dirn=" << toString(*pDirn) << "/" << *pDirnMagnitude
<< " ; " << *pEventType << "/" << *pMagnitude
) ;
return true ;
@ -265,17 +324,17 @@ detectDirn( const MouseStrokeHistory* pStrokeHistory , eDirn* pDirn , int* pDirn
// ---------------------------------------------------------------------
static bool
findDevice( InterceptionDevice hDevice , Device** ppDevice , DeviceConfig** ppDeviceConfig )
findDevice( InterceptionDevice hDevice , const Device** ppDevice , const DeviceConfig** ppDeviceConfig )
{
// find the specified device
for( DeviceTable::iterator it=gDeviceTable.begin() ; it != gDeviceTable.end() ; ++it )
for( DeviceTable::const_iterator it=gDeviceTable.begin() ; it != gDeviceTable.end() ; ++it )
{
Device* pDevice = (*it).second ;
const Device* pDevice = (*it).second ;
// FIXME! have to check HID as well
if ( pDevice->deviceNumber() == hDevice )
{
// found it - found the corresponding DeviceConfig
DeviceConfigTable::iterator it2 = gDeviceConfigTable.find( pDevice->deviceId() ) ;
DeviceConfigTable::const_iterator it2 = gDeviceConfigTable.find( pDevice->deviceId() ) ;
if ( it2 != gDeviceConfigTable.end() )
{
*ppDevice = pDevice ;
@ -286,3 +345,47 @@ findDevice( InterceptionDevice hDevice , Device** ppDevice , DeviceConfig** ppDe
}
return false ;
}
// ---------------------------------------------------------------------
const AppProfile*
findAppProfile( const DeviceConfig* pDeviceConfig , const AppProfile** ppDefaultAppProfile )
{
// get the EXE that owns the foreground window
string processExeName ;
HWND hWnd = GetForegroundWindow() ;
if ( hWnd != NULL )
{
DWORD processId ;
DWORD rc = GetWindowThreadProcessId( hWnd , &processId ) ;
if ( rc )
{
HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION , FALSE , processId ) ;
if ( hProcess != NULL )
{
wchar_t buf[ MAX_PATH+1 ] ;
DWORD nChars = sizeof(buf) / sizeof(wchar_t) ;
BOOL rc = QueryFullProcessImageName( hProcess , 0 , buf , &nChars ) ;
if ( rc )
processExeName = toUtf8( buf , nChars ) ;
CloseHandle( hProcess ) ;
}
}
}
// find the AppProfile that belongs to the EXE
const AppProfile* pAppProfileToReturn = NULL ;
const AppProfile* pDefaultAppProfile = NULL ;
for ( AppProfilePtrVector::const_iterator it=pDeviceConfig->appProfiles().begin() ; it != pDeviceConfig->appProfiles().end() ; ++it )
{
const AppProfile* pAppProfile = *it ;
// FIXME! check for just EXE name (no path)
if ( _stricmp( pAppProfile->app().c_str() , processExeName.c_str() ) == 0 )
pAppProfileToReturn = pAppProfile ;
if ( pAppProfile->app().empty() )
pDefaultAppProfile = *it ;
}
*ppDefaultAppProfile = pDefaultAppProfile ;
return pAppProfileToReturn ;
}

@ -17,6 +17,14 @@ Device::Device( const ApiDevice* pDevice )
// ---------------------------------------------------------------------
int Device::deviceId() const { return mDeviceId ; }
const string& Device::hid() const { return mHID ; }
int Device::deviceNumber() const { return mDeviceNumber ; }
const string& Device::displayName() const { return mDisplayName ; }
bool Device::isEnabled() const { return mIsEnabled ; }
// ---------------------------------------------------------------------
void
Device::dumpDevice( ostream& os , const char* pPrefix ) const
{
@ -39,11 +47,3 @@ operator<<( ostream& os , const Device& device )
os << "[Device-" << device.deviceId() << ":" << device.hid() << "/" << device.deviceNumber() << "]" ;
return os ;
}
// ---------------------------------------------------------------------
int Device::deviceId() const { return mDeviceId ; }
const string& Device::hid() const { return mHID ; }
int Device::deviceNumber() const { return mDeviceNumber ; }
const string& Device::displayName() const { return mDisplayName ; }
bool Device::isEnabled() const { return mIsEnabled ; }

@ -52,6 +52,12 @@ DeviceConfig::DeviceConfig(
// ---------------------------------------------------------------------
int DeviceConfig::deviceId() const { return mDeviceId ; }
const int DeviceConfig::strokeHistoryResetInterval() const { return mStrokeHistoryResetInterval ; }
const AppProfilePtrVector& DeviceConfig::appProfiles() const { return mAppProfiles ; }
// ---------------------------------------------------------------------
void
DeviceConfig::dumpDeviceConfig( ostream& os , const char* pPrefix ) const
{
@ -74,9 +80,3 @@ operator<<( ostream& os , const DeviceConfig& deviceConfig )
os << "[DeviceConfig:" << deviceConfig.deviceId() << "]" ;
return os ;
}
// ---------------------------------------------------------------------
int DeviceConfig::deviceId() const { return mDeviceId ; }
const int DeviceConfig::strokeHistoryResetInterval() const { return mStrokeHistoryResetInterval ; }
const AppProfilePtrVector& DeviceConfig::appProfiles() const { return mAppProfiles ; }

@ -7,14 +7,8 @@ using namespace std ;
Event::Event( const ApiEvent* pEvent , const ApiAction* pActions , int nActions )
{
// NOTE: These relationships are not *necessary*, but let's keep things consistent.
assert( etMouseLeft == dLeft ) ;
assert( etMouseRight == dRight ) ;
assert( etMouseUp == dUp ) ;
assert( etMouseDown == dDown ) ;
// initialize the Event
mEventType = pEvent->mEventType ;
mEventType = (eEventType) pEvent->mEventType ;
mKeyModifiers = pEvent->mKeyModifiers ;
// initialize the Event
@ -24,6 +18,12 @@ Event::Event( const ApiEvent* pEvent , const ApiAction* pActions , int nActions
// ---------------------------------------------------------------------
Event::eEventType Event::eventType() const { return mEventType ; }
int Event::keyModifiers() const { return mKeyModifiers ; }
const ActionPtrVector& Event::actions() const { return mActions ; }
// ---------------------------------------------------------------------
void
Event::dumpEvent( ostream& os , const char* pPrefix ) const
{
@ -38,40 +38,29 @@ Event::dumpEvent( ostream& os , const char* pPrefix ) const
ostream&
operator<<( ostream& os , const Event& evt )
{
static EnumStringInfo stringTable[] = {
{ Event::etMouseLeft , "mouseLeft" } ,
{ Event::etMouseRight , "mouseRight" } ,
{ Event::etMouseUp , "mouseUp" } ,
{ Event::etMouseDown , "mouseDown" } ,
{ -1 , NULL }
} ;
// insert the Event
os << "{Event:" << enumString(stringTable,evt.eventType()) ;
os << "{Event:" << evt.eventType() ;
if ( evt.keyModifiers() != 0 )
os << ":" << Event::keyModifiersString(evt.keyModifiers()) ;
os << ":" << keyModifiersString(evt.keyModifiers()) ;
os << "}" ;
return os ;
}
// ---------------------------------------------------------------------
string
Event::keyModifiersString( int keyModifiers )
ostream&
operator<<( ostream& os , const Event::eEventType& eventType )
{
// return the KeyModifiers as a string
static BitFlagsInfo stringTable[] =
{
{ Event::kmCtrl , "Ctrl" } ,
{ Event::kmAlt , "Alt" } ,
{ Event::kmShift , "Shift" } ,
{ -1 , NULL } ,
// insert the eEventType
static EnumStringInfo stringTable[] = {
{ Event::etMouseLeft , "mouseLeft" } ,
{ Event::etMouseRight , "mouseRight" } ,
{ Event::etMouseUp , "mouseUp" } ,
{ Event::etMouseDown , "mouseDown" } ,
{ Event::etWheelLeft , "wheelLeft" } ,
{ Event::etWheelRight , "wheelRight" } ,
{ Event::etWheelUp , "wheelUp" } ,
{ Event::etWheelDown , "wheelDown" } ,
{ -1 , NULL }
} ;
return bitFlagsString( stringTable , keyModifiers , '+' ) ;
os << enumString(stringTable,eventType) ;
return os ;
}
// ---------------------------------------------------------------------
int Event::eventType() const { return mEventType ; }
int Event::keyModifiers() const { return mKeyModifiers ; }
const ActionPtrVector& Event::actions() const { return mActions ; }

@ -13,8 +13,10 @@ class Event
// data types:
public:
enum eEventType { etMouseLeft=1 , etMouseRight=2 , etMouseUp=3 , etMouseDown=4 } ;
enum eKeyModifiers { kmCtrl=0x0001 , kmAlt=0x0002 , kmShift=0x0004 } ;
enum eEventType {
etMouseLeft=1 , etMouseRight=2 , etMouseUp=3 , etMouseDown=4 ,
etWheelLeft=5 , etWheelRight=6 , etWheelUp=7 , etWheelDown=8
} ;
// constructors/destructor:
public:
@ -23,19 +25,15 @@ public:
// access methods:
public:
int eventType() const ;
eEventType eventType() const ;
int keyModifiers() const ;
const ActionPtrVector& actions() const ;
public:
void dumpEvent( std::ostream& os , const char* pPrefix="" ) const ;
// miscellaneous methods:
public:
static std::string keyModifiersString( int keyModifiers ) ;
// data members:
private:
int mEventType ;
eEventType mEventType ;
int mKeyModifiers ;
ActionPtrVector mActions ;
@ -43,8 +41,9 @@ private:
typedef PtrVector<Event> EventPtrVector ;
// inserter
// inserters
std::ostream& operator<<( std::ostream& , const Event& ) ;
std::ostream& operator<<( std::ostream& , const Event::eEventType& ) ;
// ---------------------------------------------------------------------

@ -25,6 +25,22 @@ ofstream gLogFile ;
// ---------------------------------------------------------------------
string
keyModifiersString( int keyModifiers )
{
// return the KeyModifiers as a string
static BitFlagsInfo stringTable[] =
{
{ kmCtrl , "Ctrl" } ,
{ kmAlt , "Alt" } ,
{ kmShift , "Shift" } ,
{ -1 , NULL } ,
} ;
return bitFlagsString( stringTable , keyModifiers , '+' ) ;
}
// ---------------------------------------------------------------------
static StringSet gLogging ;
void initLogging( const wchar_t* pLogging )
@ -91,22 +107,6 @@ makeLogMsg( const string& msg )
// ---------------------------------------------------------------------
string toString( eDirn dirn )
{
// return the eDirn as a string
static EnumStringInfo stringTable[] = {
{ dUnknown , "UNKNOWN" } ,
{ dLeft , "LEFT" } ,
{ dRight , "RIGHT" } ,
{ dUp , "UP" } ,
{ dDown , "DOWN" } ,
{ -1 , NULL }
} ;
return enumString( stringTable , dirn ) ;
}
// ---------------------------------------------------------------------
ostream&
operator<<( ostream& os , const exception& xcptn )
{

@ -13,15 +13,15 @@
#include "api.hpp"
#include "utils.hpp"
// ---------------------------------------------------------------------
typedef std::vector<char> CharVector ;
typedef std::vector<wchar_t> WideCharVector ;
typedef std::set<int> IntSet ;
typedef std::set<std::string> StringSet ;
// ---------------------------------------------------------------------
enum eDirn { dUnknown=-1 , dLeft=1 , dRight=2 , dUp=3 , dDown=4 } ;
extern std::string toString( eDirn ) ;
enum eKeyModifiers { kmCtrl=0x0001 , kmAlt=0x0002 , kmShift=0x0004 } ;
extern std::string keyModifiersString( int keyModifiers ) ;
// ---------------------------------------------------------------------

@ -218,6 +218,10 @@
RelativePath=".\globals.cpp"
>
</File>
<File
RelativePath=".\sendInput.cpp"
>
</File>
<File
RelativePath=".\utils.cpp"
>
@ -256,6 +260,10 @@
RelativePath=".\globals.hpp"
>
</File>
<File
RelativePath=".\sendInput.hpp"
>
</File>
<File
RelativePath=".\utils.hpp"
>

@ -0,0 +1,171 @@
#include "sendInput.hpp"
#include "globals.hpp"
using namespace std ;
// --- CONSTRUCTORS ----------------------------------------------------
CSendInput::CSendInput()
{
}
// --- DESTRUCTOR ------------------------------------------------------
CSendInput::~CSendInput()
{
}
// ---------------------------------------------------------------------
void
CSendInput::sendKeyboardInput( WORD keyCode , bool keyDown , int keyModifiers )
{
// send the keyboard input
INPUT inputRec ;
memset( &inputRec , 0 , sizeof(INPUT) ) ;
inputRec.type = INPUT_KEYBOARD ;
inputRec.ki.wVk = keyCode ;
if ( ! keyDown )
inputRec.ki.dwFlags |= KEYEVENTF_KEYUP ;
doSendInput( &inputRec , keyModifiers ) ;
}
// ---------------------------------------------------------------------
void
CSendInput::sendMouseMoveInput( int dx , int dy , int keyModifiers )
{
// send the mouse movement input
INPUT inputRec ;
memset( &inputRec , 0 , sizeof(INPUT) ) ;
inputRec.type = INPUT_MOUSE ;
inputRec.mi.dx = dx ;
inputRec.mi.dy = dy ;
inputRec.mi.dwFlags = MOUSEEVENTF_MOVE ;
doSendInput( &inputRec , keyModifiers ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
CSendInput::sendWheelInput( int scrollSize , int keyModifiers )
{
// send the mouse-wheel input
INPUT inputRec ;
memset( &inputRec , 0 , sizeof(INPUT) ) ;
inputRec.type = INPUT_MOUSE ;
inputRec.mi.dwFlags = MOUSEEVENTF_WHEEL ;
inputRec.mi.mouseData = scrollSize ; // FIXME! s.b. dwData for vista
doSendInput( &inputRec , keyModifiers ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
CSendInput::sendHorzWheelInput( int scrollSize , int keyModifiers )
{
// send the mouse-wheel input
INPUT inputRec ;
memset( &inputRec , 0 , sizeof(INPUT) ) ;
inputRec.type = INPUT_MOUSE ;
inputRec.mi.dwFlags = MOUSEEVENTF_HWHEEL ;
inputRec.mi.mouseData = scrollSize ; // FIXME! s.b. dwData for vista
doSendInput( &inputRec , keyModifiers ) ;
}
// ---------------------------------------------------------------------
void
CSendInput::doSendInput( INPUT* pInputRec , int keyModifiers )
{
// set the keyboard state
bool isCtrlDown , isAltDown , isShiftDown ;
if ( keyModifiers >= 0 )
{
getKeyboardState( &isCtrlDown , &isAltDown , &isShiftDown ) ;
if ( (keyModifiers & kmCtrl) && !isCtrlDown )
sendKeyboardInput( VK_CONTROL , true , -1 ) ;
else if ( !(keyModifiers & kmCtrl) && isCtrlDown )
sendKeyboardInput( VK_CONTROL , false , -1 ) ;
if ( (keyModifiers & kmAlt) && !isAltDown )
sendKeyboardInput( VK_MENU , true , -1 ) ;
else if ( !(keyModifiers & kmAlt) && isAltDown )
sendKeyboardInput( VK_MENU , false , -1 ) ;
if ( (keyModifiers & kmShift) && !isShiftDown )
sendKeyboardInput( VK_SHIFT , true , -1 ) ;
else if ( !(keyModifiers & kmShift) && isShiftDown )
sendKeyboardInput( VK_SHIFT , false , -1 ) ;
}
// log the input
if ( isLoggingEnabled( "sendInput" ) )
{
if ( pInputRec->type == INPUT_MOUSE )
{
LOG_MSG(
"SEND INPUT (mouse):"
<< " dx=" << pInputRec->mi.dx << " ; dy=" << pInputRec->mi.dy
<< " ; mouseData=" << (int)pInputRec->mi.mouseData
<< " ; flags=0x" << hexString(pInputRec->mi.dwFlags)
) ;
}
else if ( pInputRec->type == INPUT_KEYBOARD )
{
LOG_MSG(
"SEND INPUT (keyboard):"
<< " vkey=" << pInputRec->ki.wVk << " ; scan=" << pInputRec->ki.wScan
<< " ; flags=0x" << hexString(pInputRec->ki.dwFlags)
) ;
}
else
assert( false ) ;
}
// send the input
// NOTE: The documentation says that we can send multiple events at once, and they will be guaranteed
// to not have other events interspersed between them, but things don't work :-( and the only way
// I could get it to work was to send events one at a time, with a (non-zero) sleep between them.
// Maybe because we're manipulating the Ctrl/Alt/Shift keys...?
UINT nEventRecs = SendInput( 1 , pInputRec , sizeof(INPUT) ) ;
assert( nEventRecs == 1 ) ;
Sleep( 5 ) ;
// restore the keyboard state
if ( keyModifiers >= 0 )
{
if ( (keyModifiers & kmShift) && !isShiftDown )
sendKeyboardInput( VK_SHIFT , false , -1 ) ;
else if ( !(keyModifiers & kmShift) && isShiftDown )
sendKeyboardInput( VK_SHIFT , true , -1 ) ;
if ( (keyModifiers & kmAlt) && !isAltDown )
sendKeyboardInput( VK_MENU , false , -1 ) ;
else if ( !(keyModifiers & kmAlt) && isAltDown )
sendKeyboardInput( VK_MENU , true , -1 ) ;
if ( (keyModifiers & kmCtrl) && !isCtrlDown )
sendKeyboardInput( VK_CONTROL , false , -1 ) ;
else if ( !(keyModifiers & kmCtrl) && isCtrlDown )
sendKeyboardInput( VK_CONTROL , true , -1 ) ;
}
}
// ---------------------------------------------------------------------
void
CSendInput::getKeyboardState( bool* pIsCtrlDown , bool* pIsAltDown , bool* pIsShiftDown )
{
// get the keyboard state
*pIsCtrlDown = GetAsyncKeyState( VK_CONTROL ) < 0 ;
*pIsAltDown = GetAsyncKeyState( VK_MENU ) < 0 ;
*pIsShiftDown = GetAsyncKeyState( VK_SHIFT ) < 0 ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int
CSendInput::getKeyboardState()
{
// get the keyboard state
bool isCtrlDown , isAltDown , isShiftDown ;
getKeyboardState( &isCtrlDown , &isAltDown , &isShiftDown ) ;
return (isCtrlDown ? kmCtrl : 0) | (isAltDown ? kmAlt : 0) | (isShiftDown ? kmShift : 0 ) ;
}

@ -0,0 +1,37 @@
#ifndef SENDINPUT_HPP
#define SENDINPUT_HPP
#include <windows.h>
#include "utils.hpp"
// ---------------------------------------------------------------------
class CSendInput
{
// constructors/destructor:
public:
CSendInput() ;
~CSendInput() ;
DISABLE_COPY_ASSIGNMENT( CSendInput ) ;
// input methods:
public:
void sendKeyboardInput( WORD keyCode , bool keyDown , int keyModifiers ) ;
void sendMouseMoveInput( int dx , int dy , int keyModifiers ) ;
void sendWheelInput( int scrollSize , int keyModifiers ) ;
void sendHorzWheelInput( int scrollSize , int keyModifiers ) ;
protected:
void doSendInput( INPUT* pInputRec , int keyModifiers ) ;
// miscellaneous methods:
public:
static void getKeyboardState( bool* pIsCtrlDown , bool* pIsAltDown , bool* pIsShiftDown ) ;
static int getKeyboardState() ;
} ;
// ---------------------------------------------------------------------
#endif // SENDINPUT_HPP
Loading…
Cancel
Save