535 lines
15 KiB
C
535 lines
15 KiB
C
//
|
|
// Input Manager
|
|
//
|
|
|
|
#ifndef _H_IM
|
|
#define _H_IM
|
|
|
|
|
|
#if defined(DLL_CORE) || defined(DLL_HOOK)
|
|
|
|
//
|
|
//
|
|
// CONSTANTS
|
|
//
|
|
//
|
|
|
|
|
|
//
|
|
// Values used when accumulating events to return from IEM_TranslateLocal
|
|
// and IEM_TranslateRemote.
|
|
//
|
|
#define IEM_EVENT_CTRL_DOWN 1
|
|
#define IEM_EVENT_CTRL_UP 2
|
|
#define IEM_EVENT_SHIFT_DOWN 3
|
|
#define IEM_EVENT_SHIFT_UP 4
|
|
#define IEM_EVENT_MENU_DOWN 5
|
|
#define IEM_EVENT_MENU_UP 6
|
|
#define IEM_EVENT_FORWARD 7
|
|
#define IEM_EVENT_CONSUMED 8
|
|
#define IEM_EVENT_REPLAY 9
|
|
#define IEM_EVENT_REPLAY_VK 10
|
|
#define IEM_EVENT_REPLAY_VK_DOWN 11
|
|
#define IEM_EVENT_REPLAY_VK_UP 12
|
|
#define IEM_EVENT_CAPS_LOCK_UP 13
|
|
#define IEM_EVENT_CAPS_LOCK_DOWN 14
|
|
#define IEM_EVENT_NUM_LOCK_UP 15
|
|
#define IEM_EVENT_NUM_LOCK_DOWN 16
|
|
#define IEM_EVENT_SCROLL_LOCK_UP 17
|
|
#define IEM_EVENT_SCROLL_LOCK_DOWN 18
|
|
#define IEM_EVENT_REPLAY_SPECIAL_VK 21
|
|
#define IEM_EVENT_EXTENDED_KEY 22
|
|
#define IEM_EVENT_REPLAY_SECONDARY 23
|
|
#define IEM_EVENT_SYSTEM 24
|
|
#define IEM_EVENT_NORMAL 25
|
|
|
|
#define IEM_EVENT_HOTKEY_BASE 50
|
|
//
|
|
// Range of hotkeys is 0 - 99
|
|
//
|
|
#define IEM_EVENT_KEYPAD0_DOWN 150
|
|
//
|
|
// Range of keypad down is 0-9
|
|
//
|
|
#define IEM_EVENT_KEYPAD0_UP 160
|
|
|
|
//
|
|
// The flags used in the return value from VkKeyScan.
|
|
//
|
|
#define IEM_SHIFT_DOWN 0x0001
|
|
#define IEM_CTRL_DOWN 0x0002
|
|
#define IEM_MENU_DOWN 0x0004
|
|
|
|
|
|
//
|
|
// Virtual key codes.
|
|
//
|
|
#define VK_INVALID 0xFF
|
|
|
|
|
|
//
|
|
// Given the keyboard packet flags the following macros tell us things
|
|
// about the key event.
|
|
//
|
|
|
|
//
|
|
// This is TRUE if this event is a key press. It is FALSE for key releases
|
|
// and key repeats.
|
|
//
|
|
#define IS_IM_KEY_PRESS(A) \
|
|
(((A) & (TSHR_UINT16)(IM_FLAG_KEYBOARD_RELEASE | IM_FLAG_KEYBOARD_DOWN))==0)
|
|
|
|
//
|
|
// This is TRUE if this event is a key release. It is FALSE for key
|
|
// presses and key repeats. Note that it is also TRUE for the
|
|
// theoretically impossible case of a key release when the key is already
|
|
// up (this combination could conceviably be generated if events are
|
|
// discarded by USER or our emulation of USER).
|
|
//
|
|
#define IS_IM_KEY_RELEASE(A) (((A) & IM_FLAG_KEYBOARD_RELEASE))
|
|
|
|
//
|
|
// This is TRUE if this event is a key repeat. It is FALSE for key presses
|
|
// and key releases.
|
|
//
|
|
#define IS_IM_KEY_REPEAT(A) \
|
|
(((A) & (IM_FLAG_KEYBOARD_RELEASE | IM_FLAG_KEYBOARD_DOWN))==\
|
|
IM_FLAG_KEYBOARD_DOWN)
|
|
|
|
//
|
|
// This is TRUE if the key is the right-variant of a modifier. It is FALSE
|
|
// otherwise.
|
|
//
|
|
#define IS_IM_KEY_RIGHT(A) (((A) & IM_FLAG_KEYBOARD_RIGHT))
|
|
|
|
|
|
//
|
|
// The maximum amount of time that we expect an injected event to take to
|
|
// pass through USER.
|
|
//
|
|
#define IM_EVENT_PERCOLATE_TIME 300
|
|
|
|
//
|
|
// Max VK sync attempts.
|
|
//
|
|
#define IM_MAX_VK_SYNC_ATTEMPTS 10
|
|
|
|
//
|
|
// Declare our function prototype for <ImmGetVirtualKey>.
|
|
//
|
|
typedef UINT (WINAPI* IMMGVK)(HWND);
|
|
|
|
|
|
|
|
//
|
|
//
|
|
// MACROS
|
|
//
|
|
//
|
|
//
|
|
// Macros to convert between logical mouse co-ordinates (e.g. (320,240) for
|
|
// the centre of a VGA screen to the full 16-bit range co-ordinates used
|
|
// by Windows (e.g. (320,240) is (32767, 32767).
|
|
//
|
|
#define IM_MOUSEPOS_LOG_TO_OS(coord, size) \
|
|
(((65535L * (TSHR_UINT32)coord) + 32768L) / (TSHR_UINT32)size)
|
|
|
|
//
|
|
// Macros extracting information from the mouse event flags field (event
|
|
// mask).
|
|
//
|
|
#define IM_MEV_MOVE_ONLY(e) ((e).event.mouse.flags == MOUSEEVENTF_MOVE)
|
|
#define IM_MEV_MOVE(e) (((e).event.mouse.flags & MOUSEEVENTF_MOVE) != 0 )
|
|
#define IM_MEV_ABS_MOVE(e) ((((e).event.mouse.flags & \
|
|
(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE)) == \
|
|
(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE) ))
|
|
#define IM_MEV_BUTTON_DOWN(e) \
|
|
(((e).event.mouse.flags & IM_MOUSEEVENTF_BUTTONDOWN_FLAGS) != 0 )
|
|
#define IM_MEV_BUTTON_UP(e) \
|
|
(((e).event.mouse.flags & IM_MOUSEEVENTF_BUTTONUP_FLAGS) != 0 )
|
|
|
|
#define IM_EVMASK_B1_DOWN(m) (((m) & MOUSEEVENTF_LEFTDOWN) != 0 )
|
|
#define IM_EVMASK_B1_UP(m) (((m) & MOUSEEVENTF_LEFTUP) != 0 )
|
|
#define IM_EVMASK_B2_DOWN(m) (((m) & MOUSEEVENTF_RIGHTDOWN) != 0 )
|
|
#define IM_EVMASK_B2_UP(m) (((m) & MOUSEEVENTF_RIGHTUP) != 0 )
|
|
#define IM_EVMASK_B3_DOWN(m) (((m) & MOUSEEVENTF_MIDDLEDOWN) != 0 )
|
|
#define IM_EVMASK_B3_UP(m) (((m) & MOUSEEVENTF_MIDDLEUP) != 0 )
|
|
|
|
#define IM_MEV_BUTTON1_DOWN(e) (IM_EVMASK_B1_DOWN((e).event.mouse.flags))
|
|
#define IM_MEV_BUTTON2_DOWN(e) (IM_EVMASK_B2_DOWN((e).event.mouse.flags))
|
|
#define IM_MEV_BUTTON3_DOWN(e) (IM_EVMASK_B3_DOWN((e).event.mouse.flags))
|
|
#define IM_MEV_BUTTON1_UP(e) (IM_EVMASK_B1_UP((e).event.mouse.flags))
|
|
#define IM_MEV_BUTTON2_UP(e) (IM_EVMASK_B2_UP((e).event.mouse.flags))
|
|
#define IM_MEV_BUTTON3_UP(e) (IM_EVMASK_B3_UP((e).event.mouse.flags))
|
|
|
|
#define IM_KEV_KEYUP(e) ((e).event.keyboard.flags & KEYEVENTF_KEYUP)
|
|
#define IM_KEV_KEYDOWN(e) (!IM_KEV_KEYUP(e))
|
|
#define IM_KEV_VKCODE(e) ((e).event.keyboard.vkCode)
|
|
|
|
#define IM_MOUSEEVENTF_BASE_FLAGS ( MOUSEEVENTF_MOVE | \
|
|
MOUSEEVENTF_LEFTUP | \
|
|
MOUSEEVENTF_LEFTDOWN | \
|
|
MOUSEEVENTF_RIGHTUP | \
|
|
MOUSEEVENTF_RIGHTDOWN | \
|
|
MOUSEEVENTF_MIDDLEUP | \
|
|
MOUSEEVENTF_MIDDLEDOWN )
|
|
|
|
#define IM_MOUSEEVENTF_CLICK_FLAGS ( MOUSEEVENTF_LEFTUP | \
|
|
MOUSEEVENTF_LEFTDOWN | \
|
|
MOUSEEVENTF_RIGHTUP | \
|
|
MOUSEEVENTF_RIGHTDOWN | \
|
|
MOUSEEVENTF_MIDDLEUP | \
|
|
MOUSEEVENTF_MIDDLEDOWN )
|
|
|
|
|
|
#define IM_MOUSEEVENTF_BUTTONDOWN_FLAGS ( MOUSEEVENTF_LEFTDOWN | \
|
|
MOUSEEVENTF_RIGHTDOWN | \
|
|
MOUSEEVENTF_MIDDLEDOWN )
|
|
|
|
#define IM_MOUSEEVENTF_BUTTONUP_FLAGS ( MOUSEEVENTF_LEFTUP | \
|
|
MOUSEEVENTF_RIGHTUP | \
|
|
MOUSEEVENTF_MIDDLEUP )
|
|
|
|
|
|
|
|
typedef struct tagKBDEV
|
|
{
|
|
WORD vkCode;
|
|
WORD scanCode;
|
|
DWORD flags;
|
|
DWORD time;
|
|
DWORD dwExtraInfo;
|
|
}
|
|
KBDEV, FAR *LPKBDEV;
|
|
|
|
|
|
typedef struct tagMSEV
|
|
{
|
|
POINTL pt;
|
|
DWORD cButtons;
|
|
DWORD mouseData;
|
|
DWORD flags;
|
|
DWORD time;
|
|
DWORD dwExtraInfo;
|
|
}
|
|
MSEV, FAR *LPMSEV;
|
|
|
|
|
|
//
|
|
// The IMOSEVENTS which we queue as they arrive from the mouse or
|
|
// keyboard hooks or after IMINCOMINGEVENTS have been translated into local
|
|
// events by the IEM.
|
|
//
|
|
typedef struct tagIMOSEVENT
|
|
{
|
|
TSHR_UINT32 type;
|
|
#define IM_MOUSE_EVENT 1
|
|
#define IM_KEYBOARD_EVENT 2
|
|
|
|
TSHR_UINT32 flags;
|
|
#define IM_FLAG_DONT_REPLAY 0x0001
|
|
#define IM_FLAG_UPDATESTATE 0x0002
|
|
|
|
TSHR_UINT32 time;
|
|
union
|
|
{
|
|
MSEV mouse;
|
|
KBDEV keyboard;
|
|
}
|
|
event;
|
|
}
|
|
IMOSEVENT;
|
|
typedef IMOSEVENT FAR * LPIMOSEVENT;
|
|
|
|
|
|
|
|
|
|
#define IM_TRANSFER_EVENT_BUFFER_SIZE 32
|
|
#define IM_MAX_TRANSFER_EVENT_INDEX (IM_TRANSFER_EVENT_BUFFER_SIZE-1)
|
|
|
|
|
|
typedef struct tagIMTRANSFEREVENT
|
|
{
|
|
LONG fInUse;
|
|
IMOSEVENT event;
|
|
}
|
|
IMTRANSFEREVENT, FAR * LPIMTRANSFEREVENT;
|
|
|
|
|
|
|
|
//
|
|
// For handling keyboard events in hooks
|
|
//
|
|
#define IM_MASK_KEYBOARD_SYSFLAGS 0xE100
|
|
#define IM_MASK_KEYBOARD_SYSSCANCODE 0x00FF
|
|
|
|
#define IM_MAX_DEAD_KEYS 20
|
|
|
|
#define IM_SIZE_EVENTQ 40
|
|
#define IM_SIZE_OSQ 80 // 2*EVENTQ size - key up/down
|
|
|
|
//
|
|
// Define the flags that can be returned by IMConvertIMPacketToOSEvent().
|
|
//
|
|
#define IM_IMQUEUEREMOVE 0x0001
|
|
#define IM_OSQUEUEINJECT 0x0002
|
|
|
|
//
|
|
// For managing our key state arrays.
|
|
//
|
|
#define IM_KEY_STATE_FLAG_TOGGLE (BYTE)0x01
|
|
#define IM_KEY_STATE_FLAG_DOWN (BYTE)0x80
|
|
|
|
//
|
|
// Bounds for local mouse spoiling and packet piggyback target withhold
|
|
// Note that these are local spoiling values, to prevent the data pipe from
|
|
// getting clogged and introducing unnecessary latency. Now, you may think
|
|
// that 30 move messages per second is a little low, but put this up any
|
|
// higher and USER at the other end will just spoil them when it injects
|
|
// them into the app - that would be totally wasteful of precious bandwidth.
|
|
//
|
|
#define IM_LOCAL_MOUSE_SAMPLING_GAP_LOW_MS 100
|
|
#define IM_LOCAL_MOUSE_SAMPLING_GAP_MEDIUM_MS 75
|
|
#define IM_LOCAL_MOUSE_SAMPLING_GAP_HIGH_MS 50
|
|
#define IM_LOCAL_WITHHOLD_DELAY 150
|
|
#define IM_LOCAL_MOUSE_WITHHOLD 5
|
|
#define IM_LOCAL_KEYBOARD_WITHHOLD 2
|
|
|
|
//
|
|
// For pacing the accumulation and injecting of mouse events.
|
|
// We should play back at the same rate as the highest local sampling rate
|
|
// less a small amount for processing delay on the remote system
|
|
//
|
|
#define IM_REMOTE_MOUSE_PLAYBACK_GAP_MS 20
|
|
|
|
//
|
|
// The amount of time to hold on to a mouse button down event in case a the
|
|
// user is just clicking on eg a scroll button. If we did not hold on to
|
|
// the mouse button down event then the mouse button up would be sent in
|
|
// the next packet. On a slow network this means the remote application
|
|
// may process the down period for much longer than the user wanted.
|
|
//
|
|
#define IM_MOUSE_UP_WAIT_TIME 50
|
|
|
|
#define IM_MIN_RECONVERSION_INTERVAL_MS 150
|
|
|
|
|
|
//
|
|
// #define used non-Windows to flag a VK code that equates to an ascii char
|
|
//
|
|
#define IM_TYPE_VK_ASCII ((TSHR_UINT16)0x8880)
|
|
|
|
|
|
//
|
|
// Used for checking events about to be injected.
|
|
//
|
|
#define IM_KEY_IS_TOGGLE(A) \
|
|
(((A)==VK_CAPITAL)||((A)==VK_SCROLL)||((A)==VK_NUMLOCK))
|
|
|
|
#define IM_KEY_IS_MODIFIER(A) \
|
|
(((A)==VK_SHIFT)||((A)==VK_CONTROL)||((A)==VK_MENU))
|
|
|
|
//
|
|
// Used to check values in key state arrays.
|
|
//
|
|
#define IM_KEY_STATE_IS_UP(A) (!((A)&IM_KEY_STATE_FLAG_DOWN))
|
|
#define IM_KEY_STATE_IS_DOWN(A) ((A)&IM_KEY_STATE_FLAG_DOWN)
|
|
|
|
//
|
|
// Used to determine what sort of mouse event this is from the flags.
|
|
//
|
|
#define IM_IS_MOUSE_MOVE(A) \
|
|
((A) & IM_FLAG_MOUSE_MOVE)
|
|
|
|
#define IM_IS_MOUSE_PRESS(A) \
|
|
((!IM_IS_MOUSE_MOVE(A)) && ((A) & IM_FLAG_MOUSE_DOWN))
|
|
|
|
#define IM_IS_MOUSE_RELEASE(A) \
|
|
((!IM_IS_MOUSE_MOVE(A)) && !((A) & IM_FLAG_MOUSE_DOWN))
|
|
|
|
#define IM_IS_LEFT_CLICK(A) \
|
|
(((A) & (IM_FLAG_MOUSE_DOWN | IM_FLAG_MOUSE_BUTTON1 | IM_FLAG_MOUSE_DOUBLE)) == (IM_FLAG_MOUSE_DOWN | IM_FLAG_MOUSE_BUTTON1))
|
|
#define IM_IS_LEFT_DCLICK(A) \
|
|
(((A) & (IM_FLAG_MOUSE_DOWN | IM_FLAG_MOUSE_BUTTON1 | IM_FLAG_MOUSE_DOUBLE)) == (IM_FLAG_MOUSE_DOWN | IM_FLAG_MOUSE_BUTTON1 | IM_FLAG_MOUSE_DOUBLE))
|
|
|
|
|
|
|
|
//
|
|
// Holds NETWORK events, to person controlled by us, or from person in control
|
|
// of us.
|
|
//
|
|
typedef struct tagIMEVENTQ
|
|
{
|
|
DWORD head;
|
|
DWORD numEvents;
|
|
IMEVENT events[IM_SIZE_EVENTQ];
|
|
}
|
|
IMEVENTQ;
|
|
typedef IMEVENTQ FAR * LPIMEVENTQ;
|
|
|
|
|
|
//
|
|
// Holds translated events, suitable for injection from person
|
|
// in control of us, or pre-translated events to person controlled by us.
|
|
//
|
|
typedef struct tagIMOSQ
|
|
{
|
|
DWORD head;
|
|
DWORD numEvents;
|
|
IMOSEVENT events[IM_SIZE_OSQ];
|
|
}
|
|
IMOSQ;
|
|
typedef IMOSQ FAR * LPIMOSQ;
|
|
|
|
|
|
#define CIRCULAR_INDEX(start, rel_index, size) \
|
|
(((start) + (rel_index)) % (size))
|
|
|
|
|
|
|
|
|
|
//
|
|
// To support collaboration in both NT (background service thread) and Win95
|
|
// (win16 code) with as much of the common incoming/outgoing processing in
|
|
// one places, the IM data is separated into 4 types. There are structures
|
|
// for each of these types, so that moving a variable from one to another
|
|
// is as easy as possible. Note that the declarations are bitness-safe;
|
|
// they are the same size in 16-bit and 32-bit code. And that the structures
|
|
// are DWORD aligned.
|
|
//
|
|
// (1) IM_SHARED_DATA
|
|
// This is data that both the CPI32 library needs to access, and one or
|
|
// more of the NT/Win95 implementations of collaboration.
|
|
//
|
|
// (2) IM_NT_DATA
|
|
// This is data that only the NT version of collaboration needs.
|
|
//
|
|
// (3) IM_WIN95_DATA
|
|
// This is data that only the Win95 version of collaboration needs.
|
|
//
|
|
|
|
|
|
//
|
|
// For NT, this shared structures is just declared in MNMCPI32.NT's data,
|
|
// and a pointer to it is used by the common lib.
|
|
//
|
|
// For Win95, this shared structure is allocated in a global memory block
|
|
// that can GlobalSmartPageLock() it as needed for access at interrupt time,
|
|
// and a pointer to it is mapped flat and returned to the common lib.
|
|
//
|
|
typedef struct tagIM_SHARED_DATA
|
|
{
|
|
#ifdef DEBUG
|
|
DWORD cbSize; // To make sure everybody agrees on size
|
|
#endif
|
|
|
|
//
|
|
// For critical errors -- nonzero if one is up
|
|
//
|
|
DWORD imSuspended;
|
|
|
|
//
|
|
// Control state
|
|
//
|
|
LONG imControlled;
|
|
LONG imPaused;
|
|
LONG imUnattended;
|
|
}
|
|
IM_SHARED_DATA, FAR* LPIM_SHARED_DATA;
|
|
|
|
|
|
// NT specific IM state variables
|
|
typedef struct tagIM_NT_DATA
|
|
{
|
|
//
|
|
// Low level hook thread
|
|
//
|
|
DWORD imLowLevelInputThread;
|
|
|
|
//
|
|
// Other desktop injection helper thread
|
|
//
|
|
DWORD imOtherDesktopThread;
|
|
|
|
//
|
|
// Low level hook handles
|
|
//
|
|
HHOOK imhLowLevelMouseHook;
|
|
HHOOK imhLowLevelKeyboardHook;
|
|
}
|
|
IM_NT_DATA, FAR* LPIM_NT_DATA;
|
|
|
|
|
|
|
|
// Win95 specific IM state variables
|
|
typedef struct tagIM_WIN95_DATA
|
|
{
|
|
BOOL imInjecting;
|
|
BOOL imLowLevelHooks;
|
|
|
|
//
|
|
// High level hook handles
|
|
//
|
|
HHOOK imhHighLevelMouseHook;
|
|
}
|
|
IM_WIN95_DATA, FAR* LPIM_WIN95_DATA;
|
|
|
|
|
|
|
|
//
|
|
//
|
|
// MACROS
|
|
//
|
|
//
|
|
#define IM_SET_VK_DOWN(A) (A) |= (BYTE)0x80
|
|
#define IM_SET_VK_UP(A) (A) &= (BYTE)0x7F
|
|
#define IM_TOGGLE_VK(A) (A) ^= (BYTE)0x01
|
|
|
|
//
|
|
//
|
|
// PROTOTYPES
|
|
//
|
|
//
|
|
|
|
|
|
// NT only
|
|
BOOL WINAPI OSI_InstallHighLevelMouseHook(BOOL fOn);
|
|
|
|
BOOL WINAPI OSI_InstallControlledHooks(BOOL fOn, BOOL fDesktop);
|
|
void WINAPI OSI_InjectMouseEvent(DWORD flags, LONG x, LONG y, DWORD mouseData, DWORD dwExtraInfo);
|
|
void WINAPI OSI_InjectKeyboardEvent(DWORD flags, WORD vkCode, WORD scanCode, DWORD dwExtraInfo);
|
|
void WINAPI OSI_InjectCtrlAltDel(void);
|
|
void WINAPI OSI_DesktopSwitch(UINT from, UINT to);
|
|
|
|
|
|
//
|
|
// Internal Hook DLL functions.
|
|
//
|
|
#ifdef DLL_HOOK
|
|
|
|
#ifdef IS_16
|
|
BOOL IM_DDInit(void);
|
|
void IM_DDTerm(void);
|
|
#endif // IS_16
|
|
|
|
LRESULT CALLBACK IMMouseHookProc(int code,
|
|
WPARAM wParam,
|
|
LPARAM lParam);
|
|
|
|
#endif // DLL_HOOK
|
|
|
|
|
|
#ifdef IS_16
|
|
void IMCheckWin16LockPulse(void);
|
|
#else
|
|
DWORD WINAPI IMLowLevelInputProcessor(LPVOID hEventWait);
|
|
DWORD WINAPI IMOtherDesktopProc(LPVOID hEventWait);
|
|
LRESULT CALLBACK IMLowLevelMouseProc(int, WPARAM, LPARAM);
|
|
LRESULT CALLBACK IMLowLevelKeyboardProc(int, WPARAM, LPARAM);
|
|
#endif // IS_16
|
|
|
|
#endif // DLL_CORE or DLL_HOOK
|
|
|
|
#endif // _H_IM
|
|
|