diff options
Diffstat (limited to 'helpers/mapping.py')
-rw-r--r-- | helpers/mapping.py | 209 |
1 files changed, 149 insertions, 60 deletions
diff --git a/helpers/mapping.py b/helpers/mapping.py index c2a94e6..6e3b291 100644 --- a/helpers/mapping.py +++ b/helpers/mapping.py | |||
@@ -6,10 +6,11 @@ from kivy.clock import Clock | |||
6 | import threading | 6 | import threading |
7 | import yaml | 7 | import yaml |
8 | import sys | 8 | import sys |
9 | from collections import defaultdict | ||
9 | 10 | ||
10 | from .music_file import * | 11 | from .music_file import MusicFile |
11 | from .mixer import Mixer | 12 | from .mixer import Mixer |
12 | from . import Config, gain, error_print | 13 | from . import Config, gain, error_print, warn_print |
13 | from .action import Action | 14 | from .action import Action |
14 | 15 | ||
15 | class Mapping(RelativeLayout): | 16 | class Mapping(RelativeLayout): |
@@ -26,7 +27,8 @@ class Mapping(RelativeLayout): | |||
26 | try: | 27 | try: |
27 | self.key_config, self.open_files = self.parse_config() | 28 | self.key_config, self.open_files = self.parse_config() |
28 | except Exception as e: | 29 | except Exception as e: |
29 | error_print("Error while loading configuration: {}".format(e)) | 30 | error_print("Error while loading configuration: {}".format(e), |
31 | with_trace=True) | ||
30 | sys.exit() | 32 | sys.exit() |
31 | 33 | ||
32 | super(Mapping, self).__init__(**kwargs) | 34 | super(Mapping, self).__init__(**kwargs) |
@@ -67,8 +69,9 @@ class Mapping(RelativeLayout): | |||
67 | def _on_keyboard_down(self, keyboard, keycode, text, modifiers): | 69 | def _on_keyboard_down(self, keyboard, keycode, text, modifiers): |
68 | key = self.find_by_key_code(keycode) | 70 | key = self.find_by_key_code(keycode) |
69 | if len(modifiers) == 0 and key is not None: | 71 | if len(modifiers) == 0 and key is not None: |
70 | threading.Thread(name="MSKeyAction", target=key.do_actions).start() | 72 | threading.Thread(name="MSKeyAction", target=key.run).start() |
71 | elif 'ctrl' in modifiers and (keycode[0] == 113 or keycode[0] == '99'): | 73 | elif 'ctrl' in modifiers and (keycode[0] == 113 or keycode[0] == '99'): |
74 | self.stop_all_running() | ||
72 | for thread in threading.enumerate(): | 75 | for thread in threading.enumerate(): |
73 | if thread.getName()[0:2] != "MS": | 76 | if thread.getName()[0:2] != "MS": |
74 | continue | 77 | continue |
@@ -86,7 +89,7 @@ class Mapping(RelativeLayout): | |||
86 | for key in self.children: | 89 | for key in self.children: |
87 | if not type(key).__name__ == "Key": | 90 | if not type(key).__name__ == "Key": |
88 | continue | 91 | continue |
89 | if not key.is_key_ready: | 92 | if not key.is_loaded_or_failed(): |
90 | return True | 93 | return True |
91 | self.ready_color = [0, 1, 0, 1] | 94 | self.ready_color = [0, 1, 0, 1] |
92 | return False | 95 | return False |
@@ -95,7 +98,7 @@ class Mapping(RelativeLayout): | |||
95 | running = self.running | 98 | running = self.running |
96 | self.running = [] | 99 | self.running = [] |
97 | for (key, start_time) in running: | 100 | for (key, start_time) in running: |
98 | key.interrupt_action() | 101 | key.interrupt() |
99 | 102 | ||
100 | def start_running(self, key, start_time): | 103 | def start_running(self, key, start_time): |
101 | self.running.append((key, start_time)) | 104 | self.running.append((key, start_time)) |
@@ -108,85 +111,171 @@ class Mapping(RelativeLayout): | |||
108 | self.running.remove((key, start_time)) | 111 | self.running.remove((key, start_time)) |
109 | 112 | ||
110 | def parse_config(self): | 113 | def parse_config(self): |
114 | def update_alias(prop_hash, aliases, key): | ||
115 | if isinstance(aliases[key], dict): | ||
116 | prop_hash.update(aliases[key], **prop_hash) | ||
117 | else: | ||
118 | warn_print("Alias {} is not a hash, ignored".format(key)) | ||
119 | |||
120 | def include_aliases(prop_hash, aliases): | ||
121 | if 'include' not in prop_hash: | ||
122 | return | ||
123 | |||
124 | included = prop_hash['include'] | ||
125 | del(prop_hash['include']) | ||
126 | if isinstance(included, str): | ||
127 | update_alias(prop_hash, aliases, included) | ||
128 | elif isinstance(included, list): | ||
129 | for included_ in included: | ||
130 | if isinstance(included_, str): | ||
131 | update_alias(prop_hash, aliases, included_) | ||
132 | else: | ||
133 | warn_print("Unkown alias include type, ignored: " | ||
134 | "{} in {}".format(included_, included)) | ||
135 | else: | ||
136 | warn_print("Unkown alias include type, ignored: {}" | ||
137 | .format(included)) | ||
138 | |||
139 | def check_key_property(key_property, key): | ||
140 | if 'description' in key_property: | ||
141 | desc = key_property['description'] | ||
142 | if not isinstance(desc, list): | ||
143 | warn_print("description in key_property '{}' is not " | ||
144 | "a list, ignored".format(key)) | ||
145 | del(key_property['description']) | ||
146 | if 'color' in key_property: | ||
147 | color = key_property['color'] | ||
148 | if not isinstance(color, list)\ | ||
149 | or len(color) != 3\ | ||
150 | or not all(isinstance(item, int) for item in color)\ | ||
151 | or any(item < 0 or item > 255 for item in color): | ||
152 | warn_print("color in key_property '{}' is not " | ||
153 | "a list of 3 valid integers, ignored".format(key)) | ||
154 | del(key_property['color']) | ||
155 | |||
156 | def check_key_properties(config): | ||
157 | if 'key_properties' in config: | ||
158 | if isinstance(config['key_properties'], dict): | ||
159 | return config['key_properties'] | ||
160 | else: | ||
161 | warn_print("key_properties config is not a hash, ignored") | ||
162 | return {} | ||
163 | else: | ||
164 | return {} | ||
165 | |||
166 | def check_mapped_keys(config): | ||
167 | if 'keys' in config: | ||
168 | if isinstance(config['keys'], dict): | ||
169 | return config['keys'] | ||
170 | else: | ||
171 | warn_print("keys config is not a hash, ignored") | ||
172 | return {} | ||
173 | else: | ||
174 | return {} | ||
175 | |||
176 | def check_mapped_key(mapped_keys, key): | ||
177 | if not isinstance(mapped_keys[key], list): | ||
178 | warn_print("key config '{}' is not an array, ignored" | ||
179 | .format(key)) | ||
180 | return [] | ||
181 | else: | ||
182 | return mapped_keys[key] | ||
183 | |||
184 | def check_music_property(music_property, filename): | ||
185 | if not isinstance(music_property, dict): | ||
186 | warn_print("music_property config '{}' is not a hash, ignored" | ||
187 | .format(filename)) | ||
188 | return {} | ||
189 | if 'name' in music_property: | ||
190 | music_property['name'] = str(music_property['name']) | ||
191 | if 'gain' in music_property: | ||
192 | try: | ||
193 | music_property['gain'] = float(music_property['gain']) | ||
194 | except ValueError as e: | ||
195 | del(music_property['gain']) | ||
196 | warn_print("gain for music_property '{}' is not " | ||
197 | "a float, ignored".format(filename)) | ||
198 | return music_property | ||
199 | |||
111 | stream = open(Config.yml_file, "r") | 200 | stream = open(Config.yml_file, "r") |
112 | try: | 201 | try: |
113 | config = yaml.load(stream) | 202 | config = yaml.safe_load(stream) |
114 | except Exception as e: | 203 | except Exception as e: |
115 | error_print("Error while loading config file: {}".format(e)) | 204 | error_print("Error while loading config file: {}".format(e)) |
116 | sys.exit() | 205 | sys.exit() |
117 | stream.close() | 206 | stream.close() |
118 | 207 | ||
119 | aliases = config['aliases'] | 208 | if not isinstance(config, dict): |
209 | raise Exception("Top level config is supposed to be a hash") | ||
210 | |||
211 | if 'aliases' in config and isinstance(config['aliases'], dict): | ||
212 | aliases = config['aliases'] | ||
213 | else: | ||
214 | aliases = defaultdict(dict) | ||
215 | if 'aliases' in config: | ||
216 | warn_print("aliases config is not a hash, ignored") | ||
217 | |||
218 | music_properties = defaultdict(dict) | ||
219 | if 'music_properties' in config and\ | ||
220 | isinstance(config['music_properties'], dict): | ||
221 | music_properties.update(config['music_properties']) | ||
222 | elif 'music_properties' in config: | ||
223 | warn_print("music_properties config is not a hash, ignored") | ||
224 | |||
120 | seen_files = {} | 225 | seen_files = {} |
121 | 226 | ||
122 | key_properties = {} | 227 | key_properties = defaultdict(lambda: { |
228 | "actions": [], | ||
229 | "properties": {}, | ||
230 | "files": [] | ||
231 | }) | ||
123 | 232 | ||
124 | for key in config['key_properties']: | 233 | for key in check_key_properties(config): |
125 | if key not in key_properties: | 234 | key_prop = config['key_properties'][key] |
126 | key_prop = config['key_properties'][key] | 235 | |
127 | if 'include' in key_prop: | 236 | if not isinstance(key_prop, dict): |
128 | included = key_prop['include'] | 237 | warn_print("key_property '{}' is not a hash, ignored" |
129 | del(key_prop['include']) | 238 | .format(key)) |
239 | continue | ||
240 | |||
241 | include_aliases(key_prop, aliases) | ||
242 | check_key_property(key_prop, key) | ||
243 | |||
244 | key_properties[key]["properties"] = key_prop | ||
245 | |||
246 | for mapped_key in check_mapped_keys(config): | ||
247 | for index, action in enumerate(check_mapped_key( | ||
248 | config['keys'], mapped_key)): | ||
249 | if not isinstance(action, dict) or\ | ||
250 | not len(action) == 1 or\ | ||
251 | not isinstance(list(action.values())[0] or {}, dict): | ||
252 | warn_print("action number {} of key '{}' is invalid, " | ||
253 | "ignored".format(index + 1, mapped_key)) | ||
254 | continue | ||
130 | 255 | ||
131 | if isinstance(included, str): | ||
132 | key_prop.update(aliases[included], **key_prop) | ||
133 | else: | ||
134 | for included_ in included: | ||
135 | key_prop.update(aliases[included_], **key_prop) | ||
136 | |||
137 | key_properties[key] = { | ||
138 | "actions": [], | ||
139 | "properties": key_prop, | ||
140 | "files": [] | ||
141 | } | ||
142 | |||
143 | for mapped_key in config['keys']: | ||
144 | if mapped_key not in key_properties: | ||
145 | key_properties[mapped_key] = { | ||
146 | "actions": [], | ||
147 | "properties": {}, | ||
148 | "files": [] | ||
149 | } | ||
150 | for action in config['keys'][mapped_key]: | ||
151 | action_name = list(action)[0] | 256 | action_name = list(action)[0] |
152 | action_args = {} | 257 | action_args = {} |
153 | if action[action_name] is None: | 258 | if action[action_name] is None: |
154 | action[action_name] = [] | 259 | action[action_name] = {} |
155 | |||
156 | if 'include' in action[action_name]: | ||
157 | included = action[action_name]['include'] | ||
158 | del(action[action_name]['include']) | ||
159 | 260 | ||
160 | if isinstance(included, str): | 261 | include_aliases(action[action_name], aliases) |
161 | action[action_name].update( | ||
162 | aliases[included], | ||
163 | **action[action_name]) | ||
164 | else: | ||
165 | for included_ in included: | ||
166 | action[action_name].update( | ||
167 | aliases[included_], | ||
168 | **action[action_name]) | ||
169 | 262 | ||
170 | for argument in action[action_name]: | 263 | for argument in action[action_name]: |
171 | if argument == 'file': | 264 | if argument == 'file': |
172 | filename = action[action_name]['file'] | 265 | filename = str(action[action_name]['file']) |
173 | if filename not in seen_files: | 266 | if filename not in seen_files: |
174 | if filename in config['music_properties']: | 267 | music_property = check_music_property( |
175 | seen_files[filename] = MusicFile( | 268 | music_properties[filename], |
176 | filename, | 269 | filename) |
177 | self, | 270 | |
178 | **config['music_properties'][filename]) | 271 | seen_files[filename] = MusicFile( |
179 | else: | 272 | filename, self, **music_property) |
180 | seen_files[filename] = MusicFile( | ||
181 | self, | ||
182 | filename) | ||
183 | 273 | ||
184 | if filename not in key_properties[mapped_key]['files']: | 274 | if filename not in key_properties[mapped_key]['files']: |
185 | key_properties[mapped_key]['files'] \ | 275 | key_properties[mapped_key]['files'] \ |
186 | .append(seen_files[filename]) | 276 | .append(seen_files[filename]) |
187 | 277 | ||
188 | action_args['music'] = seen_files[filename] | 278 | action_args['music'] = seen_files[filename] |
189 | |||
190 | else: | 279 | else: |
191 | action_args[argument] = action[action_name][argument] | 280 | action_args[argument] = action[action_name][argument] |
192 | 281 | ||