diff options
-rw-r--r-- | fonts/Ubuntu-B.ttf | bin | 0 -> 333612 bytes | |||
-rw-r--r-- | helpers/__init__.py | 76 | ||||
-rw-r--r-- | helpers/action.py | 4 | ||||
-rw-r--r-- | keyboard.py | 222 | ||||
-rw-r--r-- | musicsampler.kv | 743 |
5 files changed, 1042 insertions, 3 deletions
diff --git a/fonts/Ubuntu-B.ttf b/fonts/Ubuntu-B.ttf new file mode 100644 index 0000000..b173da2 --- /dev/null +++ b/fonts/Ubuntu-B.ttf | |||
Binary files differ | |||
diff --git a/helpers/__init__.py b/helpers/__init__.py index 7fe9c35..eb948f2 100644 --- a/helpers/__init__.py +++ b/helpers/__init__.py | |||
@@ -5,6 +5,80 @@ from .lock import * | |||
5 | from .font import * | 5 | from .font import * |
6 | import yaml | 6 | import yaml |
7 | 7 | ||
8 | def parse_config2(): | ||
9 | stream = open("config.yml", "r") | ||
10 | config = yaml.load(stream) | ||
11 | stream.close() | ||
12 | |||
13 | aliases = config['aliases'] | ||
14 | seen_files = {} | ||
15 | |||
16 | file_lock = Lock("file") | ||
17 | |||
18 | channel_id = 0 | ||
19 | |||
20 | key_properties = {} | ||
21 | |||
22 | for key in config['key_properties']: | ||
23 | if key not in key_properties: | ||
24 | key_properties[key] = { | ||
25 | "actions": [], | ||
26 | "properties": config['key_properties'][key], | ||
27 | "files": [] | ||
28 | } | ||
29 | |||
30 | for mapped_key in config['keys']: | ||
31 | if mapped_key not in key_properties: | ||
32 | key_properties[mapped_key] = { | ||
33 | "actions": [], | ||
34 | "properties": {}, | ||
35 | "files": [] | ||
36 | } | ||
37 | for action in config['keys'][mapped_key]: | ||
38 | action_name = list(action)[0] | ||
39 | action_args = {} | ||
40 | if action[action_name] is None: | ||
41 | action[action_name] = [] | ||
42 | |||
43 | if 'include' in action[action_name]: | ||
44 | included = action[action_name]['include'] | ||
45 | del(action[action_name]['include']) | ||
46 | |||
47 | if isinstance(included, str): | ||
48 | action[action_name].update(aliases[included], **action[action_name]) | ||
49 | else: | ||
50 | for included_ in included: | ||
51 | action[action_name].update(aliases[included_], **action[action_name]) | ||
52 | |||
53 | for argument in action[action_name]: | ||
54 | if argument == 'file': | ||
55 | filename = action[action_name]['file'] | ||
56 | if filename not in seen_files: | ||
57 | if filename in config['music_properties']: | ||
58 | seen_files[filename] = MusicFile( | ||
59 | filename, | ||
60 | file_lock, | ||
61 | channel_id, | ||
62 | **config['music_properties'][filename]) | ||
63 | else: | ||
64 | seen_files[filename] = MusicFile( | ||
65 | filename, | ||
66 | file_lock, | ||
67 | channel_id) | ||
68 | channel_id = channel_id + 1 | ||
69 | |||
70 | if filename not in key_properties[mapped_key]['files']: | ||
71 | key_properties[mapped_key]['files'].append(seen_files[filename]) | ||
72 | |||
73 | action_args['music'] = seen_files[filename] | ||
74 | |||
75 | else: | ||
76 | action_args[argument] = action[action_name][argument] | ||
77 | |||
78 | key_properties[mapped_key]['actions'].append([action_name, action_args]) | ||
79 | |||
80 | return (key_properties, channel_id + 1, seen_files) | ||
81 | |||
8 | def parse_config(mapping): | 82 | def parse_config(mapping): |
9 | stream = open("config.yml", "r") | 83 | stream = open("config.yml", "r") |
10 | config = yaml.load(stream) | 84 | config = yaml.load(stream) |
@@ -46,7 +120,7 @@ def parse_config(mapping): | |||
46 | seen_files[filename] = MusicFile( | 120 | seen_files[filename] = MusicFile( |
47 | filename, | 121 | filename, |
48 | file_lock, | 122 | file_lock, |
49 | channel_id, | 123 | channel_id, |
50 | **config['music_properties'][filename]) | 124 | **config['music_properties'][filename]) |
51 | else: | 125 | else: |
52 | seen_files[filename] = MusicFile( | 126 | seen_files[filename] = MusicFile( |
diff --git a/helpers/action.py b/helpers/action.py index d4c6252..aff61e7 100644 --- a/helpers/action.py +++ b/helpers/action.py | |||
@@ -31,7 +31,7 @@ class Action: | |||
31 | def run(self): | 31 | def run(self): |
32 | print(self.description()) | 32 | print(self.description()) |
33 | getattr(self, self.action)(**self.arguments) | 33 | getattr(self, self.action)(**self.arguments) |
34 | pygame.event.post(pygame.event.Event(pygame.USEREVENT)) | 34 | #pygame.event.post(pygame.event.Event(pygame.USEREVENT)) |
35 | 35 | ||
36 | def description(self): | 36 | def description(self): |
37 | return getattr(self, self.action + "_print")(**self.arguments) | 37 | return getattr(self, self.action + "_print")(**self.arguments) |
@@ -74,7 +74,7 @@ class Action: | |||
74 | pygame.mixer.stop() | 74 | pygame.mixer.stop() |
75 | 75 | ||
76 | def stop_all_actions(self, **kwargs): | 76 | def stop_all_actions(self, **kwargs): |
77 | self.key.mapping.stop_all_running() | 77 | self.key.parent.stop_all_running() |
78 | 78 | ||
79 | def volume(self, music = None, value = 100, **kwargs): | 79 | def volume(self, music = None, value = 100, **kwargs): |
80 | if music is not None: | 80 | if music is not None: |
diff --git a/keyboard.py b/keyboard.py new file mode 100644 index 0000000..0c1115f --- /dev/null +++ b/keyboard.py | |||
@@ -0,0 +1,222 @@ | |||
1 | from kivy.app import App | ||
2 | from kivy.uix.widget import Widget | ||
3 | from kivy.uix.floatlayout import FloatLayout | ||
4 | from kivy.uix.relativelayout import RelativeLayout | ||
5 | from kivy.properties import AliasProperty, ReferenceListProperty, BooleanProperty, NumericProperty, ListProperty, StringProperty, ObjectProperty | ||
6 | from kivy.vector import Vector | ||
7 | from kivy.clock import Clock | ||
8 | from kivy.uix.behaviors import ButtonBehavior | ||
9 | from kivy.uix.label import Label | ||
10 | from kivy.core.window import Window | ||
11 | |||
12 | from helpers.action import * | ||
13 | import time | ||
14 | import sys | ||
15 | import math | ||
16 | import pygame | ||
17 | import helpers | ||
18 | import threading | ||
19 | |||
20 | class KeyDescription(Label): | ||
21 | pass | ||
22 | |||
23 | class Key(ButtonBehavior, Widget): | ||
24 | key_sym = StringProperty(None) | ||
25 | custom_color = ListProperty([0, 1, 0, 1]) | ||
26 | custom_unready_color = ListProperty([0, 1, 0, 100/255]) | ||
27 | description_title = StringProperty("") | ||
28 | description = ListProperty([]) | ||
29 | is_key_ready = BooleanProperty(True) | ||
30 | |||
31 | def get_color(self): | ||
32 | if not self.has_actions: | ||
33 | return [1, 1, 1, 1] | ||
34 | elif self.all_actions_ready: | ||
35 | return self.custom_color | ||
36 | else: | ||
37 | return self.custom_unready_color | ||
38 | def set_color(self): | ||
39 | pass | ||
40 | |||
41 | color = AliasProperty(get_color, set_color, bind=['is_key_ready']) | ||
42 | |||
43 | def __init__(self, **kwargs): | ||
44 | super(Key, self).__init__(**kwargs) | ||
45 | self.actions = [] | ||
46 | |||
47 | def on_key_sym(self, key, key_sym): | ||
48 | if key_sym in self.parent.key_config: | ||
49 | self.is_key_ready = False | ||
50 | |||
51 | self.config = self.parent.key_config[key_sym] | ||
52 | |||
53 | self.actions = [] | ||
54 | for key_action in self.config['actions']: | ||
55 | self.add_action(key_action[0], **key_action[1]) | ||
56 | |||
57 | if 'description' in self.config['properties']: | ||
58 | key.set_description(self.config['properties']['description']) | ||
59 | if 'color' in self.config['properties']: | ||
60 | key.set_color(self.config['properties']['color']) | ||
61 | |||
62 | Clock.schedule_interval(self.check_all_active, 1) | ||
63 | |||
64 | def check_all_active(self, dt): | ||
65 | if self.all_actions_ready: | ||
66 | self.is_key_ready = True | ||
67 | return False | ||
68 | |||
69 | def set_description(self, description): | ||
70 | if description[0] is not None: | ||
71 | self.description_title = str(description[0]) | ||
72 | for desc in description[1:]: | ||
73 | if desc is None: | ||
74 | self.description.append("") | ||
75 | else: | ||
76 | self.description.append(str(desc).replace(" ", " ")) | ||
77 | |||
78 | def set_color(self, color): | ||
79 | color = [x / 255 for x in color] | ||
80 | color.append(1) | ||
81 | self.custom_color = color | ||
82 | color[3] = 100 / 255 | ||
83 | self.custom_unready_color = tuple(color) | ||
84 | |||
85 | @property | ||
86 | def has_actions(self): | ||
87 | return len(self.actions) > 0 | ||
88 | |||
89 | @property | ||
90 | def all_actions_ready(self): | ||
91 | return all(action.ready() for action in self.actions) | ||
92 | |||
93 | def add_action(self, action_name, **arguments): | ||
94 | self.actions.append(Action(action_name, self, **arguments)) | ||
95 | |||
96 | def do_actions(self): | ||
97 | print("running actions for {}".format(self.key_sym)) | ||
98 | start_time = time.time() | ||
99 | self.parent.start_running(self, start_time) | ||
100 | action_number = 0 | ||
101 | for action in self.actions: | ||
102 | if self.parent.keep_running(self, start_time): | ||
103 | self.list_actions(action_number = action_number + 0.5) | ||
104 | action.run() | ||
105 | action_number += 1 | ||
106 | self.list_actions(action_number = action_number) | ||
107 | |||
108 | self.parent.finished_running(self, start_time) | ||
109 | |||
110 | def list_actions(self, action_number = 0): | ||
111 | self.parent.parent.ids['ActionList'].update_list(self, action_number) | ||
112 | |||
113 | def on_press(self): | ||
114 | self.list_actions() | ||
115 | pass | ||
116 | |||
117 | class PlayList(RelativeLayout): | ||
118 | playlist = ListProperty([]) | ||
119 | |||
120 | def __init__(self, **kwargs): | ||
121 | super(PlayList, self).__init__(**kwargs) | ||
122 | Clock.schedule_interval(self.update_playlist, 0.5) | ||
123 | |||
124 | def update_playlist(self, dt): | ||
125 | if self.parent is None or 'Mapping' not in self.parent.ids: | ||
126 | return True | ||
127 | |||
128 | open_files = self.parent.ids['Mapping'].open_files | ||
129 | self.playlist = [] | ||
130 | for music_file in open_files.values(): | ||
131 | if not music_file.is_playing(): | ||
132 | continue | ||
133 | if music_file.is_paused(): | ||
134 | self.playlist.append(["⏸", music_file.name, False]) | ||
135 | else: | ||
136 | self.playlist.append(["⏵", music_file.name, True]) | ||
137 | |||
138 | |||
139 | class ActionList(RelativeLayout): | ||
140 | action_title = StringProperty("") | ||
141 | action_list = ListProperty([]) | ||
142 | |||
143 | def update_list(self, key, action_number = 0): | ||
144 | self.action_title = "actions linked to key {}:".format(key.key_sym) | ||
145 | self.action_list = [] | ||
146 | |||
147 | action_descriptions = [action.description() for action in key.actions] | ||
148 | |||
149 | for index, description in enumerate(action_descriptions): | ||
150 | if index < int(action_number): | ||
151 | icon = "✓" | ||
152 | elif index + 0.5 == action_number: | ||
153 | icon = "✅" | ||
154 | else: | ||
155 | icon = " " | ||
156 | |||
157 | self.action_list.append([icon, description]) | ||
158 | |||
159 | class Mapping(RelativeLayout): | ||
160 | expected_keys = NumericProperty(0) | ||
161 | |||
162 | def __init__(self, **kwargs): | ||
163 | self.key_config, self.channel_number, self.open_files = helpers.parse_config2() | ||
164 | super(Mapping, self).__init__(**kwargs) | ||
165 | self._keyboard = Window.request_keyboard(self._keyboard_closed, self) | ||
166 | self._keyboard.bind(on_key_down=self._on_keyboard_down) | ||
167 | self.running = [] | ||
168 | |||
169 | |||
170 | pygame.mixer.init(frequency = 44100) | ||
171 | pygame.mixer.set_num_channels(self.channel_number) | ||
172 | |||
173 | def _keyboard_closed(self): | ||
174 | self._keyboard.unbind(on_key_down=self._on_keyboard_down) | ||
175 | self._keyboard = None | ||
176 | |||
177 | def _on_keyboard_down(self, keyboard, keycode, text, modifiers): | ||
178 | key = self.find_by_key_code(keycode) | ||
179 | if key is not None: | ||
180 | threading.Thread(name = "MSKeyAction", target=key.do_actions).start() | ||
181 | return True | ||
182 | |||
183 | def find_by_key_code(self, key_code): | ||
184 | if "Key_" + str(key_code[0]) in self.ids: | ||
185 | return self.ids["Key_" + str(key_code[0])] | ||
186 | return None | ||
187 | |||
188 | def find_by_unicode(self, key_sym): | ||
189 | for key in self.children: | ||
190 | if not type(key).__name__ == "Key": | ||
191 | continue | ||
192 | print(key.key_sym, key_sym) | ||
193 | if key.key_sym == key_sym: | ||
194 | print("found") | ||
195 | return key | ||
196 | return None | ||
197 | |||
198 | def stop_all_running(self): | ||
199 | self.running = [] | ||
200 | |||
201 | def start_running(self, key, start_time): | ||
202 | self.running.append((key, start_time)) | ||
203 | |||
204 | def keep_running(self, key, start_time): | ||
205 | return (key, start_time) in self.running | ||
206 | |||
207 | def finished_running(self, key, start_time): | ||
208 | if (key, start_time) in self.running: | ||
209 | self.running.remove((key, start_time)) | ||
210 | |||
211 | |||
212 | class Screen(FloatLayout): | ||
213 | pass | ||
214 | |||
215 | class MusicSamplerApp(App): | ||
216 | def build(self): | ||
217 | Window.size = (913, 563) | ||
218 | |||
219 | return Screen() | ||
220 | |||
221 | if __name__ == '__main__': | ||
222 | MusicSamplerApp().run() | ||
diff --git a/musicsampler.kv b/musicsampler.kv new file mode 100644 index 0000000..3c1964b --- /dev/null +++ b/musicsampler.kv | |||
@@ -0,0 +1,743 @@ | |||
1 | #:import math math | ||
2 | |||
3 | <Key>: | ||
4 | pad_col_sep: 0 if not self.pad_cols else self.parent.pad_x | ||
5 | pad_cols: False | ||
6 | |||
7 | y: (self.parent.top-self.parent.y) - (self.row) * self.parent.key_size - (self.row - 1) * self.parent.key_sep | ||
8 | x: (self.col - 1) * self.parent.key_size + int(self.col - 1) * self.parent.key_sep + self.pad_col_sep | ||
9 | size_hint: None, None | ||
10 | line_color: 120/255, 120/255, 120/255, 1 | ||
11 | enabled: True | ||
12 | line_width: 2 | ||
13 | row: 1 | ||
14 | col: 0 | ||
15 | key_code: 0 | ||
16 | key_sym: "" | ||
17 | key_width: 1 | ||
18 | key_height: 1 | ||
19 | width: self.key_width * (self.parent.key_size + self.parent.key_sep) - self.parent.key_sep | ||
20 | height: self.key_height * (self.parent.key_size + self.parent.key_sep) - self.parent.key_sep | ||
21 | canvas.before: | ||
22 | Color: | ||
23 | rgba: self.color | ||
24 | RoundedRectangle: | ||
25 | pos: self.x, self.y | ||
26 | size: self.size | ||
27 | canvas: | ||
28 | Color: | ||
29 | rgba: self.line_color | ||
30 | Line: | ||
31 | rounded_rectangle: self.x + self.line_width, self.y + self.line_width, self.width - 2 * self.line_width, self.height - 2 * self.line_width, 10 | ||
32 | width: self.line_width | ||
33 | Label: | ||
34 | id: key_label | ||
35 | font_name: "fonts/Ubuntu-B.ttf" | ||
36 | font_size: math.ceil(2 * math.sqrt(self.parent.parent.key_size)) | ||
37 | color: 0, 0, 0, 1 | ||
38 | text: self.parent.key_sym | ||
39 | text_size: self.parent.width,self.font_size | ||
40 | shorten: True | ||
41 | shorten_from: "right" | ||
42 | split_str: "" | ||
43 | center_x: self.parent.x + self.texture_size[0] /2 + 5 | ||
44 | center_y: self.parent.y + self.parent.height - self.texture_size[1] /2 - 5 | ||
45 | Label: | ||
46 | id: key_description_title | ||
47 | font_name: "fonts/Ubuntu-Regular.ttf" | ||
48 | font_size: math.ceil(2 * math.sqrt(self.parent.parent.key_size / 2)) | ||
49 | color: 0, 0, 0, 1 | ||
50 | text: self.parent.description_title | ||
51 | text_size: self.parent.width - 2*self.parent.line_width, self.font_size | ||
52 | halign: "right" | ||
53 | valign: "middle" | ||
54 | center_x: self.parent.x + self.texture_size[0] /2 | ||
55 | center_y: self.parent.y + self.parent.height - self.texture_size[1] /2 - 5 | ||
56 | Label: | ||
57 | id: key_description | ||
58 | font_name: "fonts/Ubuntu-Regular.ttf" | ||
59 | font_size: math.ceil(2 * math.sqrt(self.parent.parent.key_size / 2)) | ||
60 | color: 0, 0, 0, 1 | ||
61 | text: "\n".join(self.parent.description) | ||
62 | text_size: 2 * self.parent.width,self.parent.height - key_label.font_size | ||
63 | halign: "left" | ||
64 | valign: "middle" | ||
65 | pos: self.parent.x + 2 * self.parent.line_width + 2, self.parent.y | ||
66 | size_hint: None, None | ||
67 | size: 2 * self.parent.width - 2 * self.parent.line_width, self.parent.height - key_label.font_size | ||
68 | |||
69 | <Screen>: | ||
70 | key_size: int( (3 * self.width - 16) / 56) | ||
71 | key_sep: int( self.key_size / 24) | ||
72 | key_pad_sep: int( self.key_size / 7) + 1 | ||
73 | |||
74 | border: (self.width - self.key_size * 18 - self.key_sep * 16 - self.key_pad_sep)/ 2 | ||
75 | |||
76 | mapping_height: self.key_size * 6 + self.key_sep * 5 | ||
77 | mapping_width: self.key_size * 18 + self.key_sep * 16 + self.key_pad_sep | ||
78 | mapping_x: self.border | ||
79 | mapping_y: self.top - self.mapping_height - self.border | ||
80 | action_list_height: self.height - self.mapping_height - 3 * self.border | ||
81 | action_list_width: 3 * self.width / 4 | ||
82 | action_list_x: self.border | ||
83 | action_list_y: self.border | ||
84 | play_list_height: self.action_list_height | ||
85 | play_list_width: self.width - self.action_list_width - 3* self.border | ||
86 | play_list_y: self.border | ||
87 | play_list_x: self.action_list_width + 2 * self.border | ||
88 | |||
89 | Mapping: | ||
90 | id: Mapping | ||
91 | pos: self.parent.mapping_x, self.parent.mapping_y | ||
92 | size: self.parent.mapping_width, self.parent.mapping_height | ||
93 | |||
94 | key_size: self.parent.key_size | ||
95 | key_sep: self.parent.key_sep | ||
96 | key_pad_sep: self.parent.key_pad_sep | ||
97 | pad_x: self.key_size * 15 + 14 * self.key_sep + self.key_pad_sep | ||
98 | ActionList: | ||
99 | id: ActionList | ||
100 | pos: self.parent.action_list_x, self.parent.action_list_y | ||
101 | size: self.parent.action_list_width, self.parent.action_list_height | ||
102 | PlayList: | ||
103 | id: PlayList | ||
104 | pos: self.parent.play_list_x, self.parent.play_list_y | ||
105 | size: self.parent.play_list_width, self.parent.play_list_height | ||
106 | |||
107 | <ActionList>: | ||
108 | size_hint: None, None | ||
109 | canvas: | ||
110 | Color: | ||
111 | rgba: 250./255, 250./255, 250./255, 1 | ||
112 | Rectangle: | ||
113 | pos: 0, 0 | ||
114 | size: self.width, self.height | ||
115 | Label: | ||
116 | id: action_list_title | ||
117 | font_name: "fonts/Ubuntu-B.ttf" | ||
118 | font_size: math.ceil(2 * math.sqrt(self.parent.parent.key_size or 10)) | ||
119 | color: 0, 0, 0, 1 | ||
120 | text: self.parent.action_title | ||
121 | text_size: None, self.parent.height | ||
122 | halign: "left" | ||
123 | valign: "top" | ||
124 | size_hint: None, None | ||
125 | size: self.texture_size[0], self.parent.height | ||
126 | Label: | ||
127 | id: action_list_icons | ||
128 | font_name: "fonts/Symbola.ttf" | ||
129 | font_size: math.ceil(2 * math.sqrt(self.parent.parent.key_size or 10)) | ||
130 | line_height: 1.2 # FIXME: Donner la bonne taille de label | ||
131 | color: 0, 0, 0, 1 | ||
132 | text: "\n".join(map(lambda x: x[0], self.parent.action_list)) | ||
133 | text_size: None, self.parent.height | ||
134 | halign: "left" | ||
135 | valign: "top" | ||
136 | size_hint: None, None | ||
137 | size: self.texture_size[0], self.parent.height - 3 * self.line_height * self.font_size | ||
138 | Label: | ||
139 | id: action_list_names | ||
140 | font_name: "fonts/Ubuntu-Regular.ttf" | ||
141 | font_size: math.ceil(2 * math.sqrt(self.parent.parent.key_size or 10)) | ||
142 | color: 0, 0, 0, 1 | ||
143 | text: "\n".join(map(lambda x: x[1], self.parent.action_list)) | ||
144 | text_size: None, self.parent.height | ||
145 | halign: "left" | ||
146 | valign: "top" | ||
147 | size_hint: None, None | ||
148 | pos: 15, self.y | ||
149 | size: self.texture_size[0], self.parent.height - 3 * self.line_height * self.font_size | ||
150 | |||
151 | <PlayList>: | ||
152 | size_hint: None, None | ||
153 | canvas: | ||
154 | Color: | ||
155 | rgba: 250./255, 250./255, 250./255, 1 | ||
156 | Rectangle: | ||
157 | pos: 0, 0 | ||
158 | size: self.width, self.height | ||
159 | Label: | ||
160 | id: playlist_icons | ||
161 | font_name: "fonts/Symbola.ttf" | ||
162 | font_size: math.ceil(2 * math.sqrt(self.parent.parent.key_size or 10)) | ||
163 | line_height: 1.2 # FIXME: Donner la bonne taille de label | ||
164 | color: 0, 0, 0, 1 | ||
165 | text: "\n".join(map(lambda x: x[0], self.parent.playlist)) | ||
166 | text_size: None, self.parent.height | ||
167 | halign: "left" | ||
168 | valign: "top" | ||
169 | size_hint: None, None | ||
170 | size: self.texture_size[0], self.parent.height | ||
171 | Label: | ||
172 | id: playlist_names | ||
173 | font_name: "fonts/Ubuntu-Regular.ttf" # FIXME: Mettre en gras quand c'est en cours | ||
174 | font_size: math.ceil(2 * math.sqrt(self.parent.parent.key_size or 10)) | ||
175 | color: 0, 0, 0, 1 | ||
176 | text: "\n".join(map(lambda x: x[1], self.parent.playlist)) | ||
177 | text_size: None, self.parent.height | ||
178 | halign: "left" | ||
179 | valign: "top" | ||
180 | size_hint: None, None | ||
181 | pos: 15, self.y | ||
182 | size: self.texture_size[0], self.parent.height | ||
183 | |||
184 | <Mapping>: | ||
185 | size_hint: None, None | ||
186 | key_size: 48 | ||
187 | key_sep: 2 | ||
188 | key_pad_sep: 7 | ||
189 | pad_x: 755 | ||
190 | canvas: | ||
191 | Color: | ||
192 | rgba: 250./255, 250./255, 250./255, 1 | ||
193 | Rectangle: | ||
194 | pos: 0, 0 | ||
195 | size: self.width, self.height | ||
196 | Key: | ||
197 | id: Key_27 | ||
198 | key_code: 27 | ||
199 | key_sym: "ESC" | ||
200 | row: 1 | ||
201 | col: 1 | ||
202 | Key: | ||
203 | id: Key_282 | ||
204 | key_code: 282 | ||
205 | key_sym: "F1" | ||
206 | row: 1 | ||
207 | col: 3 | ||
208 | Key: | ||
209 | id: Key_283 | ||
210 | key_code: 283 | ||
211 | key_sym: "F2" | ||
212 | row: 1 | ||
213 | col: 4 | ||
214 | Key: | ||
215 | id: Key_284 | ||
216 | key_code: 284 | ||
217 | key_sym: "F3" | ||
218 | row: 1 | ||
219 | col: 5 | ||
220 | Key: | ||
221 | id: Key_285 | ||
222 | key_code: 285 | ||
223 | key_sym: "F4" | ||
224 | row: 1 | ||
225 | col: 6 | ||
226 | |||
227 | Key: | ||
228 | id: Key_286 | ||
229 | key_code: 286 | ||
230 | key_sym: "F5" | ||
231 | row: 1 | ||
232 | col: 7.5 | ||
233 | Key: | ||
234 | id: Key_287 | ||
235 | key_code: 287 | ||
236 | key_sym: "F6" | ||
237 | row: 1 | ||
238 | col: 8.5 | ||
239 | Key: | ||
240 | id: Key_288 | ||
241 | key_code: 288 | ||
242 | key_sym: "F7" | ||
243 | row: 1 | ||
244 | col: 9.5 | ||
245 | Key: | ||
246 | id: Key_289 | ||
247 | key_code: 289 | ||
248 | key_sym: "F8" | ||
249 | row: 1 | ||
250 | col: 10.5 | ||
251 | |||
252 | Key: | ||
253 | id: Key_290 | ||
254 | key_code: 290 | ||
255 | key_sym: "F9" | ||
256 | row: 1 | ||
257 | col: 12 | ||
258 | Key: | ||
259 | id: Key_291 | ||
260 | key_code: 291 | ||
261 | key_sym: "F10" | ||
262 | row: 1 | ||
263 | col: 13 | ||
264 | Key: | ||
265 | id: Key_292 | ||
266 | key_code: 292 | ||
267 | key_sym: "F11" | ||
268 | row: 1 | ||
269 | col: 14 | ||
270 | Key: | ||
271 | id: Key_293 | ||
272 | key_code: 293 | ||
273 | key_sym: "F12" | ||
274 | row: 1 | ||
275 | col: 15 | ||
276 | |||
277 | Key: | ||
278 | id: Key_178 | ||
279 | key_code: 178 | ||
280 | key_sym: "²" | ||
281 | row: 2 | ||
282 | col: 1 | ||
283 | Key: | ||
284 | id: Key_38 | ||
285 | key_code: 38 | ||
286 | key_sym: "&" | ||
287 | row: 2 | ||
288 | col: 2 | ||
289 | Key: | ||
290 | id: Key_233 | ||
291 | key_code: 233 | ||
292 | key_sym: "é" | ||
293 | row: 2 | ||
294 | col: 3 | ||
295 | Key: | ||
296 | id: Key_34 | ||
297 | key_code: 34 | ||
298 | key_sym: '"' | ||
299 | row: 2 | ||
300 | col: 4 | ||
301 | Key: | ||
302 | id: Key_39 | ||
303 | key_code: 39 | ||
304 | key_sym: "'" | ||
305 | row: 2 | ||
306 | col: 5 | ||
307 | Key: | ||
308 | id: Key_40 | ||
309 | key_code: 40 | ||
310 | key_sym: "(" | ||
311 | row: 2 | ||
312 | col: 6 | ||
313 | Key: | ||
314 | id: Key_45 | ||
315 | key_code: 45 | ||
316 | key_sym: "-" | ||
317 | row: 2 | ||
318 | col: 7 | ||
319 | Key: | ||
320 | id: Key_232 | ||
321 | key_code: 232 | ||
322 | key_sym: "è" | ||
323 | row: 2 | ||
324 | col: 8 | ||
325 | Key: | ||
326 | id: Key_95 | ||
327 | key_code: 95 | ||
328 | key_sym: "_" | ||
329 | row: 2 | ||
330 | col: 9 | ||
331 | Key: | ||
332 | id: Key_231 | ||
333 | key_code: 231 | ||
334 | key_sym: "ç" | ||
335 | row: 2 | ||
336 | col: 10 | ||
337 | Key: | ||
338 | id: Key_224 | ||
339 | key_code: 224 | ||
340 | key_sym: "à" | ||
341 | row: 2 | ||
342 | col: 11 | ||
343 | Key: | ||
344 | id: Key_41 | ||
345 | key_code: 41 | ||
346 | key_sym: ")" | ||
347 | row: 2 | ||
348 | col: 12 | ||
349 | Key: | ||
350 | id: Key_61 | ||
351 | key_code: 61 | ||
352 | key_sym: "=" | ||
353 | row: 2 | ||
354 | col: 13 | ||
355 | Key: | ||
356 | id: Key_8 | ||
357 | key_code: 8 | ||
358 | key_sym: "<-" | ||
359 | row: 2 | ||
360 | col: 14 | ||
361 | key_width: 2 | ||
362 | Key: | ||
363 | id: Key_9 | ||
364 | key_code: 9 | ||
365 | key_sym: "tab" | ||
366 | row: 3 | ||
367 | col: 1 | ||
368 | key_width: 1.48 | ||
369 | Key: | ||
370 | id: Key_97 | ||
371 | key_code: 97 | ||
372 | key_sym: "a" | ||
373 | row: 3 | ||
374 | col: 2.5 | ||
375 | Key: | ||
376 | id: Key_122 | ||
377 | key_code: 122 | ||
378 | key_sym: "z" | ||
379 | row: 3 | ||
380 | col: 3.5 | ||
381 | Key: | ||
382 | id: Key_101 | ||
383 | key_code: 101 | ||
384 | key_sym: "e" | ||
385 | row: 3 | ||
386 | col: 4.5 | ||
387 | Key: | ||
388 | id: Key_114 | ||
389 | key_code: 114 | ||
390 | key_sym: "r" | ||
391 | row: 3 | ||
392 | col: 5.5 | ||
393 | Key: | ||
394 | id: Key_116 | ||
395 | key_code: 116 | ||
396 | key_sym: "t" | ||
397 | row: 3 | ||
398 | col: 6.5 | ||
399 | Key: | ||
400 | id: Key_121 | ||
401 | key_code: 121 | ||
402 | key_sym: "y" | ||
403 | row: 3 | ||
404 | col: 7.5 | ||
405 | Key: | ||
406 | id: Key_117 | ||
407 | key_code: 117 | ||
408 | key_sym: "u" | ||
409 | row: 3 | ||
410 | col: 8.5 | ||
411 | Key: | ||
412 | id: Key_105 | ||
413 | key_code: 105 | ||
414 | key_sym: "i" | ||
415 | row: 3 | ||
416 | col: 9.5 | ||
417 | Key: | ||
418 | id: Key_111 | ||
419 | key_code: 111 | ||
420 | key_sym: "o" | ||
421 | row: 3 | ||
422 | col: 10.5 | ||
423 | Key: | ||
424 | id: Key_112 | ||
425 | key_code: 112 | ||
426 | key_sym: "p" | ||
427 | row: 3 | ||
428 | col: 11.5 | ||
429 | Key: | ||
430 | id: Key_94 | ||
431 | key_code: 94 | ||
432 | key_sym: "^" | ||
433 | row: 3 | ||
434 | col: 12.5 | ||
435 | Key: | ||
436 | id: Key_36 | ||
437 | key_code: 36 | ||
438 | key_sym: "$" | ||
439 | row: 3 | ||
440 | col: 13.5 | ||
441 | Key: | ||
442 | id: Key_13 | ||
443 | key_code: 13 | ||
444 | key_sym: "Enter" | ||
445 | row: 4 | ||
446 | col: 14.8 | ||
447 | key_width: 1.23 | ||
448 | key_height: 2 | ||
449 | Key: | ||
450 | id: Key_301 | ||
451 | key_code: 301 | ||
452 | key_sym: "CAPS" | ||
453 | row: 4 | ||
454 | col: 1 | ||
455 | key_width: 1.75 | ||
456 | line_width: 1 | ||
457 | enabled: False | ||
458 | |||
459 | Key: | ||
460 | id: Key_113 | ||
461 | key_code: 113 | ||
462 | key_sym: "q" | ||
463 | row: 4 | ||
464 | col: 2.8 | ||
465 | Key: | ||
466 | id: Key_115 | ||
467 | key_code: 115 | ||
468 | key_sym: "s" | ||
469 | row: 4 | ||
470 | col: 3.8 | ||
471 | Key: | ||
472 | id: Key_100 | ||
473 | key_code: 100 | ||
474 | key_sym: "d" | ||
475 | row: 4 | ||
476 | col: 4.8 | ||
477 | Key: | ||
478 | id: Key_102 | ||
479 | key_code: 102 | ||
480 | key_sym: "f" | ||
481 | row: 4 | ||
482 | col: 5.8 | ||
483 | Key: | ||
484 | id: Key_103 | ||
485 | key_code: 103 | ||
486 | key_sym: "g" | ||
487 | row: 4 | ||
488 | col: 6.8 | ||
489 | Key: | ||
490 | id: Key_104 | ||
491 | key_code: 104 | ||
492 | key_sym: "h" | ||
493 | row: 4 | ||
494 | col: 7.8 | ||
495 | Key: | ||
496 | id: Key_106 | ||
497 | key_code: 106 | ||
498 | key_sym: "j" | ||
499 | row: 4 | ||
500 | col: 8.8 | ||
501 | Key: | ||
502 | id: Key_107 | ||
503 | key_code: 107 | ||
504 | key_sym: "k" | ||
505 | row: 4 | ||
506 | col: 9.8 | ||
507 | Key: | ||
508 | id: Key_108 | ||
509 | key_code: 108 | ||
510 | key_sym: "l" | ||
511 | row: 4 | ||
512 | col: 10.8 | ||
513 | Key: | ||
514 | id: Key_109 | ||
515 | key_code: 109 | ||
516 | key_sym: "m" | ||
517 | row: 4 | ||
518 | col: 11.8 | ||
519 | Key: | ||
520 | id: Key_249 | ||
521 | key_code: 249 | ||
522 | key_sym: "ù" | ||
523 | row: 4 | ||
524 | col: 12.8 | ||
525 | Key: | ||
526 | id: Key_42 | ||
527 | key_code: 42 | ||
528 | key_sym: "*" | ||
529 | row: 4 | ||
530 | col: 13.8 | ||
531 | Key: | ||
532 | id: Key_304 | ||
533 | key_code: 304 | ||
534 | key_sym: "LShift" | ||
535 | row: 5 | ||
536 | col: 1 | ||
537 | key_width: 1.3 | ||
538 | line_width: 1 | ||
539 | enabled: False | ||
540 | Key: | ||
541 | id: Key_60 | ||
542 | key_code: 60 | ||
543 | key_sym: "<" | ||
544 | row: 5 | ||
545 | col: 2.3 | ||
546 | Key: | ||
547 | id: Key_119 | ||
548 | key_code: 119 | ||
549 | key_sym: "w" | ||
550 | row: 5 | ||
551 | col: 3.3 | ||
552 | Key: | ||
553 | id: Key_120 | ||
554 | key_code: 120 | ||
555 | key_sym: "x" | ||
556 | row: 5 | ||
557 | col: 4.3 | ||
558 | Key: | ||
559 | id: Key_99 | ||
560 | key_code: 99 | ||
561 | key_sym: "c" | ||
562 | row: 5 | ||
563 | col: 5.3 | ||
564 | Key: | ||
565 | id: Key_118 | ||
566 | key_code: 118 | ||
567 | key_sym: "v" | ||
568 | row: 5 | ||
569 | col: 6.3 | ||
570 | Key: | ||
571 | id: Key_98 | ||
572 | key_code: 98 | ||
573 | key_sym: "b" | ||
574 | row: 5 | ||
575 | col: 7.3 | ||
576 | Key: | ||
577 | id: Key_110 | ||
578 | key_code: 110 | ||
579 | key_sym: "n" | ||
580 | row: 5 | ||
581 | col: 8.3 | ||
582 | Key: | ||
583 | id: Key_44 | ||
584 | key_code: 44 | ||
585 | key_sym: "," | ||
586 | row: 5 | ||
587 | col: 9.3 | ||
588 | Key: | ||
589 | id: Key_59 | ||
590 | key_code: 59 | ||
591 | key_sym: ";" | ||
592 | row: 5 | ||
593 | col: 10.3 | ||
594 | Key: | ||
595 | id: Key_58 | ||
596 | key_code: 58 | ||
597 | key_sym: ":" | ||
598 | row: 5 | ||
599 | col: 11.3 | ||
600 | Key: | ||
601 | id: Key_33 | ||
602 | key_code: 33 | ||
603 | key_sym: "!" | ||
604 | row: 5 | ||
605 | col: 12.3 | ||
606 | Key: | ||
607 | id: Key_303 | ||
608 | key_code: 303 | ||
609 | key_sym: "RShift" | ||
610 | row: 5 | ||
611 | col: 13.3 | ||
612 | key_width: 2.7 | ||
613 | line_width: 1 | ||
614 | enabled: False | ||
615 | Key: | ||
616 | id: Key_306 | ||
617 | key_code: 306 | ||
618 | key_sym: "LCtrl" | ||
619 | row: 6 | ||
620 | col: 1 | ||
621 | key_width: 1.3 | ||
622 | line_width: 1 | ||
623 | enabled: False | ||
624 | Key: | ||
625 | id: Key_311 | ||
626 | key_code: 311 | ||
627 | key_sym: "LSuper" | ||
628 | row: 6 | ||
629 | col: 3.3 | ||
630 | line_width: 1 | ||
631 | enabled: False | ||
632 | Key: | ||
633 | id: Key_308 | ||
634 | key_code: 308 | ||
635 | key_sym: "LAlt" | ||
636 | row: 6 | ||
637 | col: 4.3 | ||
638 | line_width: 1 | ||
639 | enabled: False | ||
640 | Key: | ||
641 | id: Key_32 | ||
642 | key_code: 32 | ||
643 | key_sym: "Espace" | ||
644 | row: 6 | ||
645 | col: 5.3 | ||
646 | key_width: 5 | ||
647 | Key: | ||
648 | id: Key_313 | ||
649 | key_code: 313 | ||
650 | key_sym: "AltGr" | ||
651 | row: 6 | ||
652 | col: 10.3 | ||
653 | line_width: 1 | ||
654 | enabled: False | ||
655 | Key: | ||
656 | id: Key_314 | ||
657 | key_code: 314 | ||
658 | key_sym: "Compose" | ||
659 | row: 6 | ||
660 | col: 11.3 | ||
661 | line_width: 1 | ||
662 | enabled: False | ||
663 | Key: | ||
664 | id: Key_305 | ||
665 | key_code: 305 | ||
666 | key_sym: "RCtrl" | ||
667 | row: 6 | ||
668 | col: 12.3 | ||
669 | key_width: 1.3 | ||
670 | line_width: 1 | ||
671 | enabled: False | ||
672 | |||
673 | |||
674 | Key: | ||
675 | id: Key_277 | ||
676 | key_code: 277 | ||
677 | key_sym: "ins" | ||
678 | row: 2 | ||
679 | col: 1 | ||
680 | pad_cols: True | ||
681 | Key: | ||
682 | id: Key_278 | ||
683 | key_code: 278 | ||
684 | key_sym: "home" | ||
685 | row: 2 | ||
686 | col: 2 | ||
687 | pad_cols: True | ||
688 | Key: | ||
689 | id: Key_280 | ||
690 | key_code: 280 | ||
691 | key_sym: "pg_u" | ||
692 | row: 2 | ||
693 | col: 3 | ||
694 | pad_cols: True | ||
695 | Key: | ||
696 | id: Key_127 | ||
697 | key_code: 127 | ||
698 | key_sym: "del" | ||
699 | row: 3 | ||
700 | col: 1 | ||
701 | pad_cols: True | ||
702 | Key: | ||
703 | id: Key_279 | ||
704 | key_code: 279 | ||
705 | key_sym: "end" | ||
706 | row: 3 | ||
707 | col: 2 | ||
708 | pad_cols: True | ||
709 | Key: | ||
710 | id: Key_281 | ||
711 | key_code: 281 | ||
712 | key_sym: "pg_d" | ||
713 | row: 3 | ||
714 | col: 3 | ||
715 | pad_cols: True | ||
716 | Key: | ||
717 | id: Key_273 | ||
718 | key_code: 273 | ||
719 | key_sym: "up" | ||
720 | row: 5 | ||
721 | col: 2 | ||
722 | pad_cols: True | ||
723 | Key: | ||
724 | id: Key_274 | ||
725 | key_code: 274 | ||
726 | key_sym: "down" | ||
727 | row: 6 | ||
728 | col: 2 | ||
729 | pad_cols: True | ||
730 | Key: | ||
731 | id: Key_276 | ||
732 | key_code: 276 | ||
733 | key_sym: "left" | ||
734 | row: 6 | ||
735 | col: 1 | ||
736 | pad_cols: True | ||
737 | Key: | ||
738 | id: Key_275 | ||
739 | key_code: 275 | ||
740 | key_sym: "right" | ||
741 | row: 6 | ||
742 | col: 3 | ||
743 | pad_cols: True | ||