13 from pyfbsdk_additions
import *
21 def UIValue(key, mods):
23 return "%s : %s" % (mods, key)
28 class Mapping(object):
29 def __init__(self,action,key="", mods="", time = "DN"):
31 self.mods = self.edit_mods = mods
32 self.key = self.edit_key = key
38 return "{%s:%s*%s}" % (self.mods,self.key,self.time)
44 return UIValue(self.key,self.mods)
47 def MappingsToShortcut(mappings):
49 for i, mapping
in enumerate(mappings):
50 value = mapping.FileValue()
57 MOD_TO_ID = {
"NONE" : 0,
"SHFT" : 1,
"CTRL" : 2,
"ALT" : 4,
"ALCT" : 6,
"ALSH" : 5,
"CTSH" : 3,
"ALCTSH" : 7 }
59 KEY_TO_ID = {
"NONE" : -1,
60 "ESC" : 0x1b,
"TAB" : 0x09,
"CAPS" : 0x14,
"BKSP" : 0x08,
"LBR" : 0xdb,
"RBR" : 0xdd,
"SEMI" : 0xba,
"ENTR" : 0x0d,
61 "SPC" : 0x20,
"PRNT" : 0x2c,
"SCRL" : 0x91,
"PAUS" : 0x13,
"INS" : 0x2d,
"HOME" : 0x24,
"PGUP" : 0x21,
"DEL" : 0x2e,
62 "END" : 0x1b,
"PGDN" : 0x1b,
"UP" : 0x1b,
"LEFT" : 0x1b,
"DOWN" : 0x1b,
"RGHT" : 0x1b,
63 "F1" : 0x70,
"F2" : 0x71 ,
"F3" : 0x72,
"F4" : 0x73,
"F5" : 0x74,
"F6" : 0x75,
"F7" : 0x76,
"F8" : 0x77,
"F9" : 0x78,
"F10" : 0x79 ,
"F11" : 0x7a,
"F12" : 0x7b,
64 "NUML" : 0x90,
"NMUL" : 0x6a,
"NADD" : 0x6b,
"NDIV" : 0x6f,
"NSUB" : 0x6d,
"NDEC" : 0x6e ,
"N0" : 0x60,
"N1" : 0x61,
"N2" : 0x62,
"N3" : 0x63,
"N4" : 0x64,
"N5" : 0x65,
"N6" : 0x66,
"N7" : 0x67 ,
"N8" : 0x68,
"N9" : 0x69,
65 "'" : 0xde,
"," : 0xbc,
"-" : 0xbd,
"/" : 0xbf,
"=" : 0xbb ,
"." : 0xbe,
"\\" : 0xdc,
"`" : 0xc0,
66 "0" : 48,
"1" : 49,
"2" : 50,
"3" : 51,
"4" : 52,
"5" : 53 ,
"6" : 54,
"7" : 55,
"8" : 56,
"9" : 59,
67 "A" : 65,
"B" : 66,
"C" : 67,
"D" : 68,
"E" : 69,
"F" : 70 ,
"G" : 71,
"H" : 72,
"I" : 73,
68 "J" : 74,
"K" : 75,
"L" : 76,
"M" : 77,
"N" : 78,
"O" : 79,
"P" : 80,
"Q" : 81,
"R" : 82 ,
69 "S" : 83,
"T" : 84,
"U" : 85, "V" : 86, "W" : 87,"X" : 88, "Y" : 89, "Z" : 90
73 for key, i
in KEY_TO_ID.iteritems():
77 for key, i
in MOD_TO_ID.iteritems():
80 class KeyboardMapper(object):
82 def GetMappingFromShortcut(self,key,mods,mappings = None):
85 mappings = self.row_to_mapping
86 for mapping
in mappings:
87 if key
and key == mapping.key
and mapping.mods == mods:
91 def OnShortcut(self,control,event):
93 if event.InputType == FBInputType.kFBKeyPressRaw
and event.Key != -1
and self.edit_mapping:
95 self.edit_mapping.edit_key = ID_TO_KEY[event.Key]
96 self.edit_mapping.edit_mods = ID_TO_MOD[event.KeyState]
98 shortcut = UIValue(self.edit_mapping.edit_key,self.edit_mapping.edit_mods)
99 self.shortcut_edit.Text = shortcut
101 self.conflict_mapping = self.GetMappingFromShortcut(self.edit_mapping.edit_key,self.edit_mapping.edit_mods)
102 if self.conflict_mapping:
103 self.conflict_edit.Text = self.conflict_mapping.action
105 self.conflict_edit.Text =
""
107 def UpdateEditMapping(self,row):
109 if self.shortcut_spread.GetRow(row).RowSelected:
110 mapping = self.row_to_mapping[row]
111 self.action_edit.Text = mapping.action
112 self.shortcut_edit.Text = mapping.UIValue()
113 self.edit_mapping = mapping
119 self.edit_mapping =
None
120 self.action_edit.Text =
""
121 self.shortcut_edit.Text =
""
122 self.conflict_mapping =
None
123 self.conflict_edit.Text =
""
126 def RowClicked(self,control,event):
128 self.UpdateEditMapping(event.Row)
130 def OnKeyboardChange(self,control,event):
134 if self.row_to_mapping:
135 self.shortcut_spread.Clear()
136 self.shortcut_spread.ColumnAdd(
"Shortcut")
137 self.mapping_to_row = {}
138 self.row_to_mapping = []
139 self.action_to_mappings = {}
142 config = mbutils.OpenConfigFile(self.keyboard_files[self.file_list.ItemIndex])
146 items = config.items(
"Actions")
147 items.sort(key =
lambda pair : pair[0] )
149 for action, shortcut
in items:
150 mappings = self.ParseShortcut(action, shortcut)
152 for i, mapping
in enumerate(mappings):
154 self.shortcut_spread.RowAdd(
"", rowref)
156 self.shortcut_spread.RowAdd(action, rowref)
159 self.row_to_mapping.append(mapping)
160 self.mapping_to_row[mapping] = rowref
161 self.shortcut_spread.SetCellValue(rowref, 0, mapping.UIValue())
165 def ParseShortcut(self,action, desc_string):
168 desclist = desc_string.split(
"|")
169 for desc
in desclist:
171 keystr = desc.strip(
"{}")
172 mod_keytime = keystr.split(
":")
173 key_time = mod_keytime[1].split(
"*")
174 mapping = Mapping(action,key_time[0],mod_keytime[0],key_time[1])
176 mapping = Mapping(action)
178 self.action_to_mappings[action] = l
181 def Assign(self,control,event):
183 if not self.edit_mapping:
186 action_mappings = self.action_to_mappings[self.edit_mapping.action]
188 if self.GetMappingFromShortcut(self.edit_mapping.edit_key,self.edit_mapping.edit_mods,action_mappings):
192 self.edit_mapping.key = self.edit_mapping.edit_key
193 self.edit_mapping.mods = self.edit_mapping.edit_mods
196 self.shortcut_spread.SetCellValue(self.mapping_to_row[self.edit_mapping], 0, self.edit_mapping.UIValue())
199 self.WriteEditMapping()
201 def WriteEditMapping(self,update_conflict = True):
203 keyboard_dir, keyboard_file = os.path.split(self.keyboard_files[self.file_list.ItemIndex])
205 config.Set(
"Actions",self.edit_mapping.action,MappingsToShortcut(self.action_to_mappings[self.edit_mapping.action]))
208 if self.conflict_mapping:
209 self.conflict_mapping.key =
""
210 self.conflict_mapping.mods =
""
212 self.shortcut_spread.SetCellValue(self.mapping_to_row[self.conflict_mapping], 0,
"")
213 config.Set(
"Actions",self.conflict_mapping.action,MappingsToShortcut(self.action_to_mappings[self.conflict_mapping.action]))
214 self.conflict_edit.Text =
""
216 def Remove(self,control,event):
218 if not self.edit_mapping:
220 row = self.mapping_to_row[self.edit_mapping]
223 self.edit_mapping.key =
""
224 self.edit_mapping.mods =
""
225 self.shortcut_edit.Text =
""
227 self.WriteEditMapping(
False)
230 self.OnKeyboardChange(
None,
None)
232 if row > len(self.row_to_mapping):
233 row = len(self.row_to_mapping) - 1
234 self.shortcut_spread.GetRow(row).RowSelected =
True
236 self.UpdateEditMapping(row)
239 def Add(self,control,event):
241 if not self.edit_mapping:
244 action_mappings = self.action_to_mappings[self.edit_mapping.action]
247 if self.GetMappingFromShortcut(self.edit_mapping.edit_key,self.edit_mapping.edit_mods,action_mappings):
250 row = self.mapping_to_row[action_mappings[0]] + len(action_mappings)
253 mapping = Mapping(self.edit_mapping.action,self.edit_mapping.edit_key,self.edit_mapping.edit_mods)
254 self.edit_mapping = mapping
255 action_mappings.append(mapping)
256 self.WriteEditMapping(
True)
259 self.OnKeyboardChange(
None,
None)
261 if row > len(self.row_to_mapping):
262 row = len(self.row_to_mapping) - 1
263 self.shortcut_spread.GetRow(row).RowSelected =
True
265 self.UpdateEditMapping(row)
271 def ClosePopup(self,control, event):
272 self.popup.Close(
True)
279 self.popup.Caption =
"Keyboard Mapper"
280 self.popup.Modal =
True
285 self.popup.AddRegion(
"main",
"main", x,y,w,h)
286 self.popup.Left = 300
288 self.popup.Width = 650
289 self.popup.Height = 500
292 self.popup.SetControl(
"main",grid)
300 l.Caption =
"Keyboard files"
302 grid.SetRowHeight(row, widgetHeight)
307 self.file_list.OnChange.Add(self.OnKeyboardChange)
308 self.file_list.Style = FBListStyle.kFBDropDownList
309 grid.Add(self.file_list, row, 0)
310 grid.SetRowHeight(row, widgetHeight)
315 l.Caption =
"Shortcut list"
317 grid.SetRowHeight(row, widgetHeight)
322 self.shortcut_spread.Caption =
"Action Name"
323 self.shortcut_spread.ColumnAdd(
"Shortcut")
324 self.shortcut_spread.OnRowClick.Add(self.RowClicked)
325 grid.AddRange(self.shortcut_spread, row, row, 0, 2)
326 grid.SetRowRatio(row, 1.0)
331 l.Caption =
"Action Name"
335 l.Caption =
"Shortcut"
338 grid.SetRowHeight(row, widgetHeight)
342 self.action_edit =
FBEdit()
343 self.action_edit.ReadOnly =
True
344 grid.Add(self.action_edit, row, 0)
354 self.input_layout.AddRegion(
"Border",
"Click here and type a shortcut", x, y, w, h)
355 self.input_layout.SetBorder(
"Border",FBBorderStyle.kFBEmbossBorder,
True,
False,2,2,90,0)
356 self.input_layout.OnInput.Add(self.OnShortcut)
357 grid.Add(self.input_layout, row, 1)
359 self.shortcut_edit =
FBEdit()
360 self.shortcut_edit.ReadOnly =
True
361 grid.Add(self.shortcut_edit, row, 2)
362 grid.SetRowHeight(row, widgetHeight)
367 b.Caption =
"Replace shortcut"
368 b.OnClick.Add(self.Assign)
369 hbox.Add(b, buttonWidth)
371 b.Caption =
"Add shortcut"
372 b.OnClick.Add(self.Add)
373 hbox.Add(b, buttonWidth)
375 b.Caption =
"Remove shortcut"
376 b.OnClick.Add(self.Remove)
377 hbox.Add(b, buttonWidth)
379 grid.AddRange(hbox, row, row, 0, 1)
380 grid.SetRowHeight(row, widgetHeight)
385 l.Caption =
"Shortcut already assigned to action"
386 grid.AddRange(l, row, row, 0,2)
387 grid.SetRowHeight(row, widgetHeight)
391 self.conflict_edit =
FBEdit()
392 self.conflict_edit.ReadOnly =
True
393 grid.Add(self.conflict_edit, row, 0)
394 grid.SetRowHeight(row, widgetHeight)
401 b.OnClick.Add(self.ClosePopup)
402 hbox.Add(b, buttonWidth)
404 l.Caption =
'Reset Settings->Keyboard configuration->"Your Keyboard" for changes to take place.'
405 l.Style = FBTextStyle.kFBTextStyleBold
408 grid.AddRange(hbox, row, row, 0, 2)
409 grid.SetRowHeight(row, widgetHeight)
413 self.action_to_mappings = {}
414 self.mapping_to_row = {}
415 self.row_to_mapping = []
416 self.edit_mapping =
None
417 self.conflict_mapping =
None
419 self.keyboard_files = []
421 keyboard_folder = os.path.join(mbutils.GetConfigPath(),
"Keyboard")
422 for f
in os.listdir(keyboard_folder):
423 self.keyboard_files.append(os.path.join(keyboard_folder,f))
424 self.file_list.Items.append(f)
426 PythonKeyboardPath = os.path.join(mbutils.GetUserConfigPath(),
"Python",
"PythonKeyboard.txt")
428 if os.path.isfile(PythonKeyboardPath):
430 self.keyboard_files.append(os.path.join(mbutils.GetUserConfigPath(),
"Python",
"PythonKeyboard.txt"))
431 self.file_list.Items.append(
"PythonKeyboard.txt")
434 self.keyboard_files.append(os.path.join(mbutils.GetConfigPath(),
"Python\Keyboard",
"PythonKeyboard.txt"))
435 self.file_list.Items.append(
"PythonKeyboard.txt")
437 self.OnKeyboardChange(
None,
None)
439 def PopKeyboardMapper(control,event):
440 mapper = KeyboardMapper()
444 def PopulateLayout(tool):
459 tool.AddRegion(
"main",
"main", x, y, w, h)
460 tool.SetControl(
"main",vbox)
463 b.Caption =
"Keyboard mapper"
465 b.OnClick.Add(PopKeyboardMapper)
469 tool.StartSizeX = 200
470 tool.StartSizeY = 100