build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / window / debugevent.cxx
blob255491f2f2948700f39bf675c7896872528b2c5b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <comphelper/random.hxx>
11 #include <rtl/math.hxx>
12 #include <rtl/string.hxx>
13 #include <tools/time.hxx>
14 #include <vcl/keycodes.hxx>
15 #include <vcl/svapp.hxx>
16 #include <vcl/debugevent.hxx>
17 #include <vcl/wrkwin.hxx>
18 #include <vcl/menu.hxx>
19 #include "window.h"
20 #include "salwtype.hxx"
22 #if OSL_DEBUG_LEVEL > 0
24 DebugEventInjector::DebugEventInjector( sal_uInt32 nMaxEvents) :
25 Timer("debug event injector")
26 , mnEventsLeft( nMaxEvents )
28 SetTimeout( 1000 /* ms */ );
29 Start();
32 static double getRandom()
34 return comphelper::rng::uniform_real_distribution();
37 vcl::Window *DebugEventInjector::ChooseWindow()
39 vcl::Window *pWindow, *pParent;
41 if (getRandom() < 0.80 &&
42 (pWindow = Application::GetFocusWindow()))
43 return pWindow;
45 if (getRandom() > 0.50 ||
46 !(pParent = Application::GetActiveTopWindow()))
48 // select a top window at random
49 long nIdx = Application::GetTopWindowCount() * getRandom();
50 if (!(pParent = Application::GetTopWindow( nIdx )))
51 pParent = static_cast<vcl::Window *>(Application::GetAppWindow());
53 assert (pParent != nullptr);
55 std::vector< vcl::Window *> aChildren;
56 pParent->CollectChildren( aChildren );
58 return aChildren[ aChildren.size() * getRandom() ];
62 static void CollectMenuItemIds( Menu *pMenu, std::vector< SalMenuEvent > &rIds )
64 sal_uInt16 nItems = pMenu->GetItemCount();
65 for (sal_uInt16 i = 0; i < nItems; i++)
67 if (pMenu->GetItemType( i ) != MenuItemType::SEPARATOR || getRandom() < 0.01)
68 rIds.push_back( SalMenuEvent( pMenu->GetItemId( i ), pMenu ) );
69 PopupMenu *pPopup = pMenu->GetPopupMenu( i );
70 if (pPopup)
71 CollectMenuItemIds( pPopup, rIds );
75 void DebugEventInjector::InjectMenuEvent()
77 vcl::Window *pFocus = Application::GetFocusWindow();
78 if (!pFocus)
79 return;
81 SystemWindow *pSysWin = pFocus->GetSystemWindow();
82 if (!pSysWin)
83 return;
85 MenuBar *pMenuBar = pSysWin->GetMenuBar();
86 if (!pMenuBar)
87 return;
89 SalEvent nEvents[] = {
90 SalEvent::MenuCommand,
91 SalEvent::MenuCommand,
92 SalEvent::MenuActivate,
93 SalEvent::MenuDeactivate,
94 SalEvent::MenuHighlight,
95 SalEvent::MenuCommand,
96 SalEvent::MenuCommand,
97 SalEvent::MenuCommand,
98 SalEvent::MenuButtonCommand,
99 SalEvent::MenuButtonCommand,
102 std::vector< SalMenuEvent > aIds;
103 CollectMenuItemIds( pMenuBar, aIds );
105 SalEvent nEvent = nEvents[ (int)(getRandom() * SAL_N_ELEMENTS( nEvents )) ];
106 SalMenuEvent aEvent = aIds[ getRandom() * aIds.size() ];
107 bool bHandled = ImplWindowFrameProc( pSysWin, nEvent, &aEvent);
109 SAL_INFO( "vcl.debugevent",
110 "Injected menu event " << aEvent.mpMenu
111 << " (" << aEvent.mnId << ") '"
112 << static_cast<Menu *>(aEvent.mpMenu)->GetItemText( aEvent.mnId ) << "' -> "
113 << bHandled );
116 static void InitKeyEvent( SalKeyEvent &rKeyEvent )
118 double nRand = getRandom();
119 if (nRand < 0.001)
120 rKeyEvent.mnTime = getRandom() * SAL_MAX_UINT64;
121 else
122 rKeyEvent.mnTime = tools::Time::GetSystemTicks();
124 if (getRandom() < 0.01)
125 rKeyEvent.mnRepeat = getRandom() * 20;
126 else
127 rKeyEvent.mnRepeat = 0;
130 void DebugEventInjector::InjectTextEvent()
132 SalKeyEvent aKeyEvent;
133 vcl::Window *pWindow = ChooseWindow();
135 InitKeyEvent( aKeyEvent );
137 if (getRandom() < 0.10) // Occasionally a truly random event
139 aKeyEvent.mnCode = getRandom() * KEY_CODE_MASK;
140 aKeyEvent.mnCharCode = getRandom() * 0xffff;
142 else
144 struct {
145 sal_uInt16 nCodeStart, nCodeEnd;
146 char aCharStart;
147 } nTextCodes[] = {
148 { KEY_0, KEY_9, '0' },
149 { KEY_A, KEY_Z, 'a' }
152 size_t i = getRandom() * SAL_N_ELEMENTS( nTextCodes );
153 int offset = int( getRandom() * ( nTextCodes[i].nCodeEnd - nTextCodes[i].nCodeStart ) );
154 aKeyEvent.mnCode = nTextCodes[i].nCodeStart + offset;
155 aKeyEvent.mnCharCode = nTextCodes[i].aCharStart + offset;
156 // fprintf( stderr, "Char '%c' offset %d into record %d base '%c'\n",
157 // aKeyEvent.mnCharCode, offset, (int)i, nTextCodes[i].aCharStart );
160 if( getRandom() < 0.05 ) // modifier
161 aKeyEvent.mnCode |= (sal_uInt16)( getRandom() * KEY_MODIFIERS_MASK ) & KEY_MODIFIERS_MASK;
163 bool bHandled = ImplWindowFrameProc( pWindow, SalEvent::KeyInput, &aKeyEvent);
165 SAL_INFO( "vcl.debugevent",
166 "Injected key 0x" << std::hex << (int) aKeyEvent.mnCode << std::dec
167 << " -> " << bHandled
168 << " win " << pWindow );
170 ImplWindowFrameProc( pWindow, SalEvent::KeyUp, &aKeyEvent );
174 * The more heuristics we have to inform this the better,
175 * key-bindings, menu entries, allowable entry types etc.
177 void DebugEventInjector::InjectEvent()
179 // fprintf( stderr, "%6d - ", (int)mnEventsLeft );
181 double nRand = getRandom();
182 if (nRand < 0.30)
184 int nEvents = getRandom() * 10;
185 for (int i = 0; i < nEvents; i++)
186 InjectTextEvent();
188 else if (nRand < 0.60)
189 InjectKeyNavEdit();
190 else if (nRand < 0.95)
191 InjectMenuEvent();
194 void DebugEventInjector::InjectKeyNavEdit()
196 vcl::Window *pWindow = ChooseWindow();
198 struct {
199 double mnProb;
200 sal_uInt16 mnKey;
201 } nWeights[] = {
202 // edit / escape etc. - 50%
203 { 0.20, KEY_SPACE },
204 { 0.10, KEY_TAB },
205 { 0.07, KEY_RETURN },
206 { 0.05, KEY_DELETE },
207 { 0.05, KEY_BACKSPACE },
209 // navigate - 45%
210 { 0.15, KEY_LEFT },
211 { 0.10, KEY_RIGHT },
212 { 0.05, KEY_UP },
213 { 0.05, KEY_DOWN },
214 { 0.05, KEY_PAGEUP },
215 { 0.05, KEY_PAGEDOWN },
217 // other
218 { 0.01, KEY_INSERT },
219 { 0.02, KEY_HOME },
220 { 0.02, KEY_END },
223 double d = 0.0, nRand = getRandom();
224 sal_uInt16 nKey = KEY_SPACE;
225 for (auto & rWeight : nWeights)
227 d += rWeight.mnProb;
228 assert (d < 1.01);
229 if ( nRand < d )
231 nKey = rWeight.mnKey;
232 break;
236 SalKeyEvent aKeyEvent;
237 InitKeyEvent( aKeyEvent );
238 aKeyEvent.mnCode = nKey;
240 if (getRandom() < 0.15) // modifier
241 aKeyEvent.mnCode |= (sal_uInt16)(getRandom() * KEY_MODIFIERS_MASK) & KEY_MODIFIERS_MASK;
243 aKeyEvent.mnCharCode = 0x0; // hopefully unused.
245 bool bHandled = ImplWindowFrameProc( pWindow, SalEvent::KeyInput, &aKeyEvent );
247 SAL_INFO( "vcl.debugevent",
248 "Injected edit / move key 0x" << std::hex << (int) aKeyEvent.mnCode << std::dec
249 << " -> " << bHandled
250 << " win " << pWindow );
251 ImplWindowFrameProc( pWindow, SalEvent::KeyUp, &aKeyEvent );
254 void DebugEventInjector::Invoke()
256 InjectEvent();
257 mnEventsLeft--;
258 if (mnEventsLeft > 0)
260 SetTimeout( 1 );
261 Start();
263 else
264 Application::Quit();
267 DebugEventInjector *DebugEventInjector::getCreate()
269 sal_uInt32 nEvents;
270 const char *pEvents = getenv("VCL_EVENT_INJECTION");
271 if (!pEvents)
272 return nullptr;
273 nEvents = OString( pEvents ).toUInt32();
274 if (nEvents > 0)
275 return new DebugEventInjector( nEvents );
276 else
277 return nullptr;
280 #endif // OSL_DEBUG_LEVEL > 0
282 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */