Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / misc / win_event_emitter.cpp
blob939ad047759349a2d1bc174a110d45821e0ebb83
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Robert TIMM (rti) <mail@rtti.de>
6 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "stdmisc.h"
23 #include "nel/misc/events.h"
24 #include "nel/misc/event_emitter.h"
25 #include "nel/misc/win_event_emitter.h"
26 #include "nel/misc/event_server.h"
27 #include "nel/misc/utf_string_view.h"
29 #ifdef NL_OS_WINDOWS
30 #include <windowsx.h>
32 /**
33 * Needed for definition of WM_MOUSEWHEEL. It should be in winuser.h
34 * but not under win98.. strange..
36 #include <zmouse.h>
38 #ifdef DEBUG_NEW
39 #define new DEBUG_NEW
40 #endif
42 namespace NLMISC {
44 /*------------------------------------------------------------------*\
45 submitEvents()
46 \*------------------------------------------------------------------*/
47 void CWinEventEmitter::submitEvents(CEventServer & server, bool allWindows)
49 MSG msg;
50 while ( PeekMessageW(&msg,allWindows?NULL:_HWnd,0,0,PM_REMOVE) )
52 TranslateMessage(&msg);
53 DispatchMessageW(&msg);
56 // Dispatch sent messages
57 _InternalServer.setServer (&server);
58 _InternalServer.pump (allWindows);
61 /*------------------------------------------------------------------*\
62 processMessage()
63 \*------------------------------------------------------------------*/
66 TKeyButton getKeyButton (bool _altButton, bool _shiftButton, bool _ctrlButton)
68 TKeyButton button=noKeyButton;
69 if (_altButton)
70 (int&)button|=altKeyButton;
71 if (_shiftButton)
72 (int&)button|=shiftKeyButton;
73 if (_ctrlButton)
74 (int&)button|=ctrlKeyButton;
76 return button;
79 /*TMouseButton getMouseButton (uint32 wParam, bool _altButton)
81 TMouseButton button=noButton;
82 if (wParam&MK_CONTROL)
83 (int&)button|=ctrlButton;
84 if (wParam&MK_LBUTTON)
85 (int&)button|=leftButton;
86 if (wParam&MK_RBUTTON)
87 (int&)button|=rightButton;
88 if (wParam&MK_MBUTTON)
89 (int&)button|=middleButton;
90 if (wParam&MK_SHIFT)
91 (int&)button|=shiftButton;
92 if (_altButton)
93 (int&)button|=altButton;
94 }*/
97 TMouseButton CWinEventEmitter::getButtons() const
99 uint result = (_CtrlButton ? ctrlButton : 0)
100 | (_AltButton ? altButton : 0)
101 | (_ShiftButton ? shiftButton : 0)
102 | (_CtrlButton ? ctrlButton : 0)
103 | (_MouseButtons[0] ? leftButton : 0)
104 | (_MouseButtons[1] ? rightButton : 0)
105 | (_MouseButtons[2] ? middleButton : 0);
106 return (TMouseButton) result;
110 bool CWinEventEmitter::processMessage (HWND hWnd, uint32 msg, WPARAM wParam, LPARAM lParam, CEventServer *server)
112 if (!server)
113 server=&_InternalServer;
115 /// Process IME messages
116 /*if ( _IMEEventsEnabled && (ImmIsUIMessage( ImmGetDefaultIMEWnd((HWND)_HWnd), msg, wParam, lParam) == TRUE) )
118 server->postEvent( new CEventIME(msg, wParam, lParam, this) );
119 return true; // trap message (however DefWindowProc will still be called in some instances by the event listener)
122 switch (msg)
124 case WM_KEYDOWN:
125 case WM_SYSKEYDOWN:
126 if (_KeyboardEventsEnabled)
128 // Ctrl, shit or alt ?
129 if ((sint)wParam==VK_MENU)
130 _AltButton=true;
131 if ((sint)wParam==VK_CONTROL)
132 _CtrlButton=true;
133 if ((sint)wParam==VK_SHIFT)
134 _ShiftButton=true;
136 // Post the message
137 if (wParam < KeyCount)
138 server->postEvent (new CEventKeyDown ((NLMISC::TKey)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), (((int) lParam)&(1<<30))==0, this));
140 break;
142 case WM_SYSKEYUP:
143 case WM_KEYUP:
144 if (_KeyboardEventsEnabled)
146 // Ctrl, shit or alt ?
147 if ((int)wParam==VK_MENU)
148 _AltButton=false;
149 if ((int)wParam==VK_CONTROL)
150 _CtrlButton=false;
151 if ((int)wParam==VK_SHIFT)
152 _ShiftButton=false;
154 // As Print Screen button does not trigger a WM_KEYDOWN msg, simulate it here
155 if ((int)wParam==VK_SNAPSHOT)
157 if (wParam < KeyCount)
158 server->postEvent (new CEventKeyDown ((NLMISC::TKey)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), true, this));
161 // Post the message
162 if (wParam < KeyCount)
163 server->postEvent (new CEventKeyUp ((NLMISC::TKey)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this));
165 break;
166 #ifdef WM_UNICHAR
167 case WM_UNICHAR:
168 if (wParam != UNICODE_NOCHAR && _KeyboardEventsEnabled)
170 //if (wParam < KeyCount)
171 //nlinfo("WM_UNICHAR with %u", wParam);
172 server->postEvent (new CEventChar ((u32char)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this));
174 break;
175 #endif
176 case WM_CHAR:
177 if (_KeyboardEventsEnabled)
179 //if (wParam < KeyCount)
180 //nlinfo("WM_CHAR with %u", wParam);
181 wchar_t c = (wchar_t)wParam;
182 if ((c & 0xFC00) == 0xD800)
184 _Utf16Pair = c;
186 else if (_Utf16Pair && (c & 0xFC00) == 0xDC00)
188 wchar_t cc[] = { _Utf16Pair, c, 0 };
189 _Utf16Pair = 0;
190 CUtfStringView cv = CUtfStringView(cc);
191 for (CUtfStringView::iterator it(cv.begin()), end(cv.end()); it != end; ++it)
192 server->postEvent(new CEventChar(*it, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this));
194 else
196 if (_Utf16Pair)
198 server->postEvent(new CEventChar(_Utf16Pair, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this));
199 _Utf16Pair = 0;
201 server->postEvent(new CEventChar(c, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this));
204 break;
205 /*case WM_IME_CHAR:
206 if (_KeyboardEventsEnabled && _IMEEventsEnabled)
208 server->postEvent (new CEventChar ((ucchar)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this));
210 break;*/
211 case WM_ACTIVATE:
212 if (WA_INACTIVE==LOWORD(wParam))
213 server->postEvent (new CEventActivate (false, this));
214 else
216 // Reset flags state
217 resetButtonFlagState ();
219 // Post the message
220 server->postEvent (new CEventActivate (true, this));
222 break;
223 case WM_KILLFOCUS:
224 server->postEvent (new CEventSetFocus (false, this));
225 break;
226 case WM_SETFOCUS:
227 // Reset flags state
228 resetButtonFlagState ();
230 // Post the message
231 server->postEvent (new CEventSetFocus (true, this));
232 break;
233 case WM_MOUSEMOVE:
234 case WM_RBUTTONDOWN:
235 case WM_LBUTTONDOWN:
236 case WM_MBUTTONDOWN:
237 case WM_RBUTTONUP:
238 case WM_LBUTTONUP:
239 case WM_MBUTTONUP:
240 case WM_RBUTTONDBLCLK:
241 case WM_MBUTTONDBLCLK:
242 case WM_LBUTTONDBLCLK:
244 if (_MouseEventsEnabled)
246 // MSWindows coordinates to NeL window coordinate
247 float fX, fY;
248 RECT client;
250 float xPos = (float)GET_X_LPARAM(lParam);
251 float yPos = (float)GET_Y_LPARAM(lParam);
253 GetClientRect (hWnd, &client);
254 fX=xPos/(float)(client.right-client.left);
255 fY=1.f-yPos/(float)(client.bottom-client.top);
257 // buttons
258 TMouseButton button=getButtons();
260 // Reswitch
261 switch (msg)
263 case WM_MOUSEMOVE:
264 server->postEvent (new CEventMouseMove (fX, fY, button, this));
265 break;
267 case WM_RBUTTONDOWN:
268 _MouseButtons[1] = true;
269 server->postEvent (new CEventMouseDown (fX, fY, (TMouseButton)(rightButton|(button&~(leftButton|middleButton|rightButton))), this));
270 break;
271 case WM_MBUTTONDOWN:
272 _MouseButtons[2] = true;
273 server->postEvent (new CEventMouseDown (fX, fY, (TMouseButton)(middleButton|(button&~(leftButton|middleButton|rightButton))), this));
274 break;
275 case WM_LBUTTONDOWN:
276 _MouseButtons[0] = true;
277 server->postEvent (new CEventMouseDown (fX, fY, (TMouseButton)(leftButton|(button&~(leftButton|middleButton|rightButton))), this));
278 break;
280 case WM_RBUTTONUP:
281 _MouseButtons[1] = false;
282 server->postEvent (new CEventMouseUp (fX, fY, (TMouseButton)(rightButton|(button&~(leftButton|middleButton|rightButton))), this));
283 break;
284 case WM_MBUTTONUP:
285 _MouseButtons[2] = false;
286 server->postEvent (new CEventMouseUp (fX, fY, (TMouseButton)(middleButton|(button&~(leftButton|middleButton|rightButton))), this));
287 break;
288 case WM_LBUTTONUP:
289 _MouseButtons[0] = false;
290 server->postEvent (new CEventMouseUp (fX, fY, (TMouseButton)(leftButton|(button&~(leftButton|middleButton|rightButton))), this));
291 break;
293 case WM_RBUTTONDBLCLK:
294 server->postEvent (new CEventMouseDblClk (fX, fY, (TMouseButton)(rightButton|(button&~(leftButton|middleButton|rightButton))), this));
295 break;
296 case WM_MBUTTONDBLCLK:
297 server->postEvent (new CEventMouseDblClk (fX, fY, (TMouseButton)(middleButton|(button&~(leftButton|middleButton|rightButton))), this));
298 break;
299 case WM_LBUTTONDBLCLK:
300 server->postEvent (new CEventMouseDblClk (fX, fY, (TMouseButton)(leftButton|(button&~(leftButton|middleButton|rightButton))), this));
301 break;
303 break;
305 break;
307 case WM_DESTROY:
308 server->postEvent (new CEventDestroyWindow (this));
309 break;
310 case WM_CLOSE:
311 server->postEvent (new CEventCloseWindow (this));
312 return true;
313 case WM_DISPLAYCHANGE:
314 server->postEvent (new CEventDisplayChange (LOWORD(lParam), HIWORD(lParam), (uint)wParam, this));
315 break;
316 case WM_MOUSEWHEEL:
317 if (_MouseEventsEnabled)
319 // MSWindows coordinates to NeL window coordinate
320 float fX, fY;
321 RECT client;
322 GetClientRect (hWnd, &client);
323 if (client.right-client.left > 0)
324 fX=(float)LOWORD(lParam)/(float)(client.right-client.left);
325 else
326 fX=0;
327 if (client.bottom-client.top > 0)
328 fY=1.f-(float)HIWORD(lParam)/(float)(client.bottom-client.top);
329 else
330 fY=0;
332 // buttons
333 TMouseButton button=getButtons();
335 server->postEvent (new CEventMouseWheel (fX, fY, button, (short) HIWORD(wParam)>=0, this));
336 break;
338 case WM_IME_SETCONTEXT:
339 case WM_IME_STARTCOMPOSITION:
340 case WM_IME_COMPOSITION:
341 case WM_IME_ENDCOMPOSITION:
342 case WM_IME_NOTIFY:
343 //case WM_INPUTLANGCHANGEREQUEST:
344 case WM_INPUTLANGCHANGE:
345 if ( _IMEEventsEnabled )
347 // wParam = Specifies the character set of the new locale.
348 // lParam = Input locale identifier.
349 server->postEvent( new CEventIME( msg, (uint32)wParam, (uint32)lParam, this ) );
350 return true; // trap message
352 break;
354 return false;
357 //==========================================================
358 void CWinEventEmitter::resetButtonFlagState ()
360 _CtrlButton=( (GetAsyncKeyState(VK_CONTROL)&0x8000) != 0);
361 _ShiftButton=( (GetAsyncKeyState(VK_SHIFT)&0x8000) != 0);
362 _AltButton=( (GetAsyncKeyState(VK_MENU)&0x8000) != 0);
364 _MouseButtons[0]=( (GetAsyncKeyState(VK_LBUTTON)&0x8000) != 0);
365 _MouseButtons[1]=( (GetAsyncKeyState(VK_RBUTTON)&0x8000) != 0);
366 _MouseButtons[2]=( (GetAsyncKeyState(VK_MBUTTON)&0x8000) != 0);
372 //==========================================================
373 TMouseButton CWinEventEmitter::buildFlags() const
375 uint flags = (_CtrlButton ? ctrlButton : 0)
376 | (_ShiftButton ? shiftButton : 0)
377 | (_AltButton ? altButton : 0)
378 | (_MouseButtons[0] ? leftButton : 0)
379 | (_MouseButtons[1] ? rightButton : 0)
380 | (_MouseButtons[2] ? middleButton : 0);
381 return (TMouseButton) flags;
385 } // NLMISC
387 #endif // NL_OS_WINDOWS