I prefer to leverage game states as a means to orchestrate chunks of behavior that must coordinate with a broad range of engine subsystems.
For example, you may have a cutscene/movie subsystem that knows how to play avi files and a game state is responsible for checking whether the player has watched the intro movie and if not, instructs the movie subsystem to play it; otherwise transition to the login screen. The login state is responsible for preparing the login UI with the UI subsystem, perhaps loading the game's theme music and waiting for the user to enter their credentials. Our entire game menu/settings system which can be invoked from the login screen, character select screen, and while in game is all driven inside the game state system by pushing that state onto the active state list.
Another simple example of the game state system at work is when a user transitions from one map to another. You simply signal that you need to transition to a loading state, when you enter the loading state you know which map you need to load and so you can display an appropriate loading screen. During the update loop of this state, perhaps various things are being performed, specific tasks completion statuses being checked and when loading has finished, you pop the state which removes the loading screen and returns the player back to the game play state. Such a transition disables input to the controllers and perhaps other aspects.
As for event detection/dispatch, the observer pattern is simple and yet powerful. Most of my subsystems expose some type of listener interface that I just implement where needed. It's a very simple solution to implement, has minimal overhead and allows you to focus your energy in other places rather than loosing momentum designing something that is likely overkill for where you are at right now. Then when an event is fired, the class holding the listeners simply iterates the listeners, calls some virtual method and the listener implementation fires it's logic. :)
Good luck!