def parse_menu(self): if self.args.from_profile: try: self._menuid = self.args.items[0] self.items = MenuData.from_profile(self.args.from_profile, self._menuid) except IOError: print >> sys.stderr, '%s: error: profile file not found' % ( sys.argv[0]) return False except ValueError: print >> sys.stderr, '%s: error: menu not found' % ( sys.argv[0]) return False elif self.args.from_file: try: self._menuid = self.args.from_file self.items = MenuData.from_file(self.args.from_file) except: print >> sys.stderr, '%s: error: failed to load menu file' % ( sys.argv[0]) return False else: try: self.items = MenuData.from_args(self.args.items) self._menuid = None except ValueError: print >> sys.stderr, '%s: error: invalid number of arguments' % ( sys.argv[0]) return False return True
def parse_menu(self): if self.args.from_profile: try: self._menuid = self.args.items[0] self.items = MenuData.from_profile(self.args.from_profile, self._menuid) except IOError: print >>sys.stderr, '%s: error: profile file not found' % (sys.argv[0]) return False except ValueError: print >>sys.stderr, '%s: error: menu not found' % (sys.argv[0]) return False elif self.args.from_file: try: self._menuid = self.args.from_file self.items = MenuData.from_file(self.args.from_file) except: print >>sys.stderr, '%s: error: failed to load menu file' % (sys.argv[0]) return False else: try: self.items = MenuData.from_args(self.args.items) self._menuid = None except ValueError: print >>sys.stderr, '%s: error: invalid number of arguments' % (sys.argv[0]) return False return True
def parse_argumets(self, argv): if not OSDWindow.parse_argumets(self, argv): return False if not self.config: self.config = Config() if self.args.from_profile: try: self._menuid = self.args.items[0] self.items = MenuData.from_profile(self.args.from_profile, self._menuid) except IOError: print >> sys.stderr, '%s: error: profile file not found' % ( sys.argv[0]) return False except ValueError: print >> sys.stderr, '%s: error: menu not found' % ( sys.argv[0]) return False elif self.args.from_file: #try: data = json.loads(open(self.args.from_file, "r").read()) self._menuid = self.args.from_file self.items = MenuData.from_json_data(data) #except: # print >>sys.stderr, '%s: error: failed to load menu file' % (sys.argv[0]) # return False else: try: self.items = MenuData.from_args(self.args.items) self._menuid = None except ValueError: print >> sys.stderr, '%s: error: invalid number of arguments' % ( sys.argv[0]) return False # Parse simpler arguments self._control_with = self.args.control_with self._confirm_with = self.args.confirm_with self._cancel_with = self.args.cancel_with if self.args.use_cursor: self.enable_cursor() # Create buttons that are displayed on screen self.items = self.items.generate(self) for item in self.items: item.widget = self.generate_widget(item) self.pack_items(self.parent, self.items) if len(self.items) == 0: print >> sys.stderr, '%s: error: no items in menu' % (sys.argv[0]) return False if self.args.print_items: max_id_len = max(*[len(x.id) for x in self.items]) row_format = "{:>%s}:\t{}" % (max_id_len, ) for item in self.items: print row_format.format(item.id, item.label) return True
def parse_argumets(self, argv): if not OSDWindow.parse_argumets(self, argv): return False if not self.config: self.config = Config() if self.args.from_profile: try: self._menuid = self.args.items[0] self.items = MenuData.from_profile(self.args.from_profile, self._menuid) except IOError: print >>sys.stderr, '%s: error: profile file not found' % (sys.argv[0]) return False except ValueError: print >>sys.stderr, '%s: error: menu not found' % (sys.argv[0]) return False elif self.args.from_file: #try: data = json.loads(open(self.args.from_file, "r").read()) self._menuid = self.args.from_file self.items = MenuData.from_json_data(data) #except: # print >>sys.stderr, '%s: error: failed to load menu file' % (sys.argv[0]) # return False else: try: self.items = MenuData.from_args(self.args.items) self._menuid = None except ValueError: print >>sys.stderr, '%s: error: invalid number of arguments' % (sys.argv[0]) return False # Parse simpler arguments self._control_with = self.args.control_with self._confirm_with = self.args.confirm_with self._cancel_with = self.args.cancel_with print "_control_with", self._control_with if self.args.use_cursor: self.enable_cursor() # Create buttons that are displayed on screen self.items = self.items.generate(self) for item in self.items: item.widget = self.generate_widget(item) self.pack_items(self.parent, self.items) if len(self.items) == 0: print >>sys.stderr, '%s: error: no items in menu' % (sys.argv[0]) return False if self.args.print_items: max_id_len = max(*[ len(x.id) for x in self.items ]) row_format ="{:>%s}:\t{}" % (max_id_len,) for item in self.items: print row_format.format(item.id, item.label) return True
def parse_argumets(self, argv): if not OSDWindow.parse_argumets(self, argv): return False if self.args.from_profile: try: self._menuid = self.args.items[0] self.items = MenuData.from_profile(self.args.from_profile, self._menuid) except IOError: print >>sys.stderr, '%s: error: profile file not found' % (sys.argv[0]) return False except ValueError: print >>sys.stderr, '%s: error: menu not found' % (sys.argv[0]) return False elif self.args.from_file: try: data = json.loads(open(self.args.from_file, "r").read()) self._menuid = self.args.from_file self.items = MenuData.from_json_data(data) except: print >>sys.stderr, '%s: error: failed to loade menu file' % (sys.argv[0]) return False else: try: self.items = MenuData.from_args(self.args.items) self._menuid = None except ValueError: print >>sys.stderr, '%s: error: invalid number of arguments' % (sys.argv[0]) return False # Parse simpler arguments self._control_with = self.args.control_with self._confirm_with = self.args.confirm_with self._cancel_with = self.args.cancel_with if self.args.use_cursor: self.f.add(self.cursor) self.f.show_all() self._use_cursor = True # Create buttons that are displayed on screen for item in self.items: item.widget = Gtk.Button.new_with_label(item.label) item.widget.set_name("osd-menu-item") item.widget.set_relief(Gtk.ReliefStyle.NONE) self.pack_items(self.parent, self.items) if len(self.items) == 0: print >>sys.stderr, '%s: error: no items in menu' % (sys.argv[0]) return False return True
def parse_argumets(self, argv): if not OSDWindow.parse_argumets(self, argv): return False if not self.config: self.config = Config() try: self.items = MenuData.from_args(self.args.items) self._menuid = None except ValueError: print >> sys.stderr, '%s: error: invalid number of arguments' % ( sys.argv[0]) return False self._text.set_label(self.args.text) if self.args.feedback_amplitude: side = "LEFT" self.feedback = side, int(self.args.feedback_amplitude) # Create buttons that are displayed on screen items = self.items.generate(self) self.items = [] for item in items: item.widget = self.generate_widget(item) if item.widget is not None: self.items.append(item) self.pack_items(self.parent, self.items) if len(self.items) == 0: print >> sys.stderr, '%s: error: no items in menu' % (sys.argv[0]) return False return True
def _add_refereced_menu(self, model, menu_id, used): """ As _add_refereced_profile, but reads and parses menu file. """ if "." in menu_id and menu_id not in used: # Dot in id means filename used.add(menu_id) filename = find_menu(menu_id) name = ".".join(menu_id.split(".")[0:-1]) if name.startswith(".") and menu_is_default(menu_id): # Default and hidden, don't bother user with it return if filename: model.append((not menu_is_default(menu_id), _("Menu"), name, filename, True, self.TP_MENU)) try: menu = MenuData.from_file(filename, ActionParser()) except Exception, e: # Menu that cannot be parsed shouldn't be exported log.error(e) return for item in menu: if isinstance(item, Submenu): self._add_refereced_menu( model, os.path.split(item.filename)[-1], used) if hasattr(item, "action"): self._parse_action(model, item.action, used) else: model.append((False, _("Menu"), _("%s (not found)") % (name, ), "", False, self.TP_MENU))
def parse_argumets(self, argv): if not OSDWindow.parse_argumets(self, argv): return False if not self.config: self.config = Config() try: self.items = MenuData.from_args(self.args.items) self._menuid = None except ValueError: print >>sys.stderr, '%s: error: invalid number of arguments' % (sys.argv[0]) return False self._text.set_label(self.args.text) if self.args.feedback_amplitude: side = "LEFT" self.feedback = side, int(self.args.feedback_amplitude) # Create buttons that are displayed on screen items = self.items.generate(self) self.items = [] for item in items: item.widget = self.generate_widget(item) if item.widget is not None: self.items.append(item) self.pack_items(self.parent, self.items) if len(self.items) == 0: print >>sys.stderr, '%s: error: no items in menu' % (sys.argv[0]) return False return True
def _add_refereced_menu(self, model, menu_id, used): """ As _add_refereced_profile, but reads and parses menu file. """ if "." in menu_id and menu_id not in used: # Dot in id means filename used.add(menu_id) filename = find_menu(menu_id) name = ".".join(menu_id.split(".")[0:-1]) if name.startswith(".") and menu_is_default(menu_id): # Default and hidden, don't bother user with it return if filename: model.append((not menu_is_default(menu_id), _("Menu"), name, filename, True, self.TP_MENU)) try: menu = MenuData.from_file(filename, ActionParser()) except Exception, e: # Menu that cannot be parsed shouldn't be exported log.error(e) return for item in menu: if isinstance(item, Submenu): self._add_refereced_menu(model, os.path.split(item.filename)[-1], used) if hasattr(item, "action"): self._parse_action(model, item.action, used) else: model.append((False, _("Menu"), _("%s (not found)") % (name,), "", False, self.TP_MENU))
def _load_items_from_file(self, id): for p in (get_menus_path(), get_default_menus_path()): path = os.path.join(p, "%s.menu" % (id, )) if os.path.exists(path): return MenuData.from_file(path, TalkingActionParser()) # Menu file not found return None
def export_menu(tar, filename): try: menu = MenuData.from_json_data(json.loads(open(filename, "r").read()), ActionParser()) tar.add(filename, arcname=os.path.split(filename)[-1], recursive=False) except Exception, e: # Menu that cannot be parsed shouldn't be exported log.error(e) return False
def _load_items_from_file(self, id): for p in (get_menus_path(), get_default_menus_path()): path = os.path.join(p, "%s.menu" % (id,)) if os.path.exists(path): data = json.loads(open(path, "r").read()) return MenuData.from_json_data(data, TalkingActionParser()) # Menu file not found return None
def _load_items_from_file(self, id): for p in (get_menus_path(), get_default_menus_path()): path = os.path.join(p, "%s.menu" % (id, )) if os.path.exists(path): data = json.loads(open(path, "r").read()) return MenuData.from_json_data(data, TalkingActionParser()) # Menu file not found return None
def load(self, filename): """ Loads profile from file. Returns self """ data = json.loads(open(filename, "r").read()) # Version try: version = int(data["version"]) except: version = 0 # Buttons self.buttons = {} for x in SCButtons: self.buttons[x] = self.parser.from_json_data(data["buttons"], x.name) # Stick & gyro self.stick = self.parser.from_json_data(data, "stick") self.gyro = self.parser.from_json_data(data, "gyro") if "triggers" in data: # Old format # Triggers self.triggers = ({ x : self.parser.from_json_data(data["triggers"], x) for x in Profile.TRIGGERS }) # Pads self.pads = { Profile.LEFT : self.parser.from_json_data(data, "left_pad"), Profile.RIGHT : self.parser.from_json_data(data, "right_pad"), } else: # New format # Triggers self.triggers = { Profile.LEFT : self.parser.from_json_data(data, "trigger_left"), Profile.RIGHT : self.parser.from_json_data(data, "trigger_right"), } # Pads self.pads = { Profile.LEFT : self.parser.from_json_data(data, "pad_left"), Profile.RIGHT : self.parser.from_json_data(data, "pad_right"), } # Menus self.menus = {} if "menus" in data: for id in data["menus"]: for invalid_char in ".:/": if invalid_char in id: raise ValueError("Invalid character '%s' in menu id '%s'" % (invalid_char, id)) self.menus[id] = MenuData.from_json_data(data["menus"][id], self.parser) # Conversion if version < Profile.VERSION: self._convert(version) return self
def load_cbMIs(self): """ See above. This method just parses Default menu and checks boxes for present menu items. """ try: data = MenuData.from_fileobj(open(find_menu("Default.menu"), "r")) except Exception, e: # Shouldn't really happen log.error(traceback.format_exc()) return
def export_menu(tar, filename): try: menu = MenuData.from_json_data( json.loads(open(filename, "r").read()), ActionParser()) tar.add(filename, arcname=os.path.split(filename)[-1], recursive=False) except Exception, e: # Menu that cannot be parsed shouldn't be exported log.error(e) return False
def _generate_menudata(self): """ Generates MenuData instance from items in list """ model = self.builder.get_object("tvItems").get_model() data = MenuData(*[i[0].item for i in model]) i = 1 for item in data: item.id = "item%s" % (i, ) i += 1 return data
def on_cbMI_toggled(self, widget): """ Called when one of 'Default Menu Items' checkboxes is toggled. This actually does kind of magic: - 1st, default menu file is loaded - 2nd, based on widget name, option from DEFAULT_MENU_OPTIONS is selected - 3rd, if this option is not present in loaded menu and checkbox is toggled on, option is added - (same for option that is present while checkbox was toggled off) - 4rd, default menu is saved """ if self._recursing: return try: data = MenuData.from_fileobj(open(find_menu("Default.menu"), "r"), GuiActionParser()) index = int(widget.get_name().split("_")[-1]) instance = GlobalSettings._make_mi_instance(index) except Exception, e: log.error(traceback.format_exc()) self._recursing = True widget.set_active(not widget.get_active()) self._recursing = False return
def import_scc_tar(self, filename): """ Imports packaged profiles. Checks for shell() actions everywhere and ask user to enter main name, check generated ones and optionaly change them as he wish. """ files = self.builder.get_object("lstImportPackage") try: # Open tar tar = tarfile.open(filename, "r:gz") files.clear() # Grab 1st profile name = tar.extractfile(Export.PN_NAME).read() main_profile = "%s.sccprofile" % name parser = GuiActionParser() o = GObject.GObject() o.obj = Profile(parser).load_fileobj(tar.extractfile(main_profile)) files.append(( 2, name, name, _("(profile)"), o )) for x in tar: name = ".".join(x.name.split(".")[0:-1]) if x.name.endswith(".sccprofile") and x.name != main_profile: o = GObject.GObject() o.obj = Profile(parser).load_fileobj(tar.extractfile(x)) files.append(( True, name, name, _("(profile)"), o )) elif x.name.endswith(".menu"): o = GObject.GObject() o.obj = MenuData.from_fileobj(tar.extractfile(x), parser) files.append(( True, name, name, _("(menu)"), o )) except Exception, e: # Either entire tar or some profile cannot be parsed. # Display error message and let user to quit # Error message reuses same page as above. log.error(e) self.error(str(e)) return
def import_scc_tar(self, filename): """ Imports packaged profiles. Checks for shell() actions everywhere and ask user to enter main name, check generated ones and optionaly change them as he wish. """ files = self.builder.get_object("lstImportPackage") try: # Open tar tar = tarfile.open(filename, "r:gz") files.clear() # Grab 1st profile name = tar.extractfile(Export.PN_NAME).read() main_profile = "%s.sccprofile" % name parser = GuiActionParser() o = GObject.GObject() o.obj = Profile(parser).load_fileobj(tar.extractfile(main_profile)) files.append((2, name, name, _("(profile)"), o)) for x in tar: name = ".".join(x.name.split(".")[0:-1]) if x.name.endswith(".sccprofile") and x.name != main_profile: o = GObject.GObject() o.obj = Profile(parser).load_fileobj(tar.extractfile(x)) files.append((True, name, name, _("(profile)"), o)) elif x.name.endswith(".menu"): o = GObject.GObject() o.obj = MenuData.from_fileobj(tar.extractfile(x), parser) files.append((True, name, name, _("(menu)"), o)) except Exception, e: # Either entire tar or some profile cannot be parsed. # Display error message and let user to quit # Error message reuses same page as above. log.error(e) self.error(str(e)) return
items.insert(pos, Separator(instance.label)) pos += 1 items.insert(pos, instance) else: if isinstance(instance, MenuGenerator): items = [ x for x in items if not ( isinstance(x, Separator) and x.label == instance.label) ] items = [ x for x in items if instance.describe().strip(" >") != x.describe().strip(" >") ] path = os.path.join(get_menus_path(), "Default.menu") data = MenuData(*items) jstr = Encoder(sort_keys=True, indent=4).encode(data) open(path, "w").write(jstr) log.debug("Wrote menu file %s", path) def load_cbMIs(self): """ See above. This method just parses Default menu and checks boxes for present menu items. """ try: data = MenuData.from_fileobj(open(find_menu("Default.menu"), "r")) except Exception, e: # Shouldn't really happen log.error(traceback.format_exc()) return
def load(self, filename): """ Loads profile from file. Returns self """ data = json.loads(open(filename, "r").read()) # Version try: version = int(data["version"]) except: version = 0 # Buttons self.buttons = {} for x in SCButtons: self.buttons[x] = self.parser.from_json_data( data["buttons"], x.name) # Stick & gyro self.stick = self.parser.from_json_data(data, "stick") self.gyro = self.parser.from_json_data(data, "gyro") if "triggers" in data: # Old format # Triggers self.triggers = ({ x: self.parser.from_json_data(data["triggers"], x) for x in Profile.TRIGGERS }) # Pads self.pads = { Profile.LEFT: self.parser.from_json_data(data, "left_pad"), Profile.RIGHT: self.parser.from_json_data(data, "right_pad"), } else: # New format # Triggers self.triggers = { Profile.LEFT: self.parser.from_json_data(data, "trigger_left"), Profile.RIGHT: self.parser.from_json_data(data, "trigger_right"), } # Pads self.pads = { Profile.LEFT: self.parser.from_json_data(data, "pad_left"), Profile.RIGHT: self.parser.from_json_data(data, "pad_right"), } # Menus self.menus = {} if "menus" in data: for id in data["menus"]: for invalid_char in ".:/": if invalid_char in id: raise ValueError( "Invalid character '%s' in menu id '%s'" % (invalid_char, id)) self.menus[id] = MenuData.from_json_data( data["menus"][id], self.parser) # Conversion if version < Profile.VERSION: self._convert(version) return self
def load_fileobj(self, fileobj): """ Loads profile from file-like object. Filename attribute is not set, what may cause some trouble if used in GUI. Returns self. """ data = json.loads(fileobj.read()) # Version try: version = float(data["version"]) except: version = 0 # Settings - Description # (stored in key "_", so it's serialized on top of JSON file) if "_" not in data: self.description = "" elif type(data["_"]) == list: self.description = "\n".join(data["_"]) else: self.description = data["_"] # Settings - Template self.is_template = bool(data["is_template"]) if "is_template" in data else False # Buttons self.buttons = {} for x in SCButtons: self.buttons[x] = self.parser.from_json_data(data["buttons"], x.name) # Pressing stick is interpreted as STICKPRESS button, # formely called just STICK if "STICK" in data["buttons"] and "STICKPRESS" not in data["buttons"]: self.buttons[SCButtons.STICKPRESS] = self.parser.from_json_data( data["buttons"], "STICK") # Stick & gyro self.stick = self.parser.from_json_data(data, "stick") self.gyro = self.parser.from_json_data(data, "gyro") if "triggers" in data: # Old format # Triggers self.triggers = ({ x : self.parser.from_json_data(data["triggers"], x) for x in Profile.TRIGGERS }) # Pads self.pads = { Profile.LEFT : self.parser.from_json_data(data, "left_pad"), Profile.RIGHT : self.parser.from_json_data(data, "right_pad"), Profile.CPAD : NoAction() } else: # New format # Triggers self.triggers = { Profile.LEFT : self.parser.from_json_data(data, "trigger_left"), Profile.RIGHT : self.parser.from_json_data(data, "trigger_right"), } # Pads self.pads = { Profile.LEFT : self.parser.from_json_data(data, "pad_left"), Profile.RIGHT : self.parser.from_json_data(data, "pad_right"), Profile.CPAD : self.parser.from_json_data(data, "cpad"), } # Menus self.menus = {} if "menus" in data: for id in data["menus"]: for invalid_char in ".:/": if invalid_char in id: raise ValueError("Invalid character '%s' in menu id '%s'" % (invalid_char, id)) self.menus[id] = MenuData.from_json_data(data["menus"][id], self.parser) # Conversion self.original_version = version # TODO: This is temporary if version < Profile.VERSION: self._convert(version) return self
def parse_group(self, group, side): """ Parses output (group) from vdf profile. Returns Action. """ if not "mode" in group: raise ParseError("Group without mode") mode = group["mode"] inputs = VDFProfile.get_inputs(group) settings = group["settings"] if "settings" in group else {} for o in ("output_trigger", "output_joystick"): if o in settings: if int(settings[o]) <= 1: side = Profile.LEFT else: side = Profile.RIGHT if mode == "dpad": keys = [] for k in ("dpad_north", "dpad_south", "dpad_east", "dpad_west"): if k in inputs: keys.append(self.parse_button(inputs[k])) else: keys.append(NoAction()) action = DPadAction(*keys) elif mode == "four_buttons": keys = [] for k in ("button_y", "button_a", "button_x", "button_b"): if k in inputs: keys.append(self.parse_button(inputs[k])) else: keys.append(NoAction()) action = DPadAction(*keys) elif mode == "joystick_move": if side == Profile.LEFT: # Left action = XYAction(AxisAction(Axes.ABS_X), AxisAction(Axes.ABS_Y)) else: # Right action = XYAction(AxisAction(Axes.ABS_RX), AxisAction(Axes.ABS_RY)) elif mode == "joystick_camera": output_joystick = 0 if 'output_joystick' in settings: output_joystick = int(settings['output_joystick']) if output_joystick == 0: action = BallModifier( XYAction(AxisAction(Axes.ABS_X), AxisAction(Axes.ABS_Y))) elif output_joystick == 1: action = BallModifier( XYAction(AxisAction(Axes.ABS_RX), AxisAction(Axes.ABS_RY))) else: # TODO: Absolute mouse? Doesn't seems to do anything in Steam action = BallModifier( SensitivityModifier(0.1, 0.1, MouseAction())) elif mode == "mouse_joystick": action = BallModifier( XYAction(AxisAction(Axes.ABS_RX), AxisAction(Axes.ABS_RY))) elif mode == "scrollwheel": action = BallModifier( XYAction(MouseAction(Rels.REL_HWHEEL), MouseAction(Rels.REL_WHEEL))) elif mode == "touch_menu": # Touch menu is converted to GridMenu items = [] next_item_id = 1 for k in inputs: action = self.parse_button(inputs[k]) items.append( MenuItem("item_%s" % (next_item_id, ), action.describe(Action.AC_BUTTON), action)) next_item_id += 1 # Menu is stored in profile, with generated ID menu_id = "menu_%s" % (self.next_menu_id, ) self.next_menu_id += 1 self.menus[menu_id] = MenuData(*items) action = GridMenuAction( menu_id, 'LEFT' if side == Profile.LEFT else 'RIGHT', SCButtons.LPAD if side == Profile.LEFT else SCButtons.RPAD) elif mode == "absolute_mouse": if "click" in inputs: if side == Profile.LEFT: self.add_by_binding(SCButtons.LPAD, self.parse_button(inputs["click"])) else: self.add_by_binding(SCButtons.RPAD, self.parse_button(inputs["click"])) if "gyro_axis" in settings: if int(settings["gyro_axis"]) == 1: action = MouseAction(ROLL) else: action = MouseAction(YAW) else: action = MouseAction() elif mode == "mouse_wheel": action = BallModifier( XYAction(MouseAction(Rels.REL_HWHEEL), ouseAction(Rels.REL_WHEEL))) elif mode == "trigger": actions = [] if "click" in inputs: actions.append( TriggerAction(TRIGGER_CLICK, self.parse_button(inputs["click"]))) if side == Profile.LEFT: actions.append(AxisAction(Axes.ABS_Z)) else: actions.append(AxisAction(Axes.ABS_RZ)) action = MultiAction.make(*actions) elif mode == "mouse_region": # Read value and assume dafaults scale = float(settings["scale"]) if "scale" in settings else 100.0 x = float( settings["position_x"]) if "position_x" in settings else 50.0 y = float( settings["position_y"]) if "position_y" in settings else 50.0 w = float(settings["sensitivity_horiz_scale"] ) if "sensitivity_horiz_scale" in settings else 100.0 h = float(settings["sensitivity_vert_scale"] ) if "sensitivity_vert_scale" in settings else 100.0 # Apply scale w = w * scale / 100.0 h = h * scale / 100.0 # Convert to (0, 1) range x, y = x / 100.0, 1.0 - (y / 100.0) w, h = w / 100.0, h / 100.0 # Convert to rectangle x1 = max(0.0, x - (w * VDFProfile.REGION_IMPORT_FACTOR)) x2 = min(1.0, x + (w * VDFProfile.REGION_IMPORT_FACTOR)) y1 = max(0.0, y - (h * VDFProfile.REGION_IMPORT_FACTOR)) y2 = min(1.0, y + (h * VDFProfile.REGION_IMPORT_FACTOR)) action = RelAreaAction(x1, y1, x2, y2) else: raise ParseError("Unknown mode: '%s'" % (group["mode"], )) action = VDFProfile.parse_modifiers(group, action, side) return action
def load_fileobj(self, fileobj): """ Loads profile from file-like object. Filename attribute is not set, what may cause some trouble if used in GUI. Returns self. """ data = json.loads(fileobj.read()) # Version try: version = int(data["version"]) except: version = 0 # Settings - Description # (stored in key "_", so it's serialized on top of JSON file) if "_" not in data: self.description = "" elif type(data["_"]) == list: self.description = "\n".join(data["_"]) else: self.description = data["_"] # Settings - Template self.is_template = bool( data["is_template"]) if "is_template" in data else False # Buttons self.buttons = {} for x in SCButtons: self.buttons[x] = self.parser.from_json_data( data["buttons"], x.name) # Pressing stick is interpreted as STICKPRESS button, # formely called just STICK if "STICK" in data["buttons"] and "STICKPRESS" not in data["buttons"]: self.buttons[SCButtons.STICKPRESS] = self.parser.from_json_data( data["buttons"], "STICK") # Stick & gyro self.stick = self.parser.from_json_data(data, "stick") self.gyro = self.parser.from_json_data(data, "gyro") if "triggers" in data: # Old format # Triggers self.triggers = ({ x: self.parser.from_json_data(data["triggers"], x) for x in Profile.TRIGGERS }) # Pads self.pads = { Profile.LEFT: self.parser.from_json_data(data, "left_pad"), Profile.RIGHT: self.parser.from_json_data(data, "right_pad"), } else: # New format # Triggers self.triggers = { Profile.LEFT: self.parser.from_json_data(data, "trigger_left"), Profile.RIGHT: self.parser.from_json_data(data, "trigger_right"), } # Pads self.pads = { Profile.LEFT: self.parser.from_json_data(data, "pad_left"), Profile.RIGHT: self.parser.from_json_data(data, "pad_right"), } # Menus self.menus = {} if "menus" in data: for id in data["menus"]: for invalid_char in ".:/": if invalid_char in id: raise ValueError( "Invalid character '%s' in menu id '%s'" % (invalid_char, id)) self.menus[id] = MenuData.from_json_data( data["menus"][id], self.parser) # Conversion if version < Profile.VERSION: self._convert(version) return self