From fef1dd3a855ce6f010297fb231adac98c75e95f9 Mon Sep 17 00:00:00 2001
From: James Turk <james.p.turk@gmail.com>
Date: Tue, 19 Jul 2005 05:45:22 +0000
Subject: [PATCH] input improved drastically

---
 include/AppCore.hpp       |  44 ++++++++++++-
 include/InputListener.hpp |  96 ++++++++++++++++++++++++++++
 include/photon.hpp        |   1 +
 src/AppCore.cpp           | 128 +++++++++++++++++++++++++++++++++++++-
 src/InputListener.cpp     |  46 ++++++++++++++
 5 files changed, 311 insertions(+), 4 deletions(-)
 create mode 100644 include/InputListener.hpp
 create mode 100644 src/InputListener.cpp

diff --git a/include/AppCore.hpp b/include/AppCore.hpp
index c533654..c2a2494 100644
--- a/include/AppCore.hpp
+++ b/include/AppCore.hpp
@@ -5,7 +5,7 @@
 //  James Turk (jpt2433@rit.edu)
 //
 // Version:
-//  $Id: AppCore.hpp,v 1.7 2005/07/19 01:31:37 cozman Exp $
+//  $Id: AppCore.hpp,v 1.8 2005/07/19 05:45:22 cozman Exp $
 
 #ifndef PHOTON_APPCORE_HPP
 #define PHOTON_APPCORE_HPP
@@ -14,6 +14,9 @@
 #include "util/VersionInfo.hpp"
 #include "util/Singleton.hpp"
 #include "Task.hpp"
