From: <mk...@us...> - 2003-07-26 21:41:36
|
Update of /cvsroot/csp/APPLICATIONS/CSPSim/Tools/HID In directory sc8-pr-cvs1:/tmp/cvs-serv17533 Added Files: cspinput Removed Files: map2hid Log Message: --- NEW FILE: cspinput --- #!/usr/bin/env python # Combat Simulator Project - MAP2HID input script compiler # Copyright (C) 2002 The Combat Simulator Project # http://csp.sourceforge.net # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ## @author Mark Rose <tm...@st...> import sys import os.path KMODS = { "LSHIFT" : 0x0001, "RSHIFT" : 0x0002, "LCTRL" : 0x0040, "RCTRL" : 0x0080, "LALT" : 0x0100, "RALT" : 0x0200, "LMETA" : 0x0400, "RMETA" : 0x0800, "NUM" : 0x1000, "CAPS" : 0x2000, "MODE" : 0x4000, } MULTI_KMODS = { "SHIFT" : ("LSHIFT", "RSHIFT"), "CTRL" : ("LCTRL", "RCTRL"), "ALT" : ("LALT", "RALT"), "META" : ("LMETA", "RMETA"), } SDL_PRESSED = 0x01 def SDL_BUTTON(x): if x == 0: return 0 if x < 0 or x > 8: raise Error("invalid mouse button identifier %d (should be 0..7)." % x) return SDL_PRESSED << (x-1) class Error: def __init__(self, msg): self.msg = msg def convertToInt(s): try: if s.startswith("0x"): return int(s[2:], 16) else: return int(s) except: raise Error("expected an integer or hex value, got '%s' instead." % s) def generatePermutations(m): result = [] if len(m) > 0: subperms = generatePermutations(m[1:]) for item in m[0]: result.extend(map(lambda x, i=item: i|x, subperms)) else: result = [0] return result class Action: def __init__(self, id, time, stop = 0, loop = -1, mode = -1, jmod = -1): self.id = id self.time = time self.stop = stop self.loop = loop self.mode = mode self.jmod = jmod def __repr__(self): s = "%0.2f:%s" % (self.time, self.id) if self.mode >= 0: s = s + "/MODE_%d" % self.mode if self.stop: s = s + "/YIELD" if self.jmod >= 0: s = s + "/SHIFT_%d" % self.jmod if self.loop >= 0: s = s + "/LOOP_%d" % self.loop return s class Mapping: def __init__(self, device, number, mmod, kmod, jmod, type, mode, event_id, script): self.device = device self.number = number self.type = type self.mmod = mmod self.kmod = kmod self.jmod = jmod self.event_id = event_id self.mode = mode self.script = script def write(self, outf=sys.stdout): for action in self.script: script = "@%05.2f %+03d %+05d %+03d %+03d %s" % (action.time, action.mode, action.jmod, action.stop, action.loop, action.id) print >>outf, script code = "+" code = code + self.device.upper()[0] code = code + " %1d " % self.number code = code + self.type.upper()[0] code = code + " %04d %04d %04d %04d" % (self.kmod, self.jmod, self.mmod, self.event_id) code = code + " %02d" % self.mode print >>outf, code def dump(self): print "%s:%d" % (self.device.upper(), self.number), if self.device == 'joystick': self.dump_joystick() elif self.device == 'keyboard': self.dump_keyboard() elif self.device == 'mouse': self.dump_mouse() def dump_joystick(self): if self.type == 'axis': print "AXIS(%d) =" % self.event_id, print self.script else: if self.jmod > 0: print "SHIFT +", print "BUTTON(%d)" % self.event_id, print self.type.upper(), print "=", self.script, print "in mode", self.mode def dump_keyboard(self): print "KEY(%d){%d}" % (self.event_id, self.kmod), print "=", self.script, print "in mode", self.mode def dump_mouse(self): if self.type == "move": print "MOVE (mmod=%d, kmod=%d)" % (self.mmod, self.kmod), else: print "BUTTON(%d)" % self.event_id, print "(kmod=%d)" % self.kmod, print "=", self.script, print "in mode", self.mode class VirtualDeviceDefinition: def __init__(self): self.included = {} self.values = {} self.scripts = {} self.modes = {} self.maps = [] self.definitions = {} self.devices = {} self.filestack = [] self.pathstack = ['.'] self.line = 0 self.file = "" self.bind = {} def read(self, fn): f = open(fn, 'rt') if f is not None: self.file = fn self.parse(f) else: raise Error("unable to open file '%s'." % fn) def parse(self, f): for line in f.xreadlines(): self.line = self.line + 1 idx = line.find("#") if idx >= 0: line = line[:idx] line = line.strip() if len(line) == 0: continue; p = line.split() command = p[0] try: self.processCommand(command, p[1:]) except Error, e: for file, line_number in self.filestack: print >>sys.stderr, "In file included from %s(%d), " % (file, line_number) print >>sys.stderr, "%s(%d): %s" % (self.file, self.line, e.msg) print >>sys.stderr, ">", line sys.exit(1) def includeCommand(self, args): n = len(args) if n == 1: fn = args[0] if not self.included.has_key(fn): self.included[fn] = 1 self.filestack.append((self.file, self.line)) basepath = self.pathstack[-1] if not os.path.isabs(fn): fn = os.path.join(basepath, fn) self.pathstack.append(os.path.dirname(fn)) self.read(fn) self.pathstack.pop() self.file, self.line = self.filestack.pop() else: raise Error("incorrect number of parameters for 'include' statement.") def modeCommand(self, args): n = len(args) if n == 1: mode = args[0] if not self.modes.has_key(mode): self.modes[mode] = len(self.modes) else: raise Error("incorrect number of parameters for 'mode' statement.") def scriptCommand(self, args): n = len(args) if n == 1 or n == 2: name = args[0] if n == 1: self.scripts[name] = None else: script = args[1] script = self.unrollScript(script) if self.scripts.has_key(name): print "WARNING: script %s is multiply defined." % name else: self.scripts[name] = script else: raise Error("incorrect number of parameters for 'script' statement.") def deviceCommand(self, args): n = len(args) if n == 3 or n == 4: type = args[0] if not type in ("joystick", "keyboard", "mouse"): raise Error("unrecognized device type '%s'. Must be 'joystick', 'mouse', or 'keyboard'." % type) number = int(args[1]) if number < 0 or number > 7: raise Error("invalid device number %d (must be 0..7)." % number) name = args[2] if n == 4: definitions = args[3] if not self.definitions.has_key(definitions): raise Error("undefined device definition '%s'." % definitions) else: definitions = None self.devices[name] = (type, number, definitions) else: raise Error("incorrect number of parameters for 'device' statement.") def defineCommand(self, args): n = len(args) if n == 2: device, name = self.splitDevice(args[0]) id = self.unrollDefinition(args[1]) self.setDefinition(device, name, id) else: raise Error("incorrect number of parameters for 'define' statement.") def mapCommand(self, args): n = len(args) if n == 3 or n == 4: multi, device_type, device_number, mmod, kmod, jmod, value = self.parseEvent(args[0]) type = args[1] if device_type == 'mouse': valid = ('press', 'release', 'move') elif device_type == 'joystick': valid = ('press', 'release', 'axis') else: valid = ('press', 'release') if not type in valid: raise Error("invalid option '%s' in map command. must be one of %s." % (type, str(valid))) if type == 'move': mmod = mmod | SDL_BUTTON(value) if n > 3: modes = args[2] script = args[3] else: modes = "*" script = args[2] if '*' in modes: modes = self.modes.keys() if len(modes) == 0: raise Error("map statement, but no modes defined.") else: modes = modes.split("|") for mode in modes: if not self.modes.has_key(mode): raise Error("mode '%s' used but not defined." % mode) script = self.unrollScript(script) if type in ('move', 'axis') and len(script) > 1: raise Error("'%s' mapping can have only one target identifier." % type) if len(multi) > 0: multi = generatePermutations(multi) else: multi = (0,) script = self.buildScript(script) for mode in modes: mode_id = self.modes[mode] for m in multi: map = Mapping(device_type, device_number, mmod, kmod|m, jmod, type, mode_id, value, script) self.maps.append(map) else: raise Error("incorrect number of parameters for 'map' statement.") def bindCommand(self, args): n = len(args) if n == 1: self.bind[args[0]] = 1 else: raise Error("incorrect number of parameters for 'bind' statement.") def processCommand(self, command, args): if command == "include": self.includeCommand(args) elif command == "mode": self.modeCommand(args) elif command == "script": self.scriptCommand(args) elif command == "device": self.deviceCommand(args) elif command == "define": self.defineCommand(args) elif command == "map": self.mapCommand(args) elif command == "bind": self.bindCommand(args) else: raise Error("Unrecognized command '%s'" % command) def parseEvent(self, event): parts = event.split(':') if len(parts) != 2: raise Error("bad syntax in '%s', should be of the form 'device:event'." % event) device_name, event = parts device = self.devices.get(device_name, None) if device is None: raise Error("undefined device '%s'." % device_name) type, id, definitions = device if definitions: definitions = self.definitions.get(definitions, {}) else: definitions = {} mmod, kmod, jmod, value = 0, 0, 0, 0 multi = [] mods = event.split('-') mods, event = mods[:-1], mods[-1] if type == "joystick": for mod in mods: if mod == "SHIFT": jmod = 1 else: for mod in mods: if KMODS.has_key(mod): kmod = kmod + KMODS[mod] elif MULTI_KMODS.has_key(mod): multi.append(map(KMODS.get, MULTI_KMODS[mod])) elif type == "mouse" and definitions.has_key(mod): mmod = mmod | SDL_BUTTON(definitions[mod]) else: raise Error("unrecognized modifier '%s' in event '%s'." % (mod, event)) if definitions.has_key(event): value = definitions[event] else: try: value = int(event); except: raise Error("unknown event id '%s'" % event) if value < 0 or value > 4095: raise Error("invalid event id %d (must be 0..4095)." % value) return multi, type, id, mmod, kmod, jmod, value def unrollScript(self, script): result = [] actions = script.split("|") for action in actions: try: delay = float(action) if delay > 0.0: result.append(delay) except: if self.scripts.has_key(action): s = self.scripts[action] if s is not None: result.extend(s) else: result.append(action) return result def splitDevice(self, device): return device.split(':') def unrollDefinition(self, d): if ':' in d: device, id = d.split(':') type, number, defs = self.devices.get(device, ("", 0, {})) return defs.get(id, None) return int(d) def setDefinition(self, device, name, id): defs = self.definitions.setdefault(device, {}) defs[name] = id def buildScript(self, script): time = 0.0 loopstart = 0 actions = [] for item in script: if isinstance(item, str): item = item.split('/') command = item[0] if len(item) > 1: opts = item[1] else: opts = '' stop, loop, jmod, mode = 0, -1, -1, -1 if 'B' in opts: stop = 1 if '*' in opts: loopstart = len(actions) if 'R' in opts: loop = loopstart if self.modes.has_key(command): mode = self.modes[command] command = "" elif command == "SHIFT": jmod = 1 command = "" elif command == "NOSHIFT": jmod = 0 command = "" if time >= 100.0: raise Error("Script delay too long (%.1f >= 100 s)" % time) action = Action(command, time, stop, loop, mode, jmod) actions.append(action) time = 0.0 if loop > -1: break else: time = time + item if len(actions) == 0: actions.append(Action("", 0.0)) # nop return actions class VirtualDevice: def __init__(self): self.mode = 0 self.mapping = {} def usage(program): print "CSP map script to human interface device definition converter" print "Copyright (C) 2003 Mark Rose <tm...@st...>" print "usage: %s [--help] infile [outfile]" % program def main(argv): file = None outfile = None for arg in argv[1:]: if arg.startswith('--'): if arg == '--help': usage(argv[0]) print " infile : input map file" print " outfile : output file ('-' for stdout)" sys.exit(1) continue if file is None: file = arg elif outfile is None: outfile = arg else: usage(argv[0]) sys.exit(1) if file is None: usage(argv[0]) sys.exit(1) if outfile is None and file.endswith('.map'): outfile = file[:-4] + '.hid' outf = None if outfile == '-': outf = sys.stdout else: try: outf = open(outfile, "wt") except: print "Unable to write to '%s'." % outfile sys.exit(1) v = VirtualDeviceDefinition() try: v.read(file) except Error, e: print e.msg sys.exit(1) bindings = v.bind.keys() bindings.sort() for b in bindings: print >>outf, "=%s" % b for m in v.maps: m.write(outf) if __name__ == "__main__": main(sys.argv) --- map2hid DELETED --- |