├── .gitignore ├── README.md ├── generate_message.rb ├── keyboard ├── CMakeLists.txt ├── config │ └── example_config.yaml ├── package.xml ├── scripts │ └── keyboard_to_joy.py └── src │ └── keyboard.cpp └── keyboard_msgs ├── CMakeLists.txt ├── msg └── Key.msg └── package.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.geany 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ros2-keyboard 2 | 3 | This node uses the SDL library to grab keypresses. 4 | To do so, it opens a window where input is received. 5 | This window needs to becurrently focused, otherwise this node will not receive any key presses. 6 | 7 | # Install 8 | 9 | 1. Create a new workspace. 10 | 2. `$ cd /path/to/your_ws/src` 11 | 3. Clone this repository 12 | - (ssh) `$ git clone git@github.com:cmower/ros2-keyboard.git` 13 | - (https) `$ git clone https://github.com/cmower/ros2-keyboard.git` 14 | 4. Install SDL 1.2 with the command `sudo apt install libsdl1.2-dev`. 15 | 5. `$ cd /path/to/your_ws` 16 | 6. `$ colcon build` 17 | 18 | # Nodes 19 | 20 | ## `keyboard` 21 | 22 | Publishes keyboard events when the window is focused. 23 | 24 | * Published topics: `keydown` and `keyup` (`keyboard_msgs/Key`) 25 | * Parameters 26 | * `allow_repeat` (`bool`): Enables or disables the keyboard repeat rate. Default is `false`. 27 | * `repeat_delay` (`int`): How long the key must be pressed before it begins repeating. Default is `SDL_DEFAULT_REPEAT_DELAY`. 28 | * `repeat_interval` (`int`): Key replay speed. Default is `SDL_DEFAULT_REPEAT_INTERVAL`. 29 | 30 | ## `keyboard_to_joy.py` 31 | 32 | Converts keyboard events to a joy message. 33 | 34 | * Published topic: `joy` (`sensor_msgs/Joy`) 35 | * Subscribed topics: `keydown` and `keyup` (`keyboard_msgs/Key`) 36 | * Parameters 37 | * `config_file_name` (`str`): File name for the configuration file. See [here](keyboard/config/example_config.yaml) for an example. 38 | * `sampling_frequency` (`int`): Rate (Hz) at which `joy` messages are published. Default is `50`. 39 | 40 | ### Example: 41 | 42 | In one terminal, start the `keyboard` node. 43 | ```shell 44 | ros2 run keyboard keyboard 45 | ``` 46 | 47 | In a second terminal, start the `keyboard_to_joy.py` node. 48 | ```shell 49 | ros2 run keyboard keyboard_to_joy.py --ros-args \ 50 | -p config_file_name:=`ros2 pkg prefix keyboard`/share/keyboard/config/example_config.yaml 51 | ``` 52 | -------------------------------------------------------------------------------- /generate_message.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | keycodes = {} 4 | modifiers = {} 5 | File.open(ARGV.first,'r') {|f| 6 | lines = f.readlines 7 | lines.grep(/SDLK_.+=/).each {|l| l = l.split; keycodes[l[0]] = l[2].to_i} 8 | lines.grep(/KMOD_.*=/).each {|l| l = l.split(/[\s=]+/); modifiers[l[1]] = Integer(l[2].delete(','))} 9 | } 10 | 11 | puts keycodes.map{|k,v| k = k.gsub('SDLK', 'KEY'); "uint16 #{k}=#{v}"}.join("\n") 12 | puts modifiers.map{|k,v| k = k.gsub('KMOD', 'MODIFIER'); "uint16 #{k}=#{v}"}.join("\n") 13 | puts 14 | puts "Header header" 15 | puts "uint16 code" 16 | puts "uint16 modifiers" 17 | -------------------------------------------------------------------------------- /keyboard/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(keyboard) 3 | 4 | # Default to C99 5 | if(NOT CMAKE_C_STANDARD) 6 | set(CMAKE_C_STANDARD 99) 7 | endif() 8 | 9 | # Default to C++14 10 | if(NOT CMAKE_CXX_STANDARD) 11 | set(CMAKE_CXX_STANDARD 14) 12 | endif() 13 | 14 | # Default to release build 15 | if(NOT CMAKE_BUILD_TYPE) 16 | set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) 17 | endif() 18 | 19 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 20 | add_compile_options(-Wall -Wextra -Wpedantic) 21 | endif() 22 | 23 | # find dependencies 24 | find_package(ament_cmake REQUIRED) 25 | find_package(rclcpp REQUIRED) 26 | find_package(std_msgs REQUIRED) 27 | find_package(SDL REQUIRED) 28 | find_package(keyboard_msgs REQUIRED) 29 | 30 | add_executable(keyboard src/keyboard.cpp) 31 | ament_target_dependencies(keyboard rclcpp std_msgs keyboard_msgs) 32 | target_include_directories(keyboard 33 | PUBLIC 34 | $ 35 | $ 36 | PRIVATE 37 | ${SDL_INCLUDE_DIR} 38 | ) 39 | 40 | target_link_libraries(keyboard 41 | SDL 42 | ) 43 | 44 | 45 | install(TARGETS keyboard 46 | DESTINATION lib/${PROJECT_NAME}) 47 | 48 | install( 49 | PROGRAMS 50 | scripts/keyboard_to_joy.py 51 | DESTINATION lib/${PROJECT_NAME} 52 | ) 53 | 54 | install(DIRECTORY config 55 | DESTINATION share/${PROJECT_NAME} 56 | ) 57 | 58 | if(BUILD_TESTING) 59 | find_package(ament_lint_auto REQUIRED) 60 | # the following line skips the linter which checks for copyrights 61 | # uncomment the line when a copyright and license is not present in all source files 62 | #set(ament_cmake_copyright_FOUND TRUE) 63 | # the following line skips cpplint (only works in a git repo) 64 | # uncomment the line when this package is not in a git repo 65 | #set(ament_cmake_cpplint_FOUND TRUE) 66 | ament_lint_auto_find_test_dependencies() 67 | endif() 68 | 69 | ament_package() 70 | -------------------------------------------------------------------------------- /keyboard/config/example_config.yaml: -------------------------------------------------------------------------------- 1 | axes: 2 | - ["KEY_LEFT", "KEY_RIGHT"] 3 | - ["KEY_UP", "KEY_DOWN"] 4 | 5 | buttons: 6 | - "KEY_SPACE" 7 | -------------------------------------------------------------------------------- /keyboard/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | keyboard 5 | 1.0.0 6 | Publishes keyboard key presses to ROS 2. 7 | 8 | v01d 9 | 10 | cmower 11 | cmower 12 | 13 | 14 | GPLv2 15 | 16 | ament_cmake 17 | 18 | ament_lint_auto 19 | ament_lint_common 20 | 21 | rclcpp 22 | std_msgs 23 | keyboard_msgs 24 | 25 | 26 | ament_cmake 27 | 28 | 29 | -------------------------------------------------------------------------------- /keyboard/scripts/keyboard_to_joy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import abc 4 | 5 | import rclpy 6 | from rclpy import qos 7 | from rclpy.node import Node 8 | 9 | from sensor_msgs.msg import Joy 10 | from keyboard_msgs.msg import Key 11 | 12 | import yaml 13 | 14 | 15 | class JoyPart(abc.ABC): 16 | def __init__(self, init_value): 17 | self._value = init_value 18 | 19 | @abc.abstractmethod 20 | def down(self, code): 21 | pass 22 | 23 | @abc.abstractmethod 24 | def up(self, code): 25 | pass 26 | 27 | def get(self): 28 | return self._value 29 | 30 | 31 | class Button(JoyPart): 32 | def __init__(self, key_str): 33 | super().__init__(0) 34 | self.code = getattr(Key, key_str) 35 | 36 | def down(self, code): 37 | if code == self.code: 38 | self._value = 1 39 | 40 | def up(self, code): 41 | if code == self.code: 42 | self._value = 0 43 | 44 | 45 | class Axis(JoyPart): 46 | def __init__(self, key_neg_str, key_pos_str): 47 | super().__init__(0.0) 48 | self.code_neg = getattr(Key, key_neg_str) 49 | self.code_pos = getattr(Key, key_pos_str) 50 | 51 | def down(self, code): 52 | if code == self.code_neg: 53 | self._value -= 1.0 54 | 55 | elif code == self.code_pos: 56 | self._value += 1.0 57 | 58 | def up(self, code): 59 | if code == self.code_neg: 60 | self._value += 1.0 61 | 62 | elif code == self.code_pos: 63 | self._value -= 1.0 64 | 65 | 66 | class KeyboardToJoyNode(Node): 67 | def __init__(self): 68 | # Initialize ROS node 69 | super().__init__("keyboard_to_joy_node") 70 | 71 | # Get parameters 72 | self.declare_parameter("config_file_name") 73 | config_file_name = ( 74 | self.get_parameter("config_file_name").get_parameter_value().string_value 75 | ) 76 | 77 | self.declare_parameter("sampling_frequency", 50) 78 | hz = ( 79 | self.get_parameter("sampling_frequency").get_parameter_value().integer_value 80 | ) 81 | 82 | # Load config file 83 | with open(config_file_name, "rb") as configfile: 84 | self.config = yaml.load(configfile, Loader=yaml.FullLoader) 85 | 86 | self.buttons = [Button(key_str) for key_str in self.config.get("buttons", [])] 87 | self.axes = [ 88 | Axis(key_neg_str, key_pos_str) 89 | for key_neg_str, key_pos_str in self.config.get("axes", []) 90 | ] 91 | 92 | # Setup publisher 93 | self.joy = Joy() 94 | self.joy_pub = self.create_publisher(Joy, "joy", qos.qos_profile_system_default) 95 | 96 | # Keyboard callback 97 | self.keydown_sub = self.create_subscription( 98 | Key, "keydown", self.keydown_callback, qos.qos_profile_system_default 99 | ) 100 | self.keyup_sub = self.create_subscription( 101 | Key, "keyup", self.keyup_callback, qos.qos_profile_system_default 102 | ) 103 | 104 | # Start timer 105 | dt = 1.0 / float(hz) 106 | self.create_timer(dt, self.main_loop) 107 | 108 | def keydown_callback(self, msg): 109 | for part in self.axes + self.buttons: 110 | part.down(msg.code) 111 | 112 | def keyup_callback(self, msg): 113 | for part in self.axes + self.buttons: 114 | part.up(msg.code) 115 | 116 | def main_loop(self): 117 | msg = Joy( 118 | axes=[a.get() for a in self.axes], buttons=[b.get() for b in self.buttons] 119 | ) 120 | msg.header.stamp = self.get_clock().now().to_msg() 121 | self.joy_pub.publish(msg) 122 | 123 | 124 | def main(args=None): 125 | # Start node, and spin 126 | rclpy.init(args=args) 127 | node = KeyboardToJoyNode() 128 | 129 | try: 130 | rclpy.spin(node) 131 | except KeyboardInterrupt: 132 | pass 133 | finally: 134 | # Clean up and shutdown 135 | node.destroy_node() 136 | rclpy.shutdown() 137 | 138 | 139 | if __name__ == "__main__": 140 | main() 141 | -------------------------------------------------------------------------------- /keyboard/src/keyboard.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "rclcpp/rclcpp.hpp" 7 | 8 | #include 9 | #include 10 | 11 | using namespace std::chrono_literals; 12 | 13 | class KeyboardNode : public rclcpp::Node 14 | { 15 | public: 16 | KeyboardNode() : Node("keyboard_node") 17 | { 18 | pub_down = this->create_publisher("keydown", 10); 19 | pub_up = this->create_publisher("keyup", 10); 20 | timer = this->create_wall_timer(20ms, std::bind(&KeyboardNode::timer_callback, this)); 21 | 22 | this->declare_parameter("allow_repeat", false); 23 | bool allow_repeat = this->get_parameter("allow_repeat").as_bool(); 24 | 25 | this->declare_parameter("repeat_delay", SDL_DEFAULT_REPEAT_DELAY); 26 | int repeat_delay = this->get_parameter("repeat_delay").as_int(); 27 | 28 | this->declare_parameter("repeat_interval", SDL_DEFAULT_REPEAT_INTERVAL); 29 | int repeat_interval = this->get_parameter("repeat_interval").as_int(); 30 | 31 | 32 | if ( !allow_repeat ) repeat_delay=0; // disable 33 | if (SDL_Init(SDL_INIT_VIDEO) < 0) throw std::runtime_error("Could not init SDL"); 34 | SDL_EnableKeyRepeat( repeat_delay, repeat_interval ); 35 | SDL_WM_SetCaption("ROS keyboard input", NULL); 36 | window = SDL_SetVideoMode(100, 100, 0, 0); 37 | 38 | } 39 | 40 | private: 41 | void timer_callback() 42 | { 43 | 44 | keyboard_msgs::msg::Key k; 45 | bool pressed; 46 | 47 | bool new_event = false; 48 | 49 | SDL_Event event; 50 | if (SDL_PollEvent(&event)) { 51 | switch(event.type) { 52 | case SDL_KEYUP: 53 | pressed = false; 54 | k.code = event.key.keysym.sym; 55 | k.modifiers = event.key.keysym.mod; 56 | new_event = true; 57 | SDL_FillRect(window, NULL,SDL_MapRGB(window->format, k.code, 0, 0)); 58 | SDL_Flip(window); 59 | break; 60 | case SDL_KEYDOWN: 61 | pressed = true; 62 | k.code = event.key.keysym.sym; 63 | k.modifiers = event.key.keysym.mod; 64 | new_event = true; 65 | SDL_FillRect(window, NULL, SDL_MapRGB(window->format,k.code,0,255)); 66 | SDL_Flip(window); 67 | 68 | break; 69 | case SDL_QUIT: 70 | SDL_FreeSurface(window); 71 | SDL_Quit(); 72 | timer->cancel(); 73 | break; 74 | } 75 | } 76 | 77 | if (new_event) { 78 | k.header.stamp = this->get_clock()->now(); 79 | if (pressed) pub_down->publish(k); 80 | else pub_up->publish(k); 81 | } 82 | 83 | } 84 | rclcpp::TimerBase::SharedPtr timer; 85 | rclcpp::Publisher::SharedPtr pub_down; 86 | rclcpp::Publisher::SharedPtr pub_up; 87 | SDL_Surface* window; 88 | }; 89 | 90 | int main(int argc, char * argv[]) 91 | { 92 | rclcpp::init(argc, argv); 93 | rclcpp::spin(std::make_shared()); 94 | rclcpp::shutdown(); 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /keyboard_msgs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(keyboard_msgs) 3 | 4 | # Default to C99 5 | if(NOT CMAKE_C_STANDARD) 6 | set(CMAKE_C_STANDARD 99) 7 | endif() 8 | 9 | # Default to C++14 10 | if(NOT CMAKE_CXX_STANDARD) 11 | set(CMAKE_CXX_STANDARD 14) 12 | endif() 13 | 14 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 15 | add_compile_options(-Wall -Wextra -Wpedantic) 16 | endif() 17 | 18 | # find dependencies 19 | find_package(ament_cmake REQUIRED) 20 | find_package(std_msgs REQUIRED) 21 | find_package(rosidl_default_generators REQUIRED) 22 | 23 | # build messages 24 | rosidl_generate_interfaces(${PROJECT_NAME} 25 | "msg/Key.msg" 26 | DEPENDENCIES std_msgs 27 | ) 28 | 29 | if(BUILD_TESTING) 30 | find_package(ament_lint_auto REQUIRED) 31 | ament_lint_auto_find_test_dependencies() 32 | endif() 33 | 34 | ament_package() 35 | -------------------------------------------------------------------------------- /keyboard_msgs/msg/Key.msg: -------------------------------------------------------------------------------- 1 | uint16 KEY_UNKNOWN=0 2 | uint16 KEY_FIRST=0 3 | uint16 KEY_BACKSPACE=8 4 | uint16 KEY_TAB=9 5 | uint16 KEY_CLEAR=12 6 | uint16 KEY_RETURN=13 7 | uint16 KEY_PAUSE=19 8 | uint16 KEY_ESCAPE=27 9 | uint16 KEY_SPACE=32 10 | uint16 KEY_EXCLAIM=33 11 | uint16 KEY_QUOTEDBL=34 12 | uint16 KEY_HASH=35 13 | uint16 KEY_DOLLAR=36 14 | uint16 KEY_AMPERSAND=38 15 | uint16 KEY_QUOTE=39 16 | uint16 KEY_LEFTPAREN=40 17 | uint16 KEY_RIGHTPAREN=41 18 | uint16 KEY_ASTERISK=42 19 | uint16 KEY_PLUS=43 20 | uint16 KEY_COMMA=44 21 | uint16 KEY_MINUS=45 22 | uint16 KEY_PERIOD=46 23 | uint16 KEY_SLASH=47 24 | uint16 KEY_0=48 25 | uint16 KEY_1=49 26 | uint16 KEY_2=50 27 | uint16 KEY_3=51 28 | uint16 KEY_4=52 29 | uint16 KEY_5=53 30 | uint16 KEY_6=54 31 | uint16 KEY_7=55 32 | uint16 KEY_8=56 33 | uint16 KEY_9=57 34 | uint16 KEY_COLON=58 35 | uint16 KEY_SEMICOLON=59 36 | uint16 KEY_LESS=60 37 | uint16 KEY_EQUALS=61 38 | uint16 KEY_GREATER=62 39 | uint16 KEY_QUESTION=63 40 | uint16 KEY_AT=64 41 | uint16 KEY_LEFTBRACKET=91 42 | uint16 KEY_BACKSLASH=92 43 | uint16 KEY_RIGHTBRACKET=93 44 | uint16 KEY_CARET=94 45 | uint16 KEY_UNDERSCORE=95 46 | uint16 KEY_BACKQUOTE=96 47 | uint16 KEY_A=97 48 | uint16 KEY_B=98 49 | uint16 KEY_C=99 50 | uint16 KEY_D=100 51 | uint16 KEY_E=101 52 | uint16 KEY_F=102 53 | uint16 KEY_G=103 54 | uint16 KEY_H=104 55 | uint16 KEY_I=105 56 | uint16 KEY_J=106 57 | uint16 KEY_K=107 58 | uint16 KEY_L=108 59 | uint16 KEY_M=109 60 | uint16 KEY_N=110 61 | uint16 KEY_O=111 62 | uint16 KEY_P=112 63 | uint16 KEY_Q=113 64 | uint16 KEY_R=114 65 | uint16 KEY_S=115 66 | uint16 KEY_T=116 67 | uint16 KEY_U=117 68 | uint16 KEY_V=118 69 | uint16 KEY_W=119 70 | uint16 KEY_X=120 71 | uint16 KEY_Y=121 72 | uint16 KEY_Z=122 73 | uint16 KEY_DELETE=127 74 | uint16 KEY_WORLD_0=160 75 | uint16 KEY_WORLD_1=161 76 | uint16 KEY_WORLD_2=162 77 | uint16 KEY_WORLD_3=163 78 | uint16 KEY_WORLD_4=164 79 | uint16 KEY_WORLD_5=165 80 | uint16 KEY_WORLD_6=166 81 | uint16 KEY_WORLD_7=167 82 | uint16 KEY_WORLD_8=168 83 | uint16 KEY_WORLD_9=169 84 | uint16 KEY_WORLD_10=170 85 | uint16 KEY_WORLD_11=171 86 | uint16 KEY_WORLD_12=172 87 | uint16 KEY_WORLD_13=173 88 | uint16 KEY_WORLD_14=174 89 | uint16 KEY_WORLD_15=175 90 | uint16 KEY_WORLD_16=176 91 | uint16 KEY_WORLD_17=177 92 | uint16 KEY_WORLD_18=178 93 | uint16 KEY_WORLD_19=179 94 | uint16 KEY_WORLD_20=180 95 | uint16 KEY_WORLD_21=181 96 | uint16 KEY_WORLD_22=182 97 | uint16 KEY_WORLD_23=183 98 | uint16 KEY_WORLD_24=184 99 | uint16 KEY_WORLD_25=185 100 | uint16 KEY_WORLD_26=186 101 | uint16 KEY_WORLD_27=187 102 | uint16 KEY_WORLD_28=188 103 | uint16 KEY_WORLD_29=189 104 | uint16 KEY_WORLD_30=190 105 | uint16 KEY_WORLD_31=191 106 | uint16 KEY_WORLD_32=192 107 | uint16 KEY_WORLD_33=193 108 | uint16 KEY_WORLD_34=194 109 | uint16 KEY_WORLD_35=195 110 | uint16 KEY_WORLD_36=196 111 | uint16 KEY_WORLD_37=197 112 | uint16 KEY_WORLD_38=198 113 | uint16 KEY_WORLD_39=199 114 | uint16 KEY_WORLD_40=200 115 | uint16 KEY_WORLD_41=201 116 | uint16 KEY_WORLD_42=202 117 | uint16 KEY_WORLD_43=203 118 | uint16 KEY_WORLD_44=204 119 | uint16 KEY_WORLD_45=205 120 | uint16 KEY_WORLD_46=206 121 | uint16 KEY_WORLD_47=207 122 | uint16 KEY_WORLD_48=208 123 | uint16 KEY_WORLD_49=209 124 | uint16 KEY_WORLD_50=210 125 | uint16 KEY_WORLD_51=211 126 | uint16 KEY_WORLD_52=212 127 | uint16 KEY_WORLD_53=213 128 | uint16 KEY_WORLD_54=214 129 | uint16 KEY_WORLD_55=215 130 | uint16 KEY_WORLD_56=216 131 | uint16 KEY_WORLD_57=217 132 | uint16 KEY_WORLD_58=218 133 | uint16 KEY_WORLD_59=219 134 | uint16 KEY_WORLD_60=220 135 | uint16 KEY_WORLD_61=221 136 | uint16 KEY_WORLD_62=222 137 | uint16 KEY_WORLD_63=223 138 | uint16 KEY_WORLD_64=224 139 | uint16 KEY_WORLD_65=225 140 | uint16 KEY_WORLD_66=226 141 | uint16 KEY_WORLD_67=227 142 | uint16 KEY_WORLD_68=228 143 | uint16 KEY_WORLD_69=229 144 | uint16 KEY_WORLD_70=230 145 | uint16 KEY_WORLD_71=231 146 | uint16 KEY_WORLD_72=232 147 | uint16 KEY_WORLD_73=233 148 | uint16 KEY_WORLD_74=234 149 | uint16 KEY_WORLD_75=235 150 | uint16 KEY_WORLD_76=236 151 | uint16 KEY_WORLD_77=237 152 | uint16 KEY_WORLD_78=238 153 | uint16 KEY_WORLD_79=239 154 | uint16 KEY_WORLD_80=240 155 | uint16 KEY_WORLD_81=241 156 | uint16 KEY_WORLD_82=242 157 | uint16 KEY_WORLD_83=243 158 | uint16 KEY_WORLD_84=244 159 | uint16 KEY_WORLD_85=245 160 | uint16 KEY_WORLD_86=246 161 | uint16 KEY_WORLD_87=247 162 | uint16 KEY_WORLD_88=248 163 | uint16 KEY_WORLD_89=249 164 | uint16 KEY_WORLD_90=250 165 | uint16 KEY_WORLD_91=251 166 | uint16 KEY_WORLD_92=252 167 | uint16 KEY_WORLD_93=253 168 | uint16 KEY_WORLD_94=254 169 | uint16 KEY_WORLD_95=255 170 | uint16 KEY_KP0=256 171 | uint16 KEY_KP1=257 172 | uint16 KEY_KP2=258 173 | uint16 KEY_KP3=259 174 | uint16 KEY_KP4=260 175 | uint16 KEY_KP5=261 176 | uint16 KEY_KP6=262 177 | uint16 KEY_KP7=263 178 | uint16 KEY_KP8=264 179 | uint16 KEY_KP9=265 180 | uint16 KEY_KP_PERIOD=266 181 | uint16 KEY_KP_DIVIDE=267 182 | uint16 KEY_KP_MULTIPLY=268 183 | uint16 KEY_KP_MINUS=269 184 | uint16 KEY_KP_PLUS=270 185 | uint16 KEY_KP_ENTER=271 186 | uint16 KEY_KP_EQUALS=272 187 | uint16 KEY_UP=273 188 | uint16 KEY_DOWN=274 189 | uint16 KEY_RIGHT=275 190 | uint16 KEY_LEFT=276 191 | uint16 KEY_INSERT=277 192 | uint16 KEY_HOME=278 193 | uint16 KEY_END=279 194 | uint16 KEY_PAGEUP=280 195 | uint16 KEY_PAGEDOWN=281 196 | uint16 KEY_F1=282 197 | uint16 KEY_F2=283 198 | uint16 KEY_F3=284 199 | uint16 KEY_F4=285 200 | uint16 KEY_F5=286 201 | uint16 KEY_F6=287 202 | uint16 KEY_F7=288 203 | uint16 KEY_F8=289 204 | uint16 KEY_F9=290 205 | uint16 KEY_F10=291 206 | uint16 KEY_F11=292 207 | uint16 KEY_F12=293 208 | uint16 KEY_F13=294 209 | uint16 KEY_F14=295 210 | uint16 KEY_F15=296 211 | uint16 KEY_NUMLOCK=300 212 | uint16 KEY_CAPSLOCK=301 213 | uint16 KEY_SCROLLOCK=302 214 | uint16 KEY_RSHIFT=303 215 | uint16 KEY_LSHIFT=304 216 | uint16 KEY_RCTRL=305 217 | uint16 KEY_LCTRL=306 218 | uint16 KEY_RALT=307 219 | uint16 KEY_LALT=308 220 | uint16 KEY_RMETA=309 221 | uint16 KEY_LMETA=310 222 | uint16 KEY_LSUPER=311 223 | uint16 KEY_RSUPER=312 224 | uint16 KEY_MODE=313 225 | uint16 KEY_COMPOSE=314 226 | uint16 KEY_HELP=315 227 | uint16 KEY_PRINT=316 228 | uint16 KEY_SYSREQ=317 229 | uint16 KEY_BREAK=318 230 | uint16 KEY_MENU=319 231 | uint16 KEY_POWER=320 232 | uint16 KEY_EURO=321 233 | uint16 KEY_UNDO=322 234 | uint16 MODIFIER_NONE=0 235 | uint16 MODIFIER_LSHIFT=1 236 | uint16 MODIFIER_RSHIFT=2 237 | uint16 MODIFIER_LCTRL=64 238 | uint16 MODIFIER_RCTRL=128 239 | uint16 MODIFIER_LALT=256 240 | uint16 MODIFIER_RALT=512 241 | uint16 MODIFIER_LMETA=1024 242 | uint16 MODIFIER_RMETA=2048 243 | uint16 MODIFIER_NUM=4096 244 | uint16 MODIFIER_CAPS=8192 245 | uint16 MODIFIER_MODE=16384 246 | uint16 MODIFIER_RESERVED=32768 247 | 248 | std_msgs/Header header 249 | uint16 code 250 | uint16 modifiers 251 | -------------------------------------------------------------------------------- /keyboard_msgs/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | keyboard_msgs 5 | 1.0.0 6 | Keyboard message definitions. 7 | 8 | v01d 9 | 10 | cmower 11 | cmower 12 | 13 | GPLv2 14 | 15 | ament_cmake 16 | 17 | rosidl_default_generators 18 | rosidl_default_runtime 19 | rosidl_interface_packages 20 | 21 | std_msgs 22 | 23 | ament_lint_auto 24 | ament_lint_common 25 | 26 | 27 | ament_cmake 28 | 29 | 30 | --------------------------------------------------------------------------------