├── .gitignore
├── keyboard
├── config
│ └── example_config.yaml
├── package.xml
├── CMakeLists.txt
├── src
│ └── keyboard.cpp
└── scripts
│ └── keyboard_to_joy.py
├── generate_message.rb
├── keyboard_msgs
├── CMakeLists.txt
├── package.xml
└── msg
│ └── Key.msg
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | *.geany
2 |
--------------------------------------------------------------------------------
/keyboard/config/example_config.yaml:
--------------------------------------------------------------------------------
1 | axes:
2 | - ["KEY_LEFT", "KEY_RIGHT"]
3 | - ["KEY_UP", "KEY_DOWN"]
4 |
5 | buttons:
6 | - "KEY_SPACE"
7 |
--------------------------------------------------------------------------------
/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_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/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_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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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_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 |
--------------------------------------------------------------------------------