If you’re going to try to simulate user actions, make sure the user can do them


Many people like to simulate user actions programmatically. I'm not going to comment here on whether that's a good idea to begin with; what I want to point out is that if you're going to do it, you have to make sure you're simulating things the user can actually do.

For example, if you want to act as if the user clicked the "close" button in the corner, you have to make sure that the window is visible and enabled and that the window even has a "close" button to begin with! Failing to observe these rules means that the application you are manipulating is going to experience "impossible" conditions. The window may very well have been disabled in order to avoid the problem of the unsupported stack frame. Programmatically closing the window means that you've reintroduced the bug that the application programmer was trying to avoid.

Similarly, if you want to simulate menu clicks, you need to check whether the menu item is enabled because a user can't select a disabled menu item. Since most programs do not synchronize menu item states until the menu is opened (since the only way a user can invoke a menu item is to open the enclosing menu first), you need to open the menu before you check whether the item is enabled.

There are even more subtle conditions. For example, you might be dealing with a program that stops updating its status when the window is not visible, either because it is covered by another window or because the user has disconnected the session or locked the workstation. Under those conditions, the user can't interact with the program, and simulating such activity may result in the program behaving strangely because you're doing something "impossible".

In the referenced article, the program wanted to set foreground activation to a particular window, but it didn't check whether the window was enabled or even visible! (And even if it were enabled and visible, it might be a WS_EX_NOACTIVATE window.)

My goal here is not to come up with a comprehensive list of things to check before simulating every type of action you might want. That's something you need to figure out on your own: Look at what you're trying to simulate and think through what the window manager requires for that action to be accessible to the user.

Comments (5)
  1. PatriotB says:

    Reminds me of the SHRestricted function (http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/shrestricted.asp) and the RESTRICTIONS enumeration (http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/enums/restrictions.asp): a way to determine if policy says the user should be able to do something or not.

  2. Anonymous says:

    Of course, anyone knows that the way "real" programmers simulate user actions is to actually move the mouse around and do clicks[1].

    References:

    [1] Last para of http://blogs.msdn.com/oldnewthing/archive/2005/08/16/452141.aspx

  3. Anonymous says:

    Don’t quite understand this one, if you truly simulate user actions you cannot, for example, make an invisible window visible, or close a window with no [x] by clicking where it would have been (if it existed).

    If you wished to truely simulate user actions then you would have to ‘move the mouse around and do clicks’ (however awkward/strange this is).

    If you were writing automated testing software, for example, is this not the best approach? Remember Mouse Recorder as well as the more professional tools.

    Another example is where you wish to automate some actions where you have no/limited access to the applications involved. This, I believe, was the motivation behind ScriptIt.

    I am not suggesting building production software (or driver installations!) this way but wish to make the point that if you truly simulate user actions (but simulating actual UI input) then the ‘impossible’ remains so.

    The SetForegroundWindow example is not simulating user actions (maybe the result of user action).

    Perhaps this post is about getting the same results as possible ( – there is the point) user actions rather than simulating them? or is the distinction too fine?

  4. Anonymous says:

    Since there’s no authentication on window messages, it’s a good idea to perform sanity checks wherever neccessary anyway.

  5. Anonymous says:

    Even finding the proper window might be a challange. The only way is the class+text.

    And if something is localized and has a very common class (a dialog), then the test becomes language-speciffic.

    Even if the text is external, in some file, one would have to keep the file in sync with the latest translation. Quite a mess.

Comments are closed.