1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
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>
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 */ );
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()))
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
);
71 CollectMenuItemIds( pPopup
, rIds
);
75 void DebugEventInjector::InjectMenuEvent()
77 vcl::Window
*pFocus
= Application::GetFocusWindow();
81 SystemWindow
*pSysWin
= pFocus
->GetSystemWindow();
85 MenuBar
*pMenuBar
= pSysWin
->GetMenuBar();
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
) << "' -> "
116 static void InitKeyEvent( SalKeyEvent
&rKeyEvent
)
118 double nRand
= getRandom();
120 rKeyEvent
.mnTime
= getRandom() * SAL_MAX_UINT64
;
122 rKeyEvent
.mnTime
= tools::Time::GetSystemTicks();
124 if (getRandom() < 0.01)
125 rKeyEvent
.mnRepeat
= getRandom() * 20;
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;
145 sal_uInt16 nCodeStart
, nCodeEnd
;
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();
184 int nEvents
= getRandom() * 10;
185 for (int i
= 0; i
< nEvents
; i
++)
188 else if (nRand
< 0.60)
190 else if (nRand
< 0.95)
194 void DebugEventInjector::InjectKeyNavEdit()
196 vcl::Window
*pWindow
= ChooseWindow();
202 // edit / escape etc. - 50%
205 { 0.07, KEY_RETURN
},
206 { 0.05, KEY_DELETE
},
207 { 0.05, KEY_BACKSPACE
},
214 { 0.05, KEY_PAGEUP
},
215 { 0.05, KEY_PAGEDOWN
},
218 { 0.01, KEY_INSERT
},
223 double d
= 0.0, nRand
= getRandom();
224 sal_uInt16 nKey
= KEY_SPACE
;
225 for (auto & rWeight
: nWeights
)
231 nKey
= rWeight
.mnKey
;
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()
258 if (mnEventsLeft
> 0)
267 DebugEventInjector
*DebugEventInjector::getCreate()
270 const char *pEvents
= getenv("VCL_EVENT_INJECTION");
273 nEvents
= OString( pEvents
).toUInt32();
275 return new DebugEventInjector( nEvents
);
280 #endif // OSL_DEBUG_LEVEL > 0
282 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */