{"action":"created","comment":{"url":"https://api.github.com/repos/highfidelity/hifi/pulls/comments/29256946","id":29256946,"diff_hunk":"@@ -0,0 +1,381 @@\n+//\n+//  UserInputMapper.h\n+//  interface/src/ui\n+//\n+//  Created by Sam Gateau on 4/27/15.\n+//  Copyright 2015 High Fidelity, Inc.\n+//\n+//  Distributed under the Apache License, Version 2.0.\n+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html\n+//\n+\n+#ifndef hifi_UserInputMapper_h\n+#define hifi_UserInputMapper_h\n+\n+#include <glm/glm.hpp>\n+#include <RegisteredMetaTypes.h>\n+#include \"TouchEvent.h\"\n+#include <unordered_set>\n+#include <functional>\n+\n+class UserInputMapper : public QObject {\n+    Q_OBJECT\n+public:\n+    static const int INVALID = -1;\n+    typedef unsigned short uint16;\n+    typedef unsigned int uint32;\n+\n+    enum class ChannelType {\n+        UNKNOWN = 0,\n+        BUTTON = 1,\n+        AXIS,\n+        JOINT,\n+    };\n+\n+    class InputID {\n+    public:\n+        union {\n+            struct {\n+                uint16 _device; // Up to 64K possible devices\n+                uint16 _channel : 14; // 2^14 possible channel per Device\n+                uint16 _type : 2; // 2 bits to store the Type directly in the ID\n+            };\n+            uint32 _id = 0;\n+        };\n+\n+        uint16 getDevice() const { return _device; }\n+        uint16 getChannel() const { return _channel; }\n+        uint32 getID() const { return _id; }\n+\n+        ChannelType getType() const { return (ChannelType) _type; }\n+        bool isButton() const { return getType() == ChannelType::BUTTON; }\n+        bool isAxis() const { return getType() == ChannelType::AXIS; }\n+        bool isJoint() const { return getType() == ChannelType::JOINT; }\n+\n+        explicit InputID() {}\n+        explicit InputID(uint32 id) : _id(id) {}\n+        explicit InputID(uint16 device, uint16 channel, ChannelType type) : _device(device), _channel(channel), _type(uint16(type)) {}\n+        InputID(const InputID& src) : _id(src._id) {}\n+        InputID& operator = (const InputID& src) { _id = src._id; return (*this); }\n+    };\n+\n+    typedef std::function<bool (const InputID& input, int timestamp)> ButtonGetter;\n+    typedef std::function<float (const InputID& input, int timestamp)> AxisGetter;\n+    \n+    class JointValue {\n+    public:\n+        glm::vec3 translation{ 0.0f };\n+        glm::quat rotation;\n+\n+        JointValue() {};\n+        JointValue(const JointValue&) = default;\n+        JointValue& operator = (const JointValue&) = default;\n+    };\n+    typedef std::function<JointValue (const InputID& input, int timestamp)> JointGetter;\n+\n+ \n+    bool registerInputButton(const InputID& input, ButtonGetter getter);\n+    bool registerInputAxis(const InputID& input, AxisGetter getter);\n+    bool registerInputJoint(const InputID& input, JointGetter getter);\n+\n+    class KeyboardMouseDevice {\n+    public:\n+\n+        enum KeyboardChannel {\n+            KEYBOARD_FIRST = 0,\n+            KEYBOARD_LAST = 255,\n+            KEYBOARD_MASK = 0x00FF,\n+        };\n+\n+        enum MouseButtonChannel {\n+            MOUSE_BUTTON_LEFT = KEYBOARD_LAST + 1,\n+            MOUSE_BUTTON_RIGHT,\n+            MOUSE_BUTTON_MIDDLE,\n+        };\n+\n+        enum MouseAxisChannel {\n+            MOUSE_AXIS_X_POS = MOUSE_BUTTON_MIDDLE + 1,\n+            MOUSE_AXIS_X_NEG,\n+            MOUSE_AXIS_Y_POS,\n+            MOUSE_AXIS_Y_NEG,\n+            MOUSE_AXIS_WHEEL_Y_POS,\n+            MOUSE_AXIS_WHEEL_Y_NEG,\n+            MOUSE_AXIS_WHEEL_X_POS,\n+            MOUSE_AXIS_WHEEL_X_NEG,\n+        };\n+\n+        typedef std::unordered_set<int> ButtonPressedMap;\n+        typedef std::map<int, float> AxisStateMap; // 8 axes\n+\n+        void keyPressEvent(QKeyEvent* event);\n+        void keyReleaseEvent(QKeyEvent* event);\n+\n+        void mouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0);\n+        void mousePressEvent(QMouseEvent* event, unsigned int deviceID = 0);\n+        void mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0);\n+\n+        void touchBeginEvent(const TouchEvent& event);\n+        void touchEndEvent(const TouchEvent& event);\n+        void touchUpdateEvent(const TouchEvent& event);\n+\n+        void wheelEvent(QWheelEvent* event);\n+\n+        ButtonPressedMap _buttonPressedMap;\n+        mutable AxisStateMap _axisStateMap;\n+\n+        QPoint _lastCursor;\n+\n+        float getButton(int channel) const {\n+            if (!_buttonPressedMap.empty()) {\n+                if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {\n+                    return 1.0f;\n+                } else {\n+                    return 0.0f;\n+                }\n+            }\n+            return 0.0f;\n+        }\n+        float getAxis(int channel) const {\n+            auto& axis = _axisStateMap.find(channel);\n+            if (axis != _axisStateMap.end()) {\n+                return (*axis).second;\n+            } else {\n+                return 0.f;\n+            }\n+        }\n+\n+    \n+        // Reserverd channel for the standard keyboard and mouse\n+        const static uint16 DEFAULT_DESKTOP_DEVICE = 1;\n+\n+        // Let's make it easy for Qt because we assume we love Qt forever\n+        static InputID makeInputID(Qt::Key code) {\n+            return InputID(DEFAULT_DESKTOP_DEVICE, code & KEYBOARD_MASK, ChannelType::BUTTON);\n+        }\n+        static InputID makeInputID(Qt::MouseButton code) {","path":"interface/src/ui/UserInputMapper.h","position":155,"original_position":155,"commit_id":"a1e19cb88d3e0feeb25e25d3676bf32d13020f05","original_commit_id":"a1e19cb88d3e0feeb25e25d3676bf32d13020f05","user":{"login":"ZappoMan","id":2093195,"avatar_url":"https://avatars.githubusercontent.com/u/2093195?v=3","gravatar_id":"","url":"https://api.github.com/users/ZappoMan","html_url":"https://github.com/ZappoMan","followers_url":"https://api.github.com/users/ZappoMan/followers","following_url":"https://api.github.com/users/ZappoMan/following{/other_user}","gists_url":"https://api.github.com/users/ZappoMan/gists{/gist_id}","starred_url":"https://api.github.com/users/ZappoMan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ZappoMan/subscriptions","organizations_url":"https://api.github.com/users/ZappoMan/orgs","repos_url":"https://api.github.com/users/ZappoMan/repos","events_url":"https://api.github.com/users/ZappoMan/events{/privacy}","received_events_url":"https://api.github.com/users/ZappoMan/received_events","type":"User","site_admin":false},"body":"move to cpp\r\ncoding standard formating","created_at":"2015-04-28T15:51:19Z","updated_at":"2015-04-28T15:51:19Z","html_url":"https://github.com/highfidelity/hifi/pull/4711#discussion_r29256946","pull_request_url":"https://api.github.com/repos/highfidelity/hifi/pulls/4711","_links":{"self":{"href":"https://api.github.com/repos/highfidelity/hifi/pulls/comments/29256946"},"html":{"href":"https://github.com/highfidelity/hifi/pull/4711#discussion_r29256946"},"pull_request":{"href":"https://api.github.com/repos/highfidelity/hifi/pulls/4711"}}},"pull_request":{"url":"https://api.github.com/repos/highfidelity/hifi/pulls/4711","id":34249580,"html_url":"https://github.com/highfidelity/hifi/pull/4711","diff_url":"https://github.com/highfidelity/hifi/pull/4711.diff","patch_url":"https://github.com/highfidelity/hifi/pull/4711.patch","issue_url":"https://api.github.com/repos/highfidelity/hifi/issues/4711","number":4711,"state":"open","locked":false,"title":"DO NOT MERGE: Split the Camera and the Avatar and introduce the UserInputMapper","user":{"login":"samcake","id":2230265,"avatar_url":"https://avatars.githubusercontent.com/u/2230265?v=3","gravatar_id":"","url":"https://api.github.com/users/samcake","html_url":"https://github.com/samcake","followers_url":"https://api.github.com/users/samcake/followers","following_url":"https://api.github.com/users/samcake/following{/other_user}","gists_url":"https://api.github.com/users/samcake/gists{/gist_id}","starred_url":"https://api.github.com/users/samcake/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/samcake/subscriptions","organizations_url":"https://api.github.com/users/samcake/orgs","repos_url":"https://api.github.com/users/samcake/repos","events_url":"https://api.github.com/users/samcake/events{/privacy}","received_events_url":"https://api.github.com/users/samcake/received_events","type":"User","site_admin":false},"body":"This is a work in progress! but we need to test this, prototype more and do it again...\r\n\r\n- Split the Camera from the Avatar, meaning:\r\n    - The camera 1st and 3rd person modes are merged into the \"Camera_mode_avatar\", the only difference between the 2 modes is the boom distance of the Camera.\r\n   - The Camera position is starting from the same Avatar hips position. That's the root frame of the Camera. THis is where the yaw of the Camera is injected\r\n   - The pivot of the Camera is the frame placed at the default eye position of the avatar. This is where the pitch of the camera is injected\r\n - Lastly, the View Frame is moved along the Z axis of the boom distance\r\n\r\n- The userInputMapper is the class doing the mapping between the user input devices among others the default keyboardMouseDevice and the \"logical\" channel of the application. this is where all the different places that can \"control\" the application interface together in a single set of channels that the whole application (and js) can pull from.\r\n\r\n-  The bridge between the userInputMapper and the Camera and MyAVatar is happening in the LookMoveController. For now it;s a hard coded behavior but the plan is a js function could take over that task so user can transform the way the Camera and the avatar are moving from the user inputs.\r\n\r\nSo please test and prototype and let me know how it works  or not for you.\r\n\r\n   \r\n\r\n ","created_at":"2015-04-28T09:45:48Z","updated_at":"2015-04-28T15:51:19Z","closed_at":null,"merged_at":null,"merge_commit_sha":"558a949c5aa88c2f513e88030883076e9acbca33","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/highfidelity/hifi/pulls/4711/commits","review_comments_url":"https://api.github.com/repos/highfidelity/hifi/pulls/4711/comments","review_comment_url":"https://api.github.com/repos/highfidelity/hifi/pulls/comments{/number}","comments_url":"https://api.github.com/repos/highfidelity/hifi/issues/4711/comments","statuses_url":"https://api.github.com/repos/highfidelity/hifi/statuses/a1e19cb88d3e0feeb25e25d3676bf32d13020f05","head":{"label":"samcake:darkblue","ref":"darkblue","sha":"a1e19cb88d3e0feeb25e25d3676bf32d13020f05","user":{"login":"samcake","id":2230265,"avatar_url":"https://avatars.githubusercontent.com/u/2230265?v=3","gravatar_id":"","url":"https://api.github.com/users/samcake","html_url":"https://github.com/samcake","followers_url":"https://api.github.com/users/samcake/followers","following_url":"https://api.github.com/users/samcake/following{/other_user}","gists_url":"https://api.github.com/users/samcake/gists{/gist_id}","starred_url":"https://api.github.com/users/samcake/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/samcake/subscriptions","organizations_url":"https://api.github.com/users/samcake/orgs","repos_url":"https://api.github.com/users/samcake/repos","events_url":"https://api.github.com/users/samcake/events{/privacy}","received_events_url":"https://api.github.com/users/samcake/received_events","type":"User","site_admin":false},"repo":{"id":24736064,"name":"hifi","full_name":"samcake/hifi","owner":{"login":"samcake","id":2230265,"avatar_url":"https://avatars.githubusercontent.com/u/2230265?v=3","gravatar_id":"","url":"https://api.github.com/users/samcake","html_url":"https://github.com/samcake","followers_url":"https://api.github.com/users/samcake/followers","following_url":"https://api.github.com/users/samcake/following{/other_user}","gists_url":"https://api.github.com/users/samcake/gists{/gist_id}","starred_url":"https://api.github.com/users/samcake/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/samcake/subscriptions","organizations_url":"https://api.github.com/users/samcake/orgs","repos_url":"https://api.github.com/users/samcake/repos","events_url":"https://api.github.com/users/samcake/events{/privacy}","received_events_url":"https://api.github.com/users/samcake/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/samcake/hifi","description":"Open, decentralized virtual worlds using sensors to control avatars and dynamically assigned devices as servers.  San Francisco based startup, we are hiring: http://highfidelity.io/jobs  Contribute by reporting bugs & doing jobs on http://worklist.net","fork":true,"url":"https://api.github.com/repos/samcake/hifi","forks_url":"https://api.github.com/repos/samcake/hifi/forks","keys_url":"https://api.github.com/repos/samcake/hifi/keys{/key_id}","collaborators_url":"https://api.github.com/repos/samcake/hifi/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/samcake/hifi/teams","hooks_url":"https://api.github.com/repos/samcake/hifi/hooks","issue_events_url":"https://api.github.com/repos/samcake/hifi/issues/events{/number}","events_url":"https://api.github.com/repos/samcake/hifi/events","assignees_url":"https://api.github.com/repos/samcake/hifi/assignees{/user}","branches_url":"https://api.github.com/repos/samcake/hifi/branches{/branch}","tags_url":"https://api.github.com/repos/samcake/hifi/tags","blobs_url":"https://api.github.com/repos/samcake/hifi/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/samcake/hifi/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/samcake/hifi/git/refs{/sha}","trees_url":"https://api.github.com/repos/samcake/hifi/git/trees{/sha}","statuses_url":"https://api.github.com/repos/samcake/hifi/statuses/{sha}","languages_url":"https://api.github.com/repos/samcake/hifi/languages","stargazers_url":"https://api.github.com/repos/samcake/hifi/stargazers","contributors_url":"https://api.github.com/repos/samcake/hifi/contributors","subscribers_url":"https://api.github.com/repos/samcake/hifi/subscribers","subscription_url":"https://api.github.com/repos/samcake/hifi/subscription","commits_url":"https://api.github.com/repos/samcake/hifi/commits{/sha}","git_commits_url":"https://api.github.com/repos/samcake/hifi/git/commits{/sha}","comments_url":"https://api.github.com/repos/samcake/hifi/comments{/number}","issue_comment_url":"https://api.github.com/repos/samcake/hifi/issues/comments{/number}","contents_url":"https://api.github.com/repos/samcake/hifi/contents/{+path}","compare_url":"https://api.github.com/repos/samcake/hifi/compare/{base}...{head}","merges_url":"https://api.github.com/repos/samcake/hifi/merges","archive_url":"https://api.github.com/repos/samcake/hifi/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/samcake/hifi/downloads","issues_url":"https://api.github.com/repos/samcake/hifi/issues{/number}","pulls_url":"https://api.github.com/repos/samcake/hifi/pulls{/number}","milestones_url":"https://api.github.com/repos/samcake/hifi/milestones{/number}","notifications_url":"https://api.github.com/repos/samcake/hifi/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/samcake/hifi/labels{/name}","releases_url":"https://api.github.com/repos/samcake/hifi/releases{/id}","created_at":"2014-10-02T20:49:37Z","updated_at":"2015-04-02T23:12:49Z","pushed_at":"2015-04-28T09:41:41Z","git_url":"git://github.com/samcake/hifi.git","ssh_url":"git@github.com:samcake/hifi.git","clone_url":"https://github.com/samcake/hifi.git","svn_url":"https://github.com/samcake/hifi","homepage":"","size":153401,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"highfidelity:master","ref":"master","sha":"f49f37ac8911756130174a4d2a4dc65587f4862c","user":{"login":"highfidelity","id":1565370,"avatar_url":"https://avatars.githubusercontent.com/u/1565370?v=3","gravatar_id":"","url":"https://api.github.com/users/highfidelity","html_url":"https://github.com/highfidelity","followers_url":"https://api.github.com/users/highfidelity/followers","following_url":"https://api.github.com/users/highfidelity/following{/other_user}","gists_url":"https://api.github.com/users/highfidelity/gists{/gist_id}","starred_url":"https://api.github.com/users/highfidelity/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/highfidelity/subscriptions","organizations_url":"https://api.github.com/users/highfidelity/orgs","repos_url":"https://api.github.com/users/highfidelity/repos","events_url":"https://api.github.com/users/highfidelity/events{/privacy}","received_events_url":"https://api.github.com/users/highfidelity/received_events","type":"Organization","site_admin":false},"repo":{"id":5372872,"name":"hifi","full_name":"highfidelity/hifi","owner":{"login":"highfidelity","id":1565370,"avatar_url":"https://avatars.githubusercontent.com/u/1565370?v=3","gravatar_id":"","url":"https://api.github.com/users/highfidelity","html_url":"https://github.com/highfidelity","followers_url":"https://api.github.com/users/highfidelity/followers","following_url":"https://api.github.com/users/highfidelity/following{/other_user}","gists_url":"https://api.github.com/users/highfidelity/gists{/gist_id}","starred_url":"https://api.github.com/users/highfidelity/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/highfidelity/subscriptions","organizations_url":"https://api.github.com/users/highfidelity/orgs","repos_url":"https://api.github.com/users/highfidelity/repos","events_url":"https://api.github.com/users/highfidelity/events{/privacy}","received_events_url":"https://api.github.com/users/highfidelity/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/highfidelity/hifi","description":"Open source software for shared virtual worlds using HMDs and dynamically assigned devices as servers.  San Francisco based startup, we are hiring: http://highfidelity.com/jobs  Documentation at http://docs.highfidelity.com  Contribute by reporting bugs & doing jobs on http://worklist.net","fork":false,"url":"https://api.github.com/repos/highfidelity/hifi","forks_url":"https://api.github.com/repos/highfidelity/hifi/forks","keys_url":"https://api.github.com/repos/highfidelity/hifi/keys{/key_id}","collaborators_url":"https://api.github.com/repos/highfidelity/hifi/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/highfidelity/hifi/teams","hooks_url":"https://api.github.com/repos/highfidelity/hifi/hooks","issue_events_url":"https://api.github.com/repos/highfidelity/hifi/issues/events{/number}","events_url":"https://api.github.com/repos/highfidelity/hifi/events","assignees_url":"https://api.github.com/repos/highfidelity/hifi/assignees{/user}","branches_url":"https://api.github.com/repos/highfidelity/hifi/branches{/branch}","tags_url":"https://api.github.com/repos/highfidelity/hifi/tags","blobs_url":"https://api.github.com/repos/highfidelity/hifi/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/highfidelity/hifi/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/highfidelity/hifi/git/refs{/sha}","trees_url":"https://api.github.com/repos/highfidelity/hifi/git/trees{/sha}","statuses_url":"https://api.github.com/repos/highfidelity/hifi/statuses/{sha}","languages_url":"https://api.github.com/repos/highfidelity/hifi/languages","stargazers_url":"https://api.github.com/repos/highfidelity/hifi/stargazers","contributors_url":"https://api.github.com/repos/highfidelity/hifi/contributors","subscribers_url":"https://api.github.com/repos/highfidelity/hifi/subscribers","subscription_url":"https://api.github.com/repos/highfidelity/hifi/subscription","commits_url":"https://api.github.com/repos/highfidelity/hifi/commits{/sha}","git_commits_url":"https://api.github.com/repos/highfidelity/hifi/git/commits{/sha}","comments_url":"https://api.github.com/repos/highfidelity/hifi/comments{/number}","issue_comment_url":"https://api.github.com/repos/highfidelity/hifi/issues/comments{/number}","contents_url":"https://api.github.com/repos/highfidelity/hifi/contents/{+path}","compare_url":"https://api.github.com/repos/highfidelity/hifi/compare/{base}...{head}","merges_url":"https://api.github.com/repos/highfidelity/hifi/merges","archive_url":"https://api.github.com/repos/highfidelity/hifi/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/highfidelity/hifi/downloads","issues_url":"https://api.github.com/repos/highfidelity/hifi/issues{/number}","pulls_url":"https://api.github.com/repos/highfidelity/hifi/pulls{/number}","milestones_url":"https://api.github.com/repos/highfidelity/hifi/milestones{/number}","notifications_url":"https://api.github.com/repos/highfidelity/hifi/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/highfidelity/hifi/labels{/name}","releases_url":"https://api.github.com/repos/highfidelity/hifi/releases{/id}","created_at":"2012-08-10T18:26:22Z","updated_at":"2015-04-28T12:04:18Z","pushed_at":"2015-04-28T12:04:17Z","git_url":"git://github.com/highfidelity/hifi.git","ssh_url":"git@github.com:highfidelity/hifi.git","clone_url":"https://github.com/highfidelity/hifi.git","svn_url":"https://github.com/highfidelity/hifi","homepage":"","size":205701,"stargazers_count":259,"watchers_count":259,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":144,"mirror_url":null,"open_issues_count":53,"forks":144,"open_issues":53,"watchers":259,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/highfidelity/hifi/pulls/4711"},"html":{"href":"https://github.com/highfidelity/hifi/pull/4711"},"issue":{"href":"https://api.github.com/repos/highfidelity/hifi/issues/4711"},"comments":{"href":"https://api.github.com/repos/highfidelity/hifi/issues/4711/comments"},"review_comments":{"href":"https://api.github.com/repos/highfidelity/hifi/pulls/4711/comments"},"review_comment":{"href":"https://api.github.com/repos/highfidelity/hifi/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/highfidelity/hifi/pulls/4711/commits"},"statuses":{"href":"https://api.github.com/repos/highfidelity/hifi/statuses/a1e19cb88d3e0feeb25e25d3676bf32d13020f05"}}}}