LibreOffice Module vcl (master) 1
debugevent.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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 */
9
10#include <comphelper/random.hxx>
11#include <o3tl/string_view.hxx>
12#include <rtl/string.hxx>
13#include <sal/log.hxx>
14#include <vcl/keycodes.hxx>
15#include <vcl/svapp.hxx>
16#include <vcl/wrkwin.hxx>
17#include <vcl/menu.hxx>
18#include <debugevent.hxx>
19#include <window.h>
20#include <salwtype.hxx>
21
23 Timer("debug event injector")
24 , mnEventsLeft( nMaxEvents )
25{
26 SetTimeout( 1000 /* ms */ );
27 Start();
28}
29
30static double getRandom()
31{
33}
34
36{
37 vcl::Window *pParent;
38
39 if (getRandom() < 0.80)
41 return pWindow;
42
43 if (getRandom() > 0.50 ||
45 {
46 // select a top window at random
48 pParent = Application::GetTopWindow( nIdx );
49 }
50 assert (pParent != nullptr);
51
52 std::vector< vcl::Window *> aChildren;
53 pParent->CollectChildren( aChildren );
54
55 return aChildren[ aChildren.size() * getRandom() ];
56}
57
58
59static void CollectMenuItemIds( Menu *pMenu, std::vector< SalMenuEvent > &rIds )
60{
61 sal_uInt16 nItems = pMenu->GetItemCount();
62 for (sal_uInt16 i = 0; i < nItems; i++)
63 {
64 if (pMenu->GetItemType( i ) != MenuItemType::SEPARATOR || getRandom() < 0.01)
65 rIds.emplace_back( pMenu->GetItemId( i ), pMenu );
66 PopupMenu *pPopup = pMenu->GetPopupMenu( i );
67 if (pPopup)
68 CollectMenuItemIds( pPopup, rIds );
69 }
70}
71
73{
75 if (!pFocus)
76 return;
77
78 SystemWindow *pSysWin = pFocus->GetSystemWindow();
79 if (!pSysWin)
80 return;
81
82 MenuBar *pMenuBar = pSysWin->GetMenuBar();
83 if (!pMenuBar)
84 return;
85
86 SalEvent nEvents[] = {
97 };
98
99 std::vector< SalMenuEvent > aIds;
100 CollectMenuItemIds( pMenuBar, aIds );
101
102 SalEvent nEvent = nEvents[ static_cast<int>(getRandom() * SAL_N_ELEMENTS( nEvents )) ];
103 SalMenuEvent aEvent = aIds[ getRandom() * aIds.size() ];
104 bool bHandled = ImplWindowFrameProc( pSysWin, nEvent, &aEvent);
105
106 SAL_INFO( "vcl.debugevent",
107 "Injected menu event " << aEvent.mpMenu
108 << " (" << aEvent.mnId << ") '"
109 << static_cast<Menu *>(aEvent.mpMenu)->GetItemText( aEvent.mnId ) << "' -> "
110 << bHandled );
111}
112
113static void InitKeyEvent( SalKeyEvent &rKeyEvent )
114{
115 if (getRandom() < 0.01)
116 rKeyEvent.mnRepeat = getRandom() * 20;
117 else
118 rKeyEvent.mnRepeat = 0;
119}
120
122{
123 SalKeyEvent aKeyEvent;
124 vcl::Window *pWindow = ChooseWindow();
125
126 InitKeyEvent( aKeyEvent );
127
128 if (getRandom() < 0.10) // Occasionally a truly random event
129 {
130 aKeyEvent.mnCode = getRandom() * KEY_CODE_MASK;
131 aKeyEvent.mnCharCode = getRandom() * 0xffff;
132 }
133 else
134 {
135 static struct {
136 sal_uInt16 nCodeStart, nCodeEnd;
137 char aCharStart;
138 } const nTextCodes[] = {
139 { KEY_0, KEY_9, '0' },
140 { KEY_A, KEY_Z, 'a' }
141 };
142
143 size_t i = getRandom() * SAL_N_ELEMENTS( nTextCodes );
144 int offset = int( getRandom() * ( nTextCodes[i].nCodeEnd - nTextCodes[i].nCodeStart ) );
145 aKeyEvent.mnCode = nTextCodes[i].nCodeStart + offset;
146 aKeyEvent.mnCharCode = nTextCodes[i].aCharStart + offset;
147// fprintf( stderr, "Char '%c' offset %d into record %d base '%c'\n",
148// aKeyEvent.mnCharCode, offset, (int)i, nTextCodes[i].aCharStart );
149 }
150
151 if( getRandom() < 0.05 ) // modifier
152 aKeyEvent.mnCode |= static_cast<sal_uInt16>( getRandom() * KEY_MODIFIERS_MASK ) & KEY_MODIFIERS_MASK;
153
154 bool bHandled = ImplWindowFrameProc( pWindow, SalEvent::KeyInput, &aKeyEvent);
155
156 SAL_INFO( "vcl.debugevent",
157 "Injected key 0x" << std::hex << static_cast<int>(aKeyEvent.mnCode) << std::dec
158 << " -> " << bHandled
159 << " win " << pWindow );
160
161 ImplWindowFrameProc( pWindow, SalEvent::KeyUp, &aKeyEvent );
162}
163
164/*
165 * The more heuristics we have to inform this the better,
166 * key-bindings, menu entries, allowable entry types etc.
167 */
169{
170// fprintf( stderr, "%6d - ", (int)mnEventsLeft );
171
172 double nRand = getRandom();
173 if (nRand < 0.30)
174 {
175 int nEvents = getRandom() * 10;
176 for (int i = 0; i < nEvents; i++)
178 }
179 else if (nRand < 0.60)
181 else if (nRand < 0.95)
183}
184
186{
187 vcl::Window *pWindow = ChooseWindow();
188
189 static struct {
190 double mnProb;
191 sal_uInt16 mnKey;
192 } const nWeights[] = {
193 // edit / escape etc. - 50%
194 { 0.20, KEY_SPACE },
195 { 0.10, KEY_TAB },
196 { 0.07, KEY_RETURN },
197 { 0.05, KEY_DELETE },
198 { 0.05, KEY_BACKSPACE },
199
200 // navigate - 45%
201 { 0.15, KEY_LEFT },
202 { 0.10, KEY_RIGHT },
203 { 0.05, KEY_UP },
204 { 0.05, KEY_DOWN },
205 { 0.05, KEY_PAGEUP },
206 { 0.05, KEY_PAGEDOWN },
207
208 // other
209 { 0.01, KEY_INSERT },
210 { 0.02, KEY_HOME },
211 { 0.02, KEY_END },
212 };
213
214 double d = 0.0, nRand = getRandom();
215 sal_uInt16 nKey = KEY_SPACE;
216 for (auto & rWeight : nWeights)
217 {
218 d += rWeight.mnProb;
219 assert (d < 1.01);
220 if ( nRand < d )
221 {
222 nKey = rWeight.mnKey;
223 break;
224 }
225 }
226
227 SalKeyEvent aKeyEvent;
228 InitKeyEvent( aKeyEvent );
229 aKeyEvent.mnCode = nKey;
230
231 if (getRandom() < 0.15) // modifier
232 aKeyEvent.mnCode |= static_cast<sal_uInt16>(getRandom() * KEY_MODIFIERS_MASK) & KEY_MODIFIERS_MASK;
233
234 aKeyEvent.mnCharCode = 0x0; // hopefully unused.
235
236 bool bHandled = ImplWindowFrameProc( pWindow, SalEvent::KeyInput, &aKeyEvent );
237
238 SAL_INFO( "vcl.debugevent",
239 "Injected edit / move key 0x" << std::hex << static_cast<int>(aKeyEvent.mnCode) << std::dec
240 << " -> " << bHandled
241 << " win " << pWindow );
242 ImplWindowFrameProc( pWindow, SalEvent::KeyUp, &aKeyEvent );
243}
244
246{
247 InjectEvent();
248 mnEventsLeft--;
249 if (mnEventsLeft > 0)
250 {
251 SetTimeout( 1 );
252 Start();
253 }
254 else
256}
257
259{
260 sal_uInt32 nEvents;
261 const char *pEvents = getenv("VCL_EVENT_INJECTION");
262 if (!pEvents)
263 return nullptr;
264 nEvents = o3tl::toUInt32( pEvents );
265 if (nEvents > 0)
266 return new DebugEventInjector( nEvents );
267 else
268 return nullptr;
269}
270
271/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
AnyEventRef aEvent
double d
static tools::Long GetTopWindowCount()
Return the number of top-level windows being used by the application.
Definition: svapp.cxx:1195
static vcl::Window * GetTopWindow(tools::Long nIndex)
Get the nth top window.
Definition: svapp.cxx:1209
static void Quit()
Quit the program.
Definition: svapp.cxx:568
static vcl::Window * GetFocusWindow()
Get the currently focused window.
Definition: svapp.cxx:1161
static vcl::Window * GetActiveTopWindow()
Get the "active" top window.
Definition: svapp.cxx:1228
DebugEventInjector(sal_uInt32 nMaxEvents)
Definition: debugevent.cxx:22
static void InjectTextEvent()
Definition: debugevent.cxx:121
sal_uInt32 mnEventsLeft
Definition: debugevent.hxx:20
virtual void Invoke() override
Calls the maInvokeHandler with the parameter this.
Definition: debugevent.cxx:245
static void InjectMenuEvent()
Definition: debugevent.cxx:72
static void InjectKeyNavEdit()
Definition: debugevent.cxx:185
static vcl::Window * ChooseWindow()
Definition: debugevent.cxx:35
static void InjectEvent()
Definition: debugevent.cxx:168
static DebugEventInjector * getCreate()
Definition: debugevent.cxx:258
Definition: menu.hxx:116
OUString GetItemText(sal_uInt16 nItemId) const
Definition: menu.cxx:992
MenuItemType GetItemType(sal_uInt16 nPos) const
Definition: menu.cxx:655
sal_uInt16 GetItemId(sal_uInt16 nPos) const
Definition: menu.cxx:623
PopupMenu * GetPopupMenu(sal_uInt16 nItemId) const
Definition: menu.cxx:750
sal_uInt16 GetItemCount() const
Definition: menu.cxx:577
MenuBar * GetMenuBar() const
Definition: syswin.hxx:183
Definition: timer.hxx:27
void SetTimeout(sal_uInt64 nTimeoutMs)
Definition: timer.cxx:90
virtual void Start(bool bStartTimer=true) override
Schedules the task for execution.
Definition: timer.cxx:83
SAL_DLLPRIVATE void CollectChildren(::std::vector< vcl::Window * > &rAllChildren)
Add all children to rAllChildren recursively.
Definition: window.cxx:2165
SystemWindow * GetSystemWindow() const
Definition: stacking.cxx:806
static void CollectMenuItemIds(Menu *pMenu, std::vector< SalMenuEvent > &rIds)
Definition: debugevent.cxx:59
static void InitKeyEvent(SalKeyEvent &rKeyEvent)
Definition: debugevent.cxx:113
static double getRandom()
Definition: debugevent.cxx:30
constexpr sal_uInt16 KEY_RETURN
Definition: keycodes.hxx:119
constexpr sal_uInt16 KEY_0
Definition: keycodes.hxx:45
constexpr sal_uInt16 KEY_HOME
Definition: keycodes.hxx:114
constexpr sal_uInt16 KEY_LEFT
Definition: keycodes.hxx:112
constexpr sal_uInt16 KEY_PAGEDOWN
Definition: keycodes.hxx:117
constexpr sal_uInt16 KEY_TAB
Definition: keycodes.hxx:121
constexpr sal_uInt16 KEY_UP
Definition: keycodes.hxx:111
constexpr sal_uInt16 KEY_CODE_MASK
Definition: keycodes.hxx:27
constexpr sal_uInt16 KEY_MODIFIERS_MASK
Definition: keycodes.hxx:34
constexpr sal_uInt16 KEY_9
Definition: keycodes.hxx:54
constexpr sal_uInt16 KEY_Z
Definition: keycodes.hxx:81
constexpr sal_uInt16 KEY_A
Definition: keycodes.hxx:56
constexpr sal_uInt16 KEY_RIGHT
Definition: keycodes.hxx:113
constexpr sal_uInt16 KEY_DELETE
Definition: keycodes.hxx:125
constexpr sal_uInt16 KEY_DOWN
Definition: keycodes.hxx:110
constexpr sal_uInt16 KEY_SPACE
Definition: keycodes.hxx:123
constexpr sal_uInt16 KEY_PAGEUP
Definition: keycodes.hxx:116
constexpr sal_uInt16 KEY_INSERT
Definition: keycodes.hxx:124
constexpr sal_uInt16 KEY_BACKSPACE
Definition: keycodes.hxx:122
constexpr sal_uInt16 KEY_END
Definition: keycodes.hxx:115
#define SAL_INFO(area, stream)
#define SAL_N_ELEMENTS(arr)
double uniform_real_distribution(double a=0.0, double b=1.0)
int i
sal_uInt32 toUInt32(std::u16string_view str, sal_Int16 radix=10)
long Long
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
SalEvent
Definition: salwtype.hxx:46
@ MenuDeactivate
@ MenuButtonCommand
sal_uInt16 mnRepeat
Definition: salwtype.hxx:127
sal_uInt16 mnCode
Definition: salwtype.hxx:125
sal_uInt16 mnCharCode
Definition: salwtype.hxx:126
bool ImplWindowFrameProc(vcl::Window *_pWindow, SalEvent nEvent, const void *pEvent)
Definition: winproc.cxx:2653