Hola.
A mi, a priori, se me ocurren tres métodos para manejar eventos, que pueden combinarse entre ellos.
El primero sería siguiendo puramente el MVC (que viene a ser el que has mencionado). Se tiene una clase que hace de controlador entre los eventos generados por el sistema operativo (vista) y las clases que necesitan ser notificadas mediante listeners para realizar las acciones pertinentes (modelo). Yo particularmente hago un wrapper de la parte dependiente del sistema que genera eventos independientes del sistema que son pasados al controlador de eventos de entrada (otro tipo de eventos pueden ser pasados a otras clases). Éste, a su vez, los notifica a los listeners que tenga registrados.
Por otro lado, puedes emular un sistema de recogida de eventos por polling de mensajes al estilo Windows o X11, en el que tu clase controladora pasa a encolar los eventos recibidos del sistema de manera abstracta, y las clases que quieren manipular esos eventos piden los que existan encolados.
También existe la posibilidad de mantener un vector con el estado de cada tecla y los últimos datos con respecto al ratón, y acceder desde cualquier parte para consultar su estado. Viene bien para comprobar el estado de algunas teclas como Shift, aunque puede ser sustituido igualmente por el primer caso y un buen diseño.
Particularmente prefiero el primer método, aunque una combinación con el segundo es muy útil en ciertos casos: cuando se quieren conocer eventos asíncronos de manera síncrona. Por ejemplo, cuando se recibe una señal, otro proceso envía un mensaje, un hilo notifica alguna acción, etc. En estos casos, en vez de interrumpir el flujo del programa, se encolan para poder ser leídos cuando corresponda. Una variación sería llamar a listeners para notificar los eventos que se hayan acumulado en la cola durante el último ciclo, para poder mantener un esquema de funcionamiento reactivo uniforme.
Lo más importante es mantener un nivel de abstracción por encima del sistema operativo subyacente, de manera que todo el código que se construya por encima sea independiente de plataforma, ya se estén manejando los eventos por DirectInput, Platform SDK, X11 o lo que sea.
Espero que te haya aclarado algo esta cuestión.
Un saludo,
Ruben3d
editado: Para el manejo genérico de eventos de cualquier tipo he desarrollado una serie de clases reutilizables que se pueden aplicar a casi cualquier contexto, aunque su diseño está íntimamente ligado a características del lenguaje en el que están implementadas. Si desarrollas en C++ te las dejo aqui.