Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

534 lines
15 KiB

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