There are many ways to handle events. Direct dispatch is the easiest, but least efficient in many cases. When an event happens, generate the event object and then pass it off to the HandleEvent method of any potentially interested game object. Since the GO does its own event filtering, this gets expensive as the number of events and interested GO list grows.
You can remove the manual filtering by giving each event object a virtual SendTo method that selects the correct handler. The InputEvent might call OnInput on the target GO, while the CollisionEvent might call OnCollision. The handlers can be empty virtual functions in the base GO class.
To get around the expense, consider using an observer pattern for some events. The GO registers which events it cares about and which handler to call. Then events are only delivered to the objects that are actually interested, not just potentially interested. You can keep the list of registrations in a Dictionary on the event emitter object (eg your InputSystem) easily.
It's common to have a mix of event delivery methods. Some events make more sense in an observer system, some in a direct dispatch system.