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