{"action":"closed","issue":{"url":"https://api.github.com/repos/keyboardio/KeyboardioFirmware/issues/36","repository_url":"https://api.github.com/repos/keyboardio/KeyboardioFirmware","labels_url":"https://api.github.com/repos/keyboardio/KeyboardioFirmware/issues/36/labels{/name}","comments_url":"https://api.github.com/repos/keyboardio/KeyboardioFirmware/issues/36/comments","events_url":"https://api.github.com/repos/keyboardio/KeyboardioFirmware/issues/36/events","html_url":"https://github.com/keyboardio/KeyboardioFirmware/issues/36","id":189326185,"number":36,"title":"Replacing loop/event-handler hooks, and more helpers","user":{"login":"algernon","id":17243,"avatar_url":"https://avatars.githubusercontent.com/u/17243?v=3","gravatar_id":"","url":"https://api.github.com/users/algernon","html_url":"https://github.com/algernon","followers_url":"https://api.github.com/users/algernon/followers","following_url":"https://api.github.com/users/algernon/following{/other_user}","gists_url":"https://api.github.com/users/algernon/gists{/gist_id}","starred_url":"https://api.github.com/users/algernon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/algernon/subscriptions","organizations_url":"https://api.github.com/users/algernon/orgs","repos_url":"https://api.github.com/users/algernon/repos","events_url":"https://api.github.com/users/algernon/events{/privacy}","received_events_url":"https://api.github.com/users/algernon/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":2,"created_at":"2016-11-15T08:14:16Z","updated_at":"2016-11-21T05:23:24Z","closed_at":"2016-11-21T05:23:24Z","body":"While trying to work out how to implement one-shot keys nicely, I ran into a couple of shortcomings with the current - very simplistic - hook helpers: the API only allows appending hooks, but to toggle one-shots on and off, I'd need a way to replace an existing hook, too.\r\n\r\nWhile there, deleting a hook, and prepending (or rather, inserting at a specific position) would also be useful. So I'm proposing the following additional helpers, which I will implement at the first opportunity, too:\r\n\r\n```c++\r\n// delete all occurrences of the hook function from the array, pulling up later handlers\r\nvoid event_handler_hook_delete (custom_handler_t hook);\r\n\r\n// replace one hook with another\r\nvoid event_handler_hook_replace (custom_handler_t old, custom_handler_t new);\r\n\r\n// insert a hook at a specific index, pushing down the rest, if need be\r\nvoid event_handler_hook_insert (byte idx, custom_handler_t hook);\r\n```\r\n\r\n...and the same for the `loop()` hooks.\r\n\r\nIn a plugin, one would use them like this:\r\n\r\n```c++\r\nvoid OneShotMods::on() {\r\n  if (isOn)\r\n    return;\r\n\r\n  event_handler_hook_replace (this->passthroughHandler, this->oneShotHandler);\r\n  loop_hook_add (this->oneShotLoop);\r\n  isOn = true;\r\n}\r\n\r\nvoid oneShotMods::off() {\r\n  if (!isOn)\r\n    return;\r\n\r\n  event_handler_hook_replace (this->oneShotHandler, this->passthoughHandler);\r\n  loop_hook_delete (this->oneShotLoop);\r\n  isOn = false;\r\n}\r\n```\r\n\r\nWhile here, it may make plugin authors' life more convenient, if the `_replace` stuff would delete if the second argument is `NULL`, and add, if the first one is. Why? Because then, we can introduce a helper:\r\n\r\n```c++\r\nvoid hooks_replace (custom_handler_t oldEvent, custom_handler_t newEvent,\r\n                    custom_loop_t oldLoop, custom_loop_t newLoop);\r\n```\r\n\r\nWith this, the above code could be simplified to:\r\n\r\n```c++\r\nvoid OneShotMods::on() {\r\n  if (isOn)\r\n    return;\r\n\r\n  hooks_replace (this->passthroughHandler, this->oneShotHandler,\r\n                 NULL, this->oneShotLoop);\r\n  isOn = true;\r\n}\r\n\r\nvoid oneShotMods::off() {\r\n  if (!isOn)\r\n    return;\r\n\r\n  hooks_replace (this->oneShotHandler, this->passthroughHandler,\r\n                 this->oneShotLoop, NULL);\r\n  isOn = false;\r\n}\r\n```\r\n\r\nWe could even have a `#define NO_HANDLER NULL` to make the code look even nicer."}}
{"actor":{"display_login":"obra"}}