+#include "InputListener.hpp"
+
+#include <vector>
 
 namespace photon
 {
@@ -83,6 +86,13 @@ public:
     // Returns:
     //  true: key is pressed, false: key isn't pressed
     bool keyPressed(KeyCode key);
+    
+    // Function: getPressedKeys
+    //  Obtain a list of all keys which are currently pressed.
+    //
+    // Returns:
+    //  std::vector of <KeyCodes> of any pressed keys.
+    std::vector<KeyCode> getPressedKeys();
 
     // Function: mouseButtonPressed
     //  Check if a given mouse button is currently pressed.
@@ -115,6 +125,30 @@ public:
     // Returns:
     //  Mouse wheel position, zero assumed to be starting position.
     int getMouseWheelPos();
+    
+// Group: Input Listeners
+public:
+
+    // Function: addInputListener
+    //  Registers an <InputListener> to listen for any input events so that it
+    //  is notified when they occur.
+    //
+    // Parameters:
+    //  listener - Pointer to <InputListener> to add.
+    static void addInputListener(InputListener *listener);
+    
+    // Function: removeInputListener
+    //  Removes an <InputListener> from the list of active listeners.
+    //
+    // Parameters:
+    //  listener - Pointer to <InputListener> to remove.
+    static void removeInputListener(InputListener *listener);
+    
+    static void GLFWCALL keyCallback(int key, int action);
+    //static void GLFWCALL charCallback(int character, int action);
+    static void GLFWCALL mouseButtonCallback(int button, int action);
+    static void GLFWCALL mouseMoveCallback(int x, int y);
+    //static void GLFWCALL mouseWheelCallback(int pos);
 
 // Group: Timing
 public:
@@ -175,7 +209,11 @@ public:
     // Returns:
     //  Height of display in pixels.
     uint getDisplayHeight();
+    
 
+    // UpdateTask, does the updating work of AppCore, registered as a Task
+    //  so that user need not call something akin to AppCore::update() every 
+    //  frame
     class UpdateTask : public Task
     {
 
@@ -203,6 +241,10 @@ private:
     uint dispWidth_;
     uint dispHeight_;
     shared_ptr<UpdateTask> task_;
+    
+    // input monitoring variables
+    static std::vector<InputListener*> listeners_;
+    static std::vector<KeyCode> pressedKeys_;
 
 // API initialization
 private:
diff --git a/include/InputListener.hpp b/include/InputListener.hpp
new file mode 100644
index 0000000..f3047a0
--- /dev/null
+++ b/include/InputListener.hpp
@@ -0,0 +1,96 @@
+//This file is part of Photon (http://photon.sourceforge.net)
+//Copyright (C) 2004-2005 James Turk
+//
+// Author:
+//  James Turk (jpt2433@rit.edu)
+//
+// Version:
+//  $Id: InputListener.hpp,v 1.1 2005/07/19 05:45:23 cozman Exp $
+
+#ifndef PHOTON_INPUTLISTENER_HPP
+#define PHOTON_INPUTLISTENER_HPP
+
+#include "math/Vector2.hpp"
+
+namespace photon
+{
+
+// Class: InputListener
+//  Virtual class to handle user input, classes can derive from this to be 
+//  notified of input events.
+class InputListener
+{
+// Group: (Con/De)structors
+public:
+
+    // Function: InputListener
+    //  Registers the InputListener to listen for input with <AppCore>.
+    InputListener();
+
+    // Function: ~InputListener
+    //  Deregisters the listener with <AppCore>. so that it is no longer
+    //  notified of events.
+    virtual ~InputListener();
+
+// Group: General
+public:
+
+    // Function: setActive
+    //  Enable/Disable the InputListener.
+    //
+    // Parameters:
+    //  active - Active state of the InputListener.
+    void setActive(bool active);
+
+    // Function: isActive
+    //  Returns true if the InputListener is active.
+    //
+    // Returns: true if active, false if deactivated
+    bool isActive() const;
+
+// Group: Keyboard Actions
+public:
+    // Function: onKeyPress
+    //  Called when a key is pressed.
+    // 
+    // Parameters:
+    //  key - Key that has been pressed. 
+    virtual void onKeyPress(int key);
+    
+    // Function: onKeyRelease
+    //  Called when a key is released.
+    // 
+    // Parameters:
+    //  key - Key that has been released.
+    virtual void onKeyRelease(int key);
+
+// Group: Mouse Actions
+public:
+    // Function: onMouseButtonPress
+    //  Called when a mouse button is pressed.
+    //
+    // Parameters:
+    //  button - Mouse button that was pressed.
+    virtual void onMouseButtonPress(int button);
+    
+    // Function: onMouseButtonRelease
+    //  Called when a mouse button is released.
+    //
+    // Parameters:
+    //  button - Mouse button that was released.
+    virtual void onMouseButtonRelease(int button);
+
+    // Function: onMouseMove
+    //  Called when the mouse is moved.
+    //
+    // Parameters:
+    //  pos - Position of the mouse.
+    virtual void onMouseMove(const math::Vector2& pos);
+    
+private:
+    bool active_;
+};
+
+}
+
+#endif  //PHOTON_INPUTLISTENER_HPP
diff --git a/include/photon.hpp b/include/photon.hpp
index 3cae671..1f60e7b 100644
--- a/include/photon.hpp
+++ b/include/photon.hpp
@@ -8,6 +8,7 @@
 #include "Task.hpp"
 #include "exceptions.hpp"
 #include "photon.hpp"
+#include "InputListener.hpp"
 #include "entrypoint.hpp"
 #include "LogSink.hpp"
 #include "Log.hpp"
diff --git a/src/AppCore.cpp b/src/AppCore.cpp
index 6128110..ff3b28d 100644
--- a/src/AppCore.cpp
+++ b/src/AppCore.cpp
@@ -5,7 +5,7 @@
 //  James Turk (jpt2433@rit.edu)
 //
 // Version:
-//  $Id: AppCore.cpp,v 1.10 2005/07/19 01:31:37 cozman Exp $
+//  $Id: AppCore.cpp,v 1.11 2005/07/19 05:45:23 cozman Exp $
 
 #include "AppCore.hpp"
 
@@ -19,14 +19,16 @@
 namespace photon
 {
 
+// static initializer
+std::vector<InputListener*> AppCore::listeners_;
+std::vector<KeyCode> AppCore::pressedKeys_;
+
 AppCore::AppCore() :
     dispWidth_(0), dispHeight_(0),
     task_(new UpdateTask())
 {
     util::VersionInfo glfwReq(2,4,2);   // requires GLFW 2.4.2
     util::ensureVersion("GLFW", initGLFW(), glfwReq);
-    
-    new video::VideoCore;   // create the VideoCore
 
     Kernel::getInstance().addTask(task_);
 }
@@ -51,9 +53,17 @@ void AppCore::createDisplay(uint width, uint height,
     {
         throw APIError("Failed to create display.");
     }
+    
+    // register the callbacks (after a window is open)
+    glfwSetKeyCallback(AppCore::keyCallback);
+    //glfwSetCharCallback(AppCore::charCallback);
+    glfwSetMouseButtonCallback(AppCore::mouseButtonCallback);
+    glfwSetMousePosCallback(AppCore::mouseMoveCallback);
+    //glfwSetMouseWheelCallback(AppCore::mouseWheelCallback);
 
     dispWidth_ = width;
     dispHeight_ = height;
+    new video::VideoCore;   // _MUST_ create the VideoCore after the window!
     video::VideoCore::getInstance().setDisplaySize(width,height);
 
     glfwSetWindowTitle(title.c_str());  // title is set separately
@@ -94,6 +104,11 @@ bool AppCore::keyPressed(KeyCode key)
     return glfwGetKey(key) == GLFW_PRESS;
 }
 
+std::vector<KeyCode> AppCore::getPressedKeys()
+{
+    return pressedKeys_;
+}
+
 bool AppCore::mouseButtonPressed(MouseButton button)
 {
     return glfwGetMouseButton(button) == GLFW_PRESS;
@@ -114,6 +129,113 @@ int AppCore::getMouseWheelPos()
     return glfwGetMouseWheel();
 }
 
+void AppCore::addInputListener(InputListener *listener)
+{
+    // should never happen since listeners add themselves with a this pointer
+    if(!listener)
+    {
+        throw ArgumentException("Null pointer in AppCore::addInputListener");
+    }
+    
+    // add the listener
+    listeners_.push_back(listener);
+}
+
+void AppCore::removeInputListener(InputListener *listener)
+{
+    // should never happen since listeners remove themselves with a this pointer
+    if(!listener)
+    {
+        throw ArgumentException("Null pointer in AppCore::removeInputListener");
+    }
+
+    // find and erase the listener
+    std::vector<InputListener*>::iterator it;
+    it = std::find(listeners_.begin(), listeners_.end(), listener);
+
+    if(it != listeners_.end())
+    {
+        listeners_.erase(it);
+    }
+}
+
+void GLFWCALL AppCore::keyCallback(int key, int action)
+{
+    // notify all listeners
+    for(std::vector<InputListener*>::iterator listener = listeners_.begin();
+        listener != listeners_.end(); 
+        ++listener)
+    {
+        // only active listeners get messages
+        if((*listener)->isActive())
+        {
+            if(action == GLFW_PRESS)
+            {
+                (*listener)->onKeyPress(key);
+            }
+            else
+            {
+                (*listener)->onKeyRelease(key);
+            }
+        }
+    }
+    
+    // maintain a list of pressed keys
+    if(action == GLFW_PRESS)
+    {
+        pressedKeys_.push_back(static_cast<KeyCode>(key));
+    }
+    else
+    {
+        // delete a key from the vector
+        std::vector<KeyCode>::iterator it;
+        it = std::find(pressedKeys_.begin(), pressedKeys_.end(), key);
+    
+        if(it != pressedKeys_.end())
+        {
+            pressedKeys_.erase(it);
+        }
+    }
+}
+
+void GLFWCALL AppCore::mouseButtonCallback(int button, int action)
+{
+    // notify all listeners
+    for(std::vector<InputListener*>::iterator listener = listeners_.begin();
+        listener != listeners_.end(); 
+        ++listener)
+    {
+        // only active listeners get messages
+        if((*listener)->isActive())
+        {
+            if(action == GLFW_PRESS)
+            {
+                (*listener)->onMouseButtonPress(button);
+            }
+            else
+            {
+                (*listener)->onMouseButtonRelease(button);
+            }
+        }
+    }
+}
+
+void GLFWCALL AppCore::mouseMoveCallback(int x, int y)
+{
+    // notify all listeners
+    for(std::vector<InputListener*>::iterator listener = listeners_.begin();
+        listener != listeners_.end(); 
+        ++listener)
+    {
+        // only active listeners get messages
+        if((*listener)->isActive())
+        {
+            (*listener)->onMouseMove(math::Vector2(static_cast<scalar>(x),
+                                                    static_cast<scalar>(y)));
+        }
+    }
+}
+
 scalar AppCore::getTime()
 {
     return glfwGetTime() - task_->pausedTime_;
diff --git a/src/InputListener.cpp b/src/InputListener.cpp
new file mode 100644
index 0000000..168ca99
--- /dev/null
+++ b/src/InputListener.cpp
@@ -0,0 +1,46 @@
+//This file is part of Photon (http://photon.sourceforge.net)
+//Copyright (C) 2004-2005 James Turk
+//
+// Author:
+//  James Turk (jpt2433@rit.edu)
+//
+// Version:
+//  $Id: InputListener.cpp,v 1.1 2005/07/19 05:45:24 cozman Exp $
+
+#include "InputListener.hpp"
+
+#include "AppCore.hpp" 
+
+namespace photon
+{
+
+InputListener::InputListener() :
+    active_(true)
+{
+    AppCore::addInputListener(this);
+}
+
+InputListener::~InputListener()
+{
+    AppCore::removeInputListener(this);
+}
+
+void InputListener::setActive(bool active)
+{
+    active_ = active;
+}
+
+bool InputListener::isActive() const
+{
+    return active_;
+}
+
+// do nothing, overloaded as needed
+void InputListener::onKeyPress(int key) { }
+void InputListener::onKeyRelease(int key) { }
+void InputListener::onMouseButtonPress(int button)  { }
+void InputListener::onMouseButtonRelease(int button) { }
+void InputListener::onMouseMove(const math::Vector2& pos) { }
+
+
+}