88namespace mozilla {
99namespace widget {
1010
11+ // Static member definitions
1112std::map<HWND, bool > InputFilter::sEnabledWindows ;
1213std::mutex InputFilter::sMutex ;
1314std::map<HWND, InputFilter::CursorPos> InputFilter::sCursorPositions ;
1415std::mutex InputFilter::sCursorMutex ;
16+ std::map<HWND, InputFilter::KeyboardState> InputFilter::sKeyboardStates ;
17+ std::mutex InputFilter::sKeyboardMutex ;
18+ std::map<HWND, InputFilter::MouseButtonState> InputFilter::sMouseButtonStates ;
19+ std::mutex InputFilter::sMouseButtonMutex ;
1520
1621HWND InputFilter::GetTopLevelWindow (HWND hwnd) {
1722 if (!hwnd) return nullptr ;
18-
19- // Walk up the parent chain to find the top-level window
2023 HWND parent = hwnd;
2124 HWND next;
2225 while ((next = ::GetParent (parent)) != nullptr ) {
@@ -25,38 +28,32 @@ HWND InputFilter::GetTopLevelWindow(HWND hwnd) {
2528 return parent;
2629}
2730
31+ // Window enable/disable
2832void InputFilter::EnableForWindow (HWND hwnd) {
2933 HWND topLevel = GetTopLevelWindow (hwnd);
3034 if (!topLevel) topLevel = hwnd;
31-
3235 std::lock_guard<std::mutex> lock (sMutex );
3336 sEnabledWindows [topLevel] = true ;
3437}
3538
3639void InputFilter::DisableForWindow (HWND hwnd) {
3740 HWND topLevel = GetTopLevelWindow (hwnd);
3841 if (!topLevel) topLevel = hwnd;
39-
4042 std::lock_guard<std::mutex> lock (sMutex );
4143 sEnabledWindows [topLevel] = false ;
4244}
4345
4446bool InputFilter::IsEnabledForWindow (HWND hwnd) {
4547 HWND topLevel = GetTopLevelWindow (hwnd);
4648 if (!topLevel) topLevel = hwnd;
47-
4849 std::lock_guard<std::mutex> lock (sMutex );
4950 auto it = sEnabledWindows .find (topLevel);
50- if (it != sEnabledWindows .end ()) {
51- return it->second ;
52- }
53- return false ; // Not in map means not enabled
51+ return (it != sEnabledWindows .end ()) ? it->second : false ;
5452}
5553
5654void InputFilter::RemoveWindow (HWND hwnd) {
5755 HWND topLevel = GetTopLevelWindow (hwnd);
5856 if (!topLevel) topLevel = hwnd;
59-
6057 {
6158 std::lock_guard<std::mutex> lock (sMutex );
6259 sEnabledWindows .erase (topLevel);
@@ -65,12 +62,98 @@ void InputFilter::RemoveWindow(HWND hwnd) {
6562 std::lock_guard<std::mutex> lock (sCursorMutex );
6663 sCursorPositions .erase (topLevel);
6764 }
65+ {
66+ std::lock_guard<std::mutex> lock (sKeyboardMutex );
67+ sKeyboardStates .erase (topLevel);
68+ }
69+ {
70+ std::lock_guard<std::mutex> lock (sMouseButtonMutex );
71+ sMouseButtonStates .erase (topLevel);
72+ }
73+ }
74+
75+ // Message type detection
76+ bool InputFilter::IsKeyboardMessage (UINT msg) {
77+ switch (msg) {
78+ case WM_KEYDOWN:
79+ case WM_KEYUP:
80+ case WM_SYSKEYDOWN:
81+ case WM_SYSKEYUP:
82+ case WM_CHAR:
83+ case WM_SYSCHAR:
84+ case WM_DEADCHAR:
85+ case WM_SYSDEADCHAR:
86+ case WM_UNICHAR:
87+ case WM_HOTKEY:
88+ case WM_IME_KEYDOWN:
89+ case WM_IME_KEYUP:
90+ case WM_IME_CHAR:
91+ case WM_IME_COMPOSITION:
92+ case WM_IME_STARTCOMPOSITION:
93+ case WM_IME_ENDCOMPOSITION:
94+ return true ;
95+ default :
96+ return false ;
97+ }
98+ }
99+
100+ bool InputFilter::IsMouseMessage (UINT msg) {
101+ switch (msg) {
102+ case WM_MOUSEMOVE:
103+ case WM_LBUTTONDOWN:
104+ case WM_LBUTTONUP:
105+ case WM_LBUTTONDBLCLK:
106+ case WM_RBUTTONDOWN:
107+ case WM_RBUTTONUP:
108+ case WM_RBUTTONDBLCLK:
109+ case WM_MBUTTONDOWN:
110+ case WM_MBUTTONUP:
111+ case WM_MBUTTONDBLCLK:
112+ case WM_XBUTTONDOWN:
113+ case WM_XBUTTONUP:
114+ case WM_XBUTTONDBLCLK:
115+ case WM_MOUSEWHEEL:
116+ case WM_MOUSEHWHEEL:
117+ case WM_NCMOUSEMOVE:
118+ case WM_NCLBUTTONDOWN:
119+ case WM_NCLBUTTONUP:
120+ case WM_NCLBUTTONDBLCLK:
121+ case WM_NCRBUTTONDOWN:
122+ case WM_NCRBUTTONUP:
123+ case WM_NCRBUTTONDBLCLK:
124+ case WM_NCMBUTTONDOWN:
125+ case WM_NCMBUTTONUP:
126+ case WM_NCMBUTTONDBLCLK:
127+ return true ;
128+ default :
129+ return false ;
130+ }
131+ }
132+
133+ bool InputFilter::IsInputMessage (UINT msg) {
134+ return IsKeyboardMessage (msg) || IsMouseMessage (msg);
135+ }
136+
137+ bool InputFilter::ShouldBlockNativeInput (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
138+ // If filtering not enabled for this window, don't block anything
139+ if (!IsEnabledForWindow (hwnd)) {
140+ return false ;
141+ }
142+
143+ // Only block input messages (keyboard and mouse)
144+ if (!IsInputMessage (msg)) {
145+ return false ;
146+ }
147+
148+ // Block all native input when filter is enabled
149+ // MouseMux will inject its own events which bypass this filter
150+ return true ;
68151}
69152
153+ // Cursor position tracking
70154void InputFilter::SetCursorPosForWindow (HWND hwnd, int screenX, int screenY) {
71155 HWND topLevel = GetTopLevelWindow (hwnd);
72156 if (!topLevel) topLevel = hwnd;
73-
74157 std::lock_guard<std::mutex> lock (sCursorMutex );
75158 CursorPos& pos = sCursorPositions [topLevel];
76159 pos.screenX = screenX;
@@ -81,15 +164,117 @@ void InputFilter::SetCursorPosForWindow(HWND hwnd, int screenX, int screenY) {
81164bool InputFilter::GetCursorPosForWindow (HWND hwnd, POINT* outPos) {
82165 HWND topLevel = GetTopLevelWindow (hwnd);
83166 if (!topLevel) topLevel = hwnd;
84-
85167 std::lock_guard<std::mutex> lock (sCursorMutex );
86168 auto it = sCursorPositions .find (topLevel);
87169 if (it != sCursorPositions .end () && it->second .valid ) {
88170 outPos->x = it->second .screenX ;
89171 outPos->y = it->second .screenY ;
90172 return true ;
91173 }
92- return false ; // No valid position stored
174+ return false ;
175+ }
176+
177+ // Keyboard state management
178+ void InputFilter::SetKeyStateForWindow (HWND hwnd, BYTE* keyState) {
179+ HWND topLevel = GetTopLevelWindow (hwnd);
180+ if (!topLevel) topLevel = hwnd;
181+ std::lock_guard<std::mutex> lock (sKeyboardMutex );
182+ KeyboardState& state = sKeyboardStates [topLevel];
183+ memcpy (state.keys , keyState, 256 );
184+ state.valid = true ;
185+ }
186+
187+ bool InputFilter::GetKeyStateForWindow (HWND hwnd, BYTE* outKeyState) {
188+ HWND topLevel = GetTopLevelWindow (hwnd);
189+ if (!topLevel) topLevel = hwnd;
190+ std::lock_guard<std::mutex> lock (sKeyboardMutex );
191+ auto it = sKeyboardStates .find (topLevel);
192+ if (it != sKeyboardStates .end () && it->second .valid ) {
193+ memcpy (outKeyState, it->second .keys , 256 );
194+ return true ;
195+ }
196+ return false ;
197+ }
198+
199+ void InputFilter::SetSingleKeyState (HWND hwnd, int vkey, bool down, bool toggled) {
200+ if (vkey < 0 || vkey > 255 ) return ;
201+
202+ HWND topLevel = GetTopLevelWindow (hwnd);
203+ if (!topLevel) topLevel = hwnd;
204+ std::lock_guard<std::mutex> lock (sKeyboardMutex );
205+ KeyboardState& state = sKeyboardStates [topLevel];
206+
207+ // High bit (0x80) = key is down
208+ // Low bit (0x01) = key is toggled (for toggle keys like CapsLock)
209+ BYTE val = 0 ;
210+ if (down) val |= 0x80 ;
211+ if (toggled) val |= 0x01 ;
212+ state.keys [vkey] = val;
213+ state.valid = true ;
214+ }
215+
216+ // Mouse button state management
217+ void InputFilter::SetMouseButtonState (HWND hwnd, bool left, bool right, bool middle) {
218+ HWND topLevel = GetTopLevelWindow (hwnd);
219+ if (!topLevel) topLevel = hwnd;
220+ std::lock_guard<std::mutex> lock (sMouseButtonMutex );
221+ MouseButtonState& state = sMouseButtonStates [topLevel];
222+ state.left = left;
223+ state.right = right;
224+ state.middle = middle;
225+ }
226+
227+ WORD InputFilter::GetMouseButtonState (HWND hwnd) {
228+ HWND topLevel = GetTopLevelWindow (hwnd);
229+ if (!topLevel) topLevel = hwnd;
230+ std::lock_guard<std::mutex> lock (sMouseButtonMutex );
231+ auto it = sMouseButtonStates .find (topLevel);
232+ if (it == sMouseButtonStates .end ()) {
233+ return 0 ;
234+ }
235+ WORD flags = 0 ;
236+ if (it->second .left ) flags |= MK_LBUTTON;
237+ if (it->second .right ) flags |= MK_RBUTTON;
238+ if (it->second .middle ) flags |= MK_MBUTTON;
239+ return flags;
240+ }
241+
242+ // Thread-local current window for KeyboardLayout to query
243+ static thread_local HWND sCurrentProcessingWindow = nullptr ;
244+
245+ void InputFilter::SetCurrentWindow (HWND hwnd) {
246+ sCurrentProcessingWindow = hwnd;
247+ }
248+
249+ HWND InputFilter::GetCurrentWindow () {
250+ return sCurrentProcessingWindow ;
251+ }
252+
253+ void InputFilter::ClearCurrentWindow () {
254+ sCurrentProcessingWindow = nullptr ;
255+ }
256+
257+ bool InputFilter::GetCurrentMouseButtons (uint16_t * outButtons) {
258+ HWND hwnd = sCurrentProcessingWindow ;
259+ if (!hwnd || !outButtons) {
260+ return false ;
261+ }
262+
263+ if (!IsEnabledForWindow (hwnd)) {
264+ return false ; // Use native GetKeyState
265+ }
266+
267+ // Get button state from our tracked state
268+ WORD flags = GetMouseButtonState (hwnd);
269+ *outButtons = 0 ;
270+
271+ // Convert MK_* flags to MouseButtonsFlag values
272+ // MouseButtonsFlag::ePrimaryFlag = 1, eSecondaryFlag = 2, eMiddleFlag = 4
273+ if (flags & MK_LBUTTON) *outButtons |= 1 ; // ePrimaryFlag
274+ if (flags & MK_RBUTTON) *outButtons |= 2 ; // eSecondaryFlag
275+ if (flags & MK_MBUTTON) *outButtons |= 4 ; // eMiddleFlag
276+
277+ return true ;
93278}
94279
95280} // namespace widget
0 commit comments