nss: upgrade to release 3.73
[LibreOffice.git] / vcl / source / window / debugevent.cxx
blob94238967164b39bc1a6bbc93f9efc68e3ff12e88
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/string.hxx>
12 #include <sal/log.hxx>
13 #include <vcl/keycodes.hxx>
14 #include <vcl/svapp.hxx>
15 #include <vcl/wrkwin.hxx>
16 #include <vcl/menu.hxx>
17 #include <debugevent.hxx>
18 #include <window.h>
19 #include <salwtype.hxx>
21 DebugEventInjector::DebugEventInjector( sal_uInt32 nMaxEvents) :
22 Timer("debug event injector")
23 , mnEventsLeft( nMaxEvents )
25 SetTimeout( 1000 /* ms */ );
26 Start();
29 static double getRandom()
31 return comphelper::rng::uniform_real_distribution();
34 vcl::Window *DebugEventInjector::ChooseWindow()
36 vcl::Window *pParent;
38 if (getRandom() < 0.80)
39 if (vcl::Window * pWindow = Application::GetFocusWindow())
40 return pWindow;
42 if (getRandom() > 0.50 ||
43 !(pParent = Application::GetActiveTopWindow()))
45 // select a top window at random
46 tools::Long nIdx = Application::GetTopWindowCount() * getRandom();
47 pParent = Application::GetTopWindow( nIdx );
49 assert (pParent != nullptr);
51 std::vector< vcl::Window *> aChildren;
52 pParent->CollectChildren( aChildren );
54 return aChildren[ aChildren.size() * getRandom() ];
58 static void CollectMenuItemIds( Menu *pMenu, std::vector< SalMenuEvent > &rIds )
60 sal_uInt16 nItems = pMenu->GetItemCount();
61 for (sal_uInt16 i = 0; i < nItems; i++)
63 if (pMenu->GetItemType( i ) != MenuItemType::SEPARATOR || getRandom() < 0.01)
64 rIds.emplace_back( pMenu->GetItemId( i ), pMenu );
65 PopupMenu *pPopup = pMenu->GetPopupMenu( i );
66 if (pPopup)
67 CollectMenuItemIds( pPopup, rIds );
71 void DebugEventInjector::InjectMenuEvent()
73 vcl::Window *pFocus = Application::GetFocusWindow();
74 if (!pFocus)
75 return;
77 SystemWindow *pSysWin = pFocus->GetSystemWindow();
78 if (!pSysWin)
79 return;
81 MenuBar *pMenuBar = pSysWin->GetMenuBar();
82 if (!pMenuBar)
83 return;
85 SalEvent nEvents[] = {
86 SalEvent::MenuCommand,
87 SalEvent::MenuCommand,
88 SalEvent::MenuActivate,
89 SalEvent::MenuDeactivate,
90 SalEvent::MenuHighlight,
91 SalEvent::MenuCommand,
92 SalEvent::MenuCommand,
93 SalEvent::MenuCommand,
94 SalEvent::MenuButtonCommand,
95 SalEvent::MenuButtonCommand,
98 std::vector< SalMenuEvent > aIds;
99 CollectMenuItemIds( pMenuBar, aIds );
101 SalEvent nEvent = nEvents[ static_cast<int>(getRandom() * SAL_N_ELEMENTS( nEvents )) ];
102 SalMenuEvent aEvent = aIds[ getRandom() * aIds.size() ];
103 bool bHandled = ImplWindowFrameProc( pSysWin, nEvent, &aEvent);
105 SAL_INFO( "vcl.debugevent",
106 "Injected menu event " << aEvent.mpMenu
107 << " (" << aEvent.mnId << ") '"
108 << static_cast<Menu *>(aEvent.mpMenu)->GetItemText( aEvent.mnId ) << "' -> "
109 << bHandled );
112 static void InitKeyEvent( SalKeyEvent &rKeyEvent )
114 if (getRandom() < 0.01)
115 rKeyEvent.mnRepeat = getRandom() * 20;
116 else
117 rKeyEvent.mnRepeat = 0;
120 void DebugEventInjector::InjectTextEvent()
122 SalKeyEvent aKeyEvent;
123 vcl::Window *pWindow = ChooseWindow();
125 InitKeyEvent( aKeyEvent );
127 if (getRandom() < 0.10) // Occasionally a truly random event
129 aKeyEvent.mnCode = getRandom() * KEY_CODE_MASK;
130 aKeyEvent.mnCharCode = getRandom() * 0xffff;
132 else
134 static struct {
135 sal_uInt16 nCodeStart, nCodeEnd;
136 char aCharStart;
137 } const nTextCodes[] = {
138 { KEY_0, KEY_9, '0' },
139 { KEY_A, KEY_Z, 'a' }
142 size_t i = getRandom() * SAL_N_ELEMENTS( nTextCodes );
143 int offset = int( getRandom() * ( nTextCodes[i].nCodeEnd - nTextCodes[i].nCodeStart ) );
144 aKeyEvent.mnCode = nTextCodes[i].nCodeStart + offset;
145 aKeyEvent.mnCharCode = nTextCodes[i].aCharStart + offset;
146 // fprintf( stderr, "Char '%c' offset %d into record %d base '%c'\n",
147 // aKeyEvent.mnCharCode, offset, (int)i, nTextCodes[i].aCharStart );
150 if( getRandom() < 0.05 ) // modifier
151 aKeyEvent.mnCode |= static_cast<sal_uInt16>( getRandom() * KEY_MODIFIERS_MASK ) & KEY_MODIFIERS_MASK;
153 bool bHandled = ImplWindowFrameProc( pWindow, SalEvent::KeyInput, &aKeyEvent);
155 SAL_INFO( "vcl.debugevent",
156 "Injected key 0x" << std::hex << static_cast<int>(aKeyEvent.mnCode) << std::dec
157 << " -> " << bHandled
158 << " win " << pWindow );
160 ImplWindowFrameProc( pWindow, SalEvent::KeyUp, &aKeyEvent );
164 * The more heuristics we have to inform this the better,
165 * key-bindings, menu entries, allowable entry types etc.
167 void DebugEventInjector::InjectEvent()
169 // fprintf( stderr, "%6d - ", (int)mnEventsLeft );
171 double nRand = getRandom();
172 if (nRand < 0.30)
174 int nEvents = getRandom() * 10;
175 for (int i = 0; i < nEvents; i++)
176 InjectTextEvent();
178 else if (nRand < 0.60)
179 InjectKeyNavEdit();
180 else if (nRand < 0.95)
181 InjectMenuEvent();
184 void DebugEventInjector::InjectKeyNavEdit()
186 vcl::Window *pWindow = ChooseWindow();
188 static struct {
189 double mnProb;
190 sal_uInt16 mnKey;
191 } const nWeights[] = {
192 // edit / escape etc. - 50%
193 { 0.20, KEY_SPACE },
194 { 0.10, KEY_TAB },
195 { 0.07, KEY_RETURN },
196 { 0.05, KEY_DELETE },
197 { 0.05, KEY_BACKSPACE },
199 // navigate - 45%
200 { 0.15, KEY_LEFT },
201 { 0.10, KEY_RIGHT },
202 { 0.05, KEY_UP },
203 { 0.05, KEY_DOWN },
204 { 0.05, KEY_PAGEUP },
205 { 0.05, KEY_PAGEDOWN },
207 // other
208 { 0.01, KEY_INSERT },
209 { 0.02, KEY_HOME },
210 { 0.02, KEY_END },
213 double d = 0.0, nRand = getRandom();
214 sal_uInt16 nKey = KEY_SPACE;
215 for (auto & rWeight : nWeights)
217 d += rWeight.mnProb;
218 assert (d < 1.01);
219 if ( nRand < d )
221 nKey = rWeight.mnKey;
222 break;
226 SalKeyEvent aKeyEvent;
227 InitKeyEvent( aKeyEvent );
228 aKeyEvent.mnCode = nKey;
230 if (getRandom() < 0.15) // modifier
231 aKeyEvent.mnCode |= static_cast<sal_uInt16>(getRandom() * KEY_MODIFIERS_MASK) & KEY_MODIFIERS_MASK;
233 aKeyEvent.mnCharCode = 0x0; // hopefully unused.
235 bool bHandled = ImplWindowFrameProc( pWindow, SalEvent::KeyInput, &aKeyEvent );
237 SAL_INFO( "vcl.debugevent",
238 "Injected edit / move key 0x" << std::hex << static_cast<int>(aKeyEvent.mnCode) << std::dec
239 << " -> " << bHandled
240 << " win " << pWindow );
241 ImplWindowFrameProc( pWindow, SalEvent::KeyUp, &aKeyEvent );
244 void DebugEventInjector::Invoke()
246 InjectEvent();
247 mnEventsLeft--;
248 if (mnEventsLeft > 0)
250 SetTimeout( 1 );
251 Start();
253 else
254 Application::Quit();
257 DebugEventInjector *DebugEventInjector::getCreate()
259 sal_uInt32 nEvents;
260 const char *pEvents = getenv("VCL_EVENT_INJECTION");
261 if (!pEvents)
262 return nullptr;
263 nEvents = OString( pEvents ).toUInt32();
264 if (nEvents > 0)
265 return new DebugEventInjector( nEvents );
266 else
267 return nullptr;
270 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */