{"action":"created","issue":{"url":"https://api.github.com/repos/PistonDevelopers/input/issues/107","labels_url":"https://api.github.com/repos/PistonDevelopers/input/issues/107/labels{/name}","comments_url":"https://api.github.com/repos/PistonDevelopers/input/issues/107/comments","events_url":"https://api.github.com/repos/PistonDevelopers/input/issues/107/events","html_url":"https://github.com/PistonDevelopers/input/issues/107","id":81496915,"number":107,"title":"Provide a simple input tracker","user":{"login":"RCIX","id":10214664,"avatar_url":"https://avatars.githubusercontent.com/u/10214664?v=3","gravatar_id":"","url":"https://api.github.com/users/RCIX","html_url":"https://github.com/RCIX","followers_url":"https://api.github.com/users/RCIX/followers","following_url":"https://api.github.com/users/RCIX/following{/other_user}","gists_url":"https://api.github.com/users/RCIX/gists{/gist_id}","starred_url":"https://api.github.com/users/RCIX/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RCIX/subscriptions","organizations_url":"https://api.github.com/users/RCIX/orgs","repos_url":"https://api.github.com/users/RCIX/repos","events_url":"https://api.github.com/users/RCIX/events{/privacy}","received_events_url":"https://api.github.com/users/RCIX/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":11,"created_at":"2015-05-27T15:30:28Z","updated_at":"2015-05-27T23:20:58Z","closed_at":null,"body":"Right now, input is passed to a Piston engine game by PressEvent, ReleaseEvent, and various kinds of mouse events from the event library. It's relatively trivial to convert this into input state usable by an update loop, however, I feel it would be of benefit to provide a convenience class within Piston that does this work for newer users. As an example, I threw together the below sample as practice to manage key and mouse button presses:\r\n\r\n```Rust\r\n    use piston::input::Button;\r\n\r\n    pub struct InputArray {\r\n        current_buttons: Vec<Button>,\r\n        last_buttons: Vec<Button>,\r\n        temp_buttons: Vec<Button>\r\n    }\r\n\r\n    impl InputArray {\r\n        pub fn new() -> InputArray {\r\n            InputArray{\r\n                current_buttons: Vec::new(),\r\n                last_buttons: Vec::new(),\r\n                temp_buttons: Vec::new()\r\n            }\r\n        }\r\n \r\n        pub fn update(&mut self) {\r\n            self.last_buttons = self.current_buttons.clone();\r\n            self.current_buttons = self.temp_buttons.clone();\r\n        }\r\n        pub fn register_press(&mut self, button: &Button) {\r\n            if !self.temp_buttons.iter().any(|b| b == button) {\r\n                self.temp_buttons.push(button.clone());\r\n            }\r\n        }\r\n        pub fn register_release(&mut self, button: &Button) {\r\n            if let Some(index) = self.temp_buttons.iter().position(|b| b == button) {\r\n                self.temp_buttons.remove(index);\r\n            }\r\n        }\r\n        pub fn pressed_state(&mut self, button: &Button, last_state: bool, current_state: bool) -> bool {\r\n            self.current_buttons.iter().any(|b| b == button) == current_state && self.last_buttons.iter().any(|b| b == button) == last_state\r\n        }\r\n    }\r\n```\r\n\r\nQuestions:\r\n\r\n* If not input, what library should this proposed class reside in?\r\n* What function semantics should be used for checking the state of a button press? the pressed_state function in the example above would not be immediately clear as to what it's doing without looking at the source\r\n* How should mouse cursor state be stored and presented?\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/PistonDevelopers/input/issues/comments/106108090","html_url":"https://github.com/PistonDevelopers/input/issues/107#issuecomment-106108090","issue_url":"https://api.github.com/repos/PistonDevelopers/input/issues/107","id":106108090,"user":{"login":"RCIX","id":10214664,"avatar_url":"https://avatars.githubusercontent.com/u/10214664?v=3","gravatar_id":"","url":"https://api.github.com/users/RCIX","html_url":"https://github.com/RCIX","followers_url":"https://api.github.com/users/RCIX/followers","following_url":"https://api.github.com/users/RCIX/following{/other_user}","gists_url":"https://api.github.com/users/RCIX/gists{/gist_id}","starred_url":"https://api.github.com/users/RCIX/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RCIX/subscriptions","organizations_url":"https://api.github.com/users/RCIX/orgs","repos_url":"https://api.github.com/users/RCIX/repos","events_url":"https://api.github.com/users/RCIX/events{/privacy}","received_events_url":"https://api.github.com/users/RCIX/received_events","type":"User","site_admin":false},"created_at":"2015-05-27T23:20:58Z","updated_at":"2015-05-27T23:20:58Z","body":"Currently unable to test pending the previously referenced PR, but I have this: \r\n\r\n```Rust\r\nuse piston::input::Button;\r\nuse std::collections::HashMap;\r\n\r\npub struct ButtonController {\r\n    current_buttons: HashMap<Button, bool>,\r\n    last_buttons: HashMap<Button, bool>,\r\n}\r\n\r\nimpl ButtonController {\r\n    pub fn new() -> ButtonController {\r\n        ButtonController {\r\n            current_buttons: HashMap::new(),\r\n            last_buttons: HashMap::new(),\r\n        }\r\n    }\r\n\r\n    pub fn update(&mut self) {\r\n        //leaving this as an idiomatic map until/unless performance becomes a concern\r\n        self.current_buttons.iter().map(|(button, state)| self.last_buttons.insert(button, state));\r\n    }\r\n    pub fn register_press(&mut self, button: &Button) {\r\n        self.current_buttons.insert(&button, true);\r\n    }\r\n\r\n    pub fn register_release(&mut self, button: &Button) {\r\n        self.current_buttons.insert(&button, false);\r\n    }\r\n\r\n    fn current_pressed(&mut self, button: &Button) -> bool {\r\n        if let Some((button, state)) = self.current_buttons.get(&button) {\r\n            state\r\n        } else {\r\n            false\r\n        }\r\n    }\r\n\r\n    fn last_pressed(&mut self, button: &Button) -> bool {\r\n        if let Some((button, state)) = self.current_buttons.get(&button) {\r\n            state\r\n        } else {\r\n            false\r\n        }\r\n    }\r\n\r\n    pub fn pressed_state(&mut self, button: &Button, last_state: bool, current_state: bool) -> bool {\r\n        self.last_pressed(button) == last_state && self.current_pressed(button) == current_state\r\n    }\r\n}\r\n```\r\n\r\nPopulation of the hashmap is lazy - a button is assumed to be unpressed until an initial PressEvent regarding one is passed in. Could be changed to full population if desired/more performant."}}