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 
22 DebugEventInjector::DebugEventInjector( sal_uInt32 nMaxEvents) :
23  Timer("debug event injector")
24  , mnEventsLeft( nMaxEvents )
25 {
26  SetTimeout( 1000 /* ms */ );
27  Start();
28 }
29 
30 static double getRandom()
31 {
33 }
34 
36 {
37  vcl::Window *pParent;
38 
39  if (getRandom() < 0.80)
40  if (vcl::Window * pWindow = Application::GetFocusWindow())
41  return pWindow;
42 
43  if (getRandom() > 0.50 ||
44  !(pParent = Application::GetActiveTopWindow()))
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 
59 static 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 
113 static 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++)
177  InjectTextEvent();
178  }
179  else if (nRand < 0.60)
181  else if (nRand < 0.95)
182  InjectMenuEvent();
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: */
static vcl::Window * GetTopWindow(tools::Long nIndex)
Get the nth top window.
Definition: svapp.cxx:1194
constexpr sal_uInt16 KEY_CODE_MASK
Definition: keycodes.hxx:27
PopupMenu * GetPopupMenu(sal_uInt16 nItemId) const
Definition: menu.cxx:750
SystemWindow * GetSystemWindow() const
Definition: stacking.cxx:806
static tools::Long GetTopWindowCount()
Return the number of top-level windows being used by the application.
Definition: svapp.cxx:1180
long Long
bool ImplWindowFrameProc(vcl::Window *_pWindow, SalEvent nEvent, const void *pEvent)
Definition: winproc.cxx:2595
constexpr sal_uInt16 KEY_A
Definition: keycodes.hxx:56
constexpr sal_uInt16 KEY_0
Definition: keycodes.hxx:45
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
static void CollectMenuItemIds(Menu *pMenu, std::vector< SalMenuEvent > &rIds)
Definition: debugevent.cxx:59
virtual void Invoke() override
Calls the maInvokeHandler with the parameter this.
Definition: debugevent.cxx:245
static void InjectKeyNavEdit()
Definition: debugevent.cxx:185
constexpr sal_uInt16 KEY_SPACE
Definition: keycodes.hxx:123
constexpr sal_uInt16 KEY_UP
Definition: keycodes.hxx:111
sal_uInt16 mnCode
Definition: salwtype.hxx:118
constexpr sal_uInt16 KEY_END
Definition: keycodes.hxx:115
constexpr sal_uInt16 KEY_9
Definition: keycodes.hxx:54
sal_uInt32 mnEventsLeft
Definition: debugevent.hxx:20
MenuItemType GetItemType(sal_uInt16 nPos) const
Definition: menu.cxx:655
constexpr sal_uInt16 KEY_PAGEUP
Definition: keycodes.hxx:116
DebugEventInjector(sal_uInt32 nMaxEvents)
Definition: debugevent.cxx:22
SAL_DLLPRIVATE void CollectChildren(::std::vector< vcl::Window * > &rAllChildren)
Add all children to rAllChildren recursively.
Definition: window.cxx:2163
static void Quit()
Quit the program.
Definition: svapp.cxx:567
static void InitKeyEvent(SalKeyEvent &rKeyEvent)
Definition: debugevent.cxx:113
double d
#define SAL_N_ELEMENTS(arr)
constexpr sal_uInt16 KEY_MODIFIERS_MASK
Definition: keycodes.hxx:34
static void InjectMenuEvent()
Definition: debugevent.cxx:72
constexpr sal_uInt16 KEY_DOWN
Definition: keycodes.hxx:110
int i
constexpr sal_uInt16 KEY_HOME
Definition: keycodes.hxx:114
sal_uInt16 GetItemId(sal_uInt16 nPos) const
Definition: menu.cxx:623
virtual void Start(bool bStartTimer=true) override
Schedules the task for execution.
Definition: timer.cxx:83
constexpr sal_uInt16 KEY_PAGEDOWN
Definition: keycodes.hxx:117
sal_uInt16 mnCharCode
Definition: salwtype.hxx:119
void SetTimeout(sal_uInt64 nTimeoutMs)
Definition: timer.cxx:90
double uniform_real_distribution(double a=0.0, double b=1.0)
static vcl::Window * GetActiveTopWindow()
Get the "active" top window.
Definition: svapp.cxx:1213
constexpr sal_uInt16 KEY_RETURN
Definition: keycodes.hxx:119
SalEvent
Definition: salwtype.hxx:41
constexpr sal_uInt16 KEY_RIGHT
Definition: keycodes.hxx:113
static double getRandom()
Definition: debugevent.cxx:30
static vcl::Window * GetFocusWindow()
Get the currently focused window.
Definition: svapp.cxx:1159
Definition: menu.hxx:115
MenuBar * GetMenuBar() const
Definition: syswin.hxx:183
#define SAL_INFO(area, stream)
sal_uInt16 GetItemCount() const
Definition: menu.cxx:577
sal_uInt32 toUInt32(std::u16string_view str, sal_Int16 radix=10)
static void InjectTextEvent()
Definition: debugevent.cxx:121
constexpr sal_uInt16 KEY_BACKSPACE
Definition: keycodes.hxx:122
static void InjectEvent()
Definition: debugevent.cxx:168
sal_uInt16 mnRepeat
Definition: salwtype.hxx:120
static vcl::Window * ChooseWindow()
Definition: debugevent.cxx:35
constexpr sal_uInt16 KEY_Z
Definition: keycodes.hxx:81
Definition: timer.hxx:26
constexpr sal_uInt16 KEY_DELETE
Definition: keycodes.hxx:125
constexpr sal_uInt16 KEY_LEFT
Definition: keycodes.hxx:112
static DebugEventInjector * getCreate()
Definition: debugevent.cxx:258
constexpr sal_uInt16 KEY_INSERT
Definition: keycodes.hxx:124
AnyEventRef aEvent
constexpr sal_uInt16 KEY_TAB
Definition: keycodes.hxx:121