|
|
//
// 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
|