diff --git a/McAirpos/launCharc/launCharc b/McAirpos/launCharc/launCharc index d148235..421455c 100755 Binary files a/McAirpos/launCharc/launCharc and b/McAirpos/launCharc/launCharc differ diff --git a/McAirpos/launCharc/launCharc.c b/McAirpos/launCharc/launCharc.c index bd62833..2984d78 100644 --- a/McAirpos/launCharc/launCharc.c +++ b/McAirpos/launCharc/launCharc.c @@ -80,9 +80,14 @@ int main(int argc, char** argv) { // Variables for whole main function scope char* path = "/dev/tty"; int fd; + char basename[200]; + memset (basename, 0, sizeof(basename)); + char copyCmd[300]; + memset (copyCmd, 0, sizeof(copyCmd)); // Read game file argument to execute + // Note: Should be updated to allow for combinations of more than one argument, e.g. "nomap verbose" and future additions char game[200]; memset (game, 0, sizeof(game)); char options[10]; @@ -98,15 +103,22 @@ int main(int argc, char** argv) { } - // Check if run on Recalbox + // Find rom's basename + snprintf(copyCmd, 300, "basename %s", game); + strcat(basename, getSystemOutput(copyCmd)); + + + // Clear Linux console screen system("clear"); + + + // Check if run on Recalbox int isRecalbox = 0; if (!strcmp("RECALBOX", getSystemOutput("uname -a | tr ' ' '\\n' | grep RECALBOX | tr -d [:cntrl:]"))) { isRecalbox = 1; // Copy game_file.elf to /tmp(.../roms folder mount exFAT and cannot execute files) - char copyCmd[300]; memset (copyCmd, 0, sizeof(copyCmd)); - snprintf(copyCmd, 300, "cp %s /tmp/arcade.elf&&chmod +x /tmp/arcade.elf", game); + snprintf(copyCmd, 300, "rsync %s /recalbox/share/bootvideos/makecode/&&chmod +x /recalbox/share/bootvideos/makecode/%s", game, basename); system(copyCmd); system("/usr/bin/fbv2 /home/pi/McAirpos/McAirpos/MakeCode/MakeCode_Arcade.png >>/dev/null 2>&1"); } @@ -150,7 +162,11 @@ int main(int argc, char** argv) { if (numberOfPads < 2) { char padCommand[150]; memset (padCommand, 0, sizeof(padCommand)); - snprintf(padCommand, 150, "/home/pi/McAirpos/McAirpos/uinput-mapper/input-read -vp /dev/input/event%d 2>&1 | grep -e BTN_START -e BTN_SOUTH -e BTN_PINKIE", i); + if (isRecalbox == 1) { + snprintf(padCommand, 150, "/home/pi/McAirpos/McAirpos/uinput-mapper/input-read -vp /dev/input/event%d 2>&1 | grep -e BTN_START -e BTN_SOUTH -e BTN_PINKIE", i); + }else { + snprintf(padCommand, 150, "/home/pi/McAirpos/McAirpos/uinput-mapper/input-read -vp /dev/input/event%d 2>&1 | grep -e BTN_START -e BTN_SOUTH -e BTN_PINKIE", i); + } char* event = getSystemOutput(padCommand); if (strcmp(event, "")) { if (numberOfPads == 0) { @@ -294,9 +310,12 @@ int main(int argc, char** argv) { } if (strcmp("", getSystemOutput("ps -A | grep pulse"))) { if (isRecalbox == 1) { - system("killall pulseaudio >>/dev/null 2>&1"); //Kill PulseAudio if running, can sometimes halt game looking for ALSA + if (strcmp("RECALBOX 5", getSystemOutput("uname -a | tr ' ' '\\n' | grep RECALBOX | tr -d [:cntrl:]"))) { + system("killall pulseaudio >>/dev/null 2>&1"); //Kill PulseAudio if running below kernel 5, can sometimes halt game looking for ALSA + } } else { - system("sudo killall pulseaudio >>/dev/null 2>&1"); //Kill PulseAudio if running, can sometimes halt game looking for ALSA + system("sudo killall pulseaudio >>/dev/null 2>&1"); //Kill PulseAudio if running on RPi OS/RetroPie, can sometimes halt game looking for ALSA + // Note: Pulseaudio used to restart automatically on kernels below 5, keep an eye on how this is handled > 5 on RPi OS/RetroPie } } fflush(stdout); @@ -319,13 +338,13 @@ int main(int argc, char** argv) { close(fd); } - // Run copy of game to circumvent Recalbox' read-only file system + // Run copy of game to circumvent Recalbox' read-only(/) and/or non-executablel(.../share/roms exFAT) file systems if (isRecalbox == 1) { memset (game, 0, sizeof(game)); - strcat(game, "/tmp/arcade.elf"); + snprintf(game, 200, "/recalbox/share/bootvideos/makecode/%s", basename); //New location instead of /tmp allows for saving game states in settings and DB extensions etc. } - // Silence the game launch + // Silence the game launch information to Linux console if verbose option is not given char gameString[200]; memcpy(gameString, game, strlen(game)+1); if (strcmp("verbose", options)) { diff --git a/McAirpos/uinput-mapper/input-create b/McAirpos/uinput-mapper/input-create index 9ebcfab..cbb135f 100755 --- a/McAirpos/uinput-mapper/input-create +++ b/McAirpos/uinput-mapper/input-create @@ -13,7 +13,8 @@ try: except ImportError: import pickle -import imp +#import imp #Deprecated +#import importlib.machinery as imp #Deprecated and not backwards compatible with 2.7 import optparse _usage = 'python create.py /path/to/config1 ... /path/to/configN' @@ -31,7 +32,12 @@ parser.add_option('-v', '--verbose', action='store_true', args, cfg = parser.parse_args() # Unpickle from stdin ; currently this is the default and only way -in_f = pickle.Unpickler(sys.stdin) +# Python 3 changed os.write() to require to specify bytes vs strings, +# since strings=bytes in Python 2.7... +if sys.version_info.major == 3: + in_f = pickle.Unpickler(sys.stdin.buffer) +else: + in_f = pickle.Unpickler(sys.stdin) # Read input device count nifd = in_f.load() @@ -47,7 +53,15 @@ if args.verbose: # Allow configurations to change our current configuration for path in cfg: - config_merge = imp.load_source('', path).config_merge +# config_merge = imp.load_source('', path).config_merge #Deprecated +# config_merge = imp.SourceFileLoader('', path).load_module() #Deprecated in 3.5, not backwards compatible to 2.7 + + #Should work to dynamically load modules in 2.7-3.x + config_file = path + with open(config_file) as f: + code = compile(f.read(), config_file, 'exec') + exec(code, globals(), locals()) + config_merge(conf, names) if args.verbose: @@ -60,7 +74,8 @@ nofd = get_exported_device_count(conf) # Create and expose uinput devices ofs = [] -for f in xrange(nofd): +#for f in xrange(nofd): +for f in range(nofd): name = names[f] d = UInputDevice() m.expose(d, f) diff --git a/McAirpos/uinput-mapper/input-read b/McAirpos/uinput-mapper/input-read index 29c5cd8..00f7cea 100755 --- a/McAirpos/uinput-mapper/input-read +++ b/McAirpos/uinput-mapper/input-read @@ -36,10 +36,10 @@ if len(input_file) + len(args.grab) == 0: exit(0) # Open input devices -fs = map(InputDevice, input_file) +fs = list(map(InputDevice, input_file)) # Open devices in grab mode -fsg = map(InputDevice, args.grab) +fsg = list(map(InputDevice, args.grab)) # Grab devices for _ in fsg: @@ -73,16 +73,21 @@ for f in fs: # Human readable info if args.dump: for f in fs: - print 'Version:', f.get_version() - print f.get_name() + print ('Version:', f.get_version()) + print (f.get_name()) d = f.get_exposed_events() for k, v in d.iteritems(): - print k + ':', ', '.join(v) + print (k + ':', ', '.join(v)) else: # Dump initial information over pickle to stdout - p = pickle.Pickler(sys.stdout) + # Python 3.x requires to specify bytes vs strings, + # since in 2.7 strings=bytes... + if sys.version_info.major == 3: + p = pickle.Pickler(sys.stdout.buffer) + else: + p = pickle.Pickler(sys.stdout) p.dump(len(fs)) @@ -91,6 +96,7 @@ else: sys.stdout.flush() + while True: events = pp.poll() @@ -110,10 +116,10 @@ while True: if args.dump: try: - print i, ev.time.tv_sec, ev.time.tv_usec + print (i, ev.time.tv_sec, ev.time.tv_usec) s = '%s %s %d' % (rev_events[ev.type], rev_event_keys[ev.type][ev.code], ev.value) - print 'Event type:', s + print ('Event type:', s) except KeyError: pass diff --git a/McAirpos/uinput-mapper/uinputmapper/cinput.py b/McAirpos/uinput-mapper/uinputmapper/cinput.py index 8b439ca..f2c5287 100644 --- a/McAirpos/uinput-mapper/uinputmapper/cinput.py +++ b/McAirpos/uinput-mapper/uinputmapper/cinput.py @@ -1,5 +1,5 @@ -from linux_input import * -from linux_uinput import * +from uinputmapper.linux_input import * +from uinputmapper.linux_uinput import * import array, struct, fcntl, os, sys @@ -16,9 +16,15 @@ def get_input_name(f, l=256): """ Returns the name of a specified fd of a device """ - buf = array.array('c', ' ' * l) +# buf = array.array('c', ' ' * l) + buf = array.array('B', [0] * l) r = fcntl.ioctl(f, EVIOCGNAME(l), buf) - return ''.join(buf.tolist()[:r]) + buflist = buf.tolist() + buflistchar = [] + for i in range(0, r): + buflistchar.append(chr(buflist[i])) +# return ''.join(buf.tolist()[:r]) + return ''.join(buflistchar) def read_abs_values(f, abs_ev): buf = array.array('i', [0] * 6) @@ -30,17 +36,19 @@ def read_abs_values(f, abs_ev): _bpl = struct.calcsize('@L') * 8 _nbits = lambda x: ((x-1) / _bpl) + 1 _ll = _nbits(KEY_MAX) -test_bit = lambda j, v: (v[j / _bpl] >> (j % _bpl)) & 1 +#test_bit = lambda j, v: (v[j / _bpl] >> (j % _bpl)) & 1 +test_bit = lambda j, v: (v[int(j / _bpl)] >> (j % _bpl)) & 1 def get_keys(f, ev): """ Get keys of type *f* from a specific input device *f*. """ - buf = array.array('L', [0L] * _ll) +# buf = array.array('L', [0L] * _ll) + buf = array.array('L', [0] * int(_ll)) try: fcntl.ioctl(f, EVIOCGBIT(ev, KEY_MAX), buf) except IOError: - #print >>sys.stderr, 'Whoops!', rev_events[ev] + #print >>sys.stderr, 'Whoopso!', rev_events[ev] return None v = struct.unpack('@%dL' % _ll, buf) @@ -89,7 +97,8 @@ def get_exposed_events(self): Returns all the keys exposed by this input device. """ d = dict() - for k, v in events.iteritems(): +# for k, v in events.iteritems(): + for k, v in events.items(): l = get_keys(self._f, v) if l: d[k] = [] @@ -142,7 +151,7 @@ def open_uinput(): try: f = os.open('/dev/input/uinput', os.O_WRONLY | os.O_NONBLOCK) except OSError: - print 'FAIL MUCH?' + print ('FAIL MUCH?') return None return f @@ -157,13 +166,17 @@ def write_uinput_device_info(uidev, f, name): # Allocate other info # TODO: Get from specs - uidev.name = name +# uidev.name = name + uidev.name = name.encode() uidev._id.bustype = 0x03 # BUS_USB (TODO) uidev._id.vendor = 0x42 uidev._id.product = 0xbebe uidev._id.version = 1 - buf = buffer(uidev)[:] + if sys.version_info.major == 3: + buf = bytes(memoryview(uidev))[:] + else: + buf = buffer(uidev)[:] # Write dev info os.write(f, buf) @@ -185,7 +198,7 @@ class UInputDevice(object): def __init__(self): self._f = open_uinput() if not self._f: - print 'Failed to open uinput' + print ('Failed to open uinput') raise OSError self.uidev = uinput_user_dev() @@ -218,7 +231,10 @@ def fire_event(self, ev): """ Fire a new input event. """ - os.write(self._f, buffer(ev)[:]) + if sys.version_info.major == 3: + os.write(self._f, bytes(memoryview(ev))[:]) + else: + os.write(self._f, buffer(ev)[:]) def __del__(self): if hasattr(self, '_f'): diff --git a/McAirpos/uinput-mapper/uinputmapper/ioctlhelp.py b/McAirpos/uinput-mapper/uinputmapper/ioctlhelp.py index 5448ac6..b729111 100644 --- a/McAirpos/uinput-mapper/uinputmapper/ioctlhelp.py +++ b/McAirpos/uinput-mapper/uinputmapper/ioctlhelp.py @@ -25,7 +25,8 @@ def IOC(_dir, _type, nr, size): - if type(size) in (str, unicode): +# if type(size) in (str, unicode): + if type(size) in (str, u''.__class__): size = struct.calcsize(size) return _dir << _IOC_DIRSHIFT | _type << _IOC_TYPESHIFT | \ nr << _IOC_NRSHIFT | size << _IOC_SIZESHIFT diff --git a/McAirpos/uinput-mapper/uinputmapper/linux_input.py b/McAirpos/uinput-mapper/uinputmapper/linux_input.py index 6f548a8..8a6520e 100644 --- a/McAirpos/uinput-mapper/uinputmapper/linux_input.py +++ b/McAirpos/uinput-mapper/uinputmapper/linux_input.py @@ -2,19 +2,27 @@ import struct -from uinput_gen import input_constants_dict as icd +from uinputmapper.uinput_gen import input_constants_dict as icd -for k, v in icd.iteritems(): - locals()[k] = v -rdict = lambda x: dict(map(lambda (k, v): (v, k), x.iteritems())) +#for k, v in icd.iteritems(): +# locals()[k] = v +for k, v in icd.items(): + locals()[k] = v -events = dict(filter(lambda (k, v): k in ["EV_SYN", "EV_KEY", "EV_REL", +#rdict = lambda x: dict(map(lambda (k, v): (v, k), x.iteritems())) +rdict = lambda x: dict(map(lambda kv: (kv[1], kv[0]), x.items())) + +#events = dict(filter(lambda (k, v): k in ["EV_SYN", "EV_KEY", "EV_REL", +# "EV_ABS", "EV_MSC", "EV_SW", "EV_LED", "EV_SND", "EV_REP", +# "EV_FF", "EV_PWR", "EV_FF_STATUS"], icd.iteritems())) +events = dict(filter(lambda kv: kv[0] in ["EV_SYN", "EV_KEY", "EV_REL", "EV_ABS", "EV_MSC", "EV_SW", "EV_LED", "EV_SND", "EV_REP", - "EV_FF", "EV_PWR", "EV_FF_STATUS"], icd.iteritems())) + "EV_FF", "EV_PWR", "EV_FF_STATUS"], icd.items())) rev_events = rdict(events) -filter_event = lambda c: dict(filter(lambda (k, v): c(k), icd.iteritems())) +#filter_event = lambda c: dict(filter(lambda (k, v): c(k), icd.iteritems())) +filter_event = lambda c: dict(filter(lambda kv: c(kv[0]), icd.items())) keys = filter_event(lambda x: x.startswith("KEY_") or x.startswith("BTN_")) rev_keys = rdict(keys) @@ -108,7 +116,7 @@ class input_absinfo(ctypes.Structure): ] -from ioctlhelp import IOR, IOW, IOC, IO, _IOC_READ +from uinputmapper.ioctlhelp import IOR, IOW, IOC, IO, _IOC_READ # Get driver version EVIOCGVERSION = IOR(ord('E'), 0x01, '@i') diff --git a/McAirpos/uinput-mapper/uinputmapper/linux_uinput.py b/McAirpos/uinput-mapper/uinputmapper/linux_uinput.py index 9f2bcc0..5a269b9 100644 --- a/McAirpos/uinput-mapper/uinputmapper/linux_uinput.py +++ b/McAirpos/uinput-mapper/uinputmapper/linux_uinput.py @@ -1,6 +1,8 @@ -from ioctlhelp import * +from uinputmapper.ioctlhelp import * +import sys + +import uinputmapper.linux_input as linux_input -import linux_input # For uinput version 3 @@ -48,7 +50,7 @@ UI_FF_ERASE = 2 import ctypes -import linux_input +import uinputmapper.linux_input as linux_input UINPUT_MAX_NAME_SIZE = 80 class uinput_user_dev(ctypes.Structure): diff --git a/McAirpos/uinput-mapper/uinputmapper/mapper.py b/McAirpos/uinput-mapper/uinputmapper/mapper.py index f4123c0..4b9933f 100644 --- a/McAirpos/uinput-mapper/uinputmapper/mapper.py +++ b/McAirpos/uinput-mapper/uinputmapper/mapper.py @@ -1,5 +1,6 @@ # encoding: utf-8 -import cinput +import uinputmapper.cinput as cinput +import sys """ Module to help out with config parsing and input mapping @@ -14,7 +15,8 @@ def parse_conf(f, devname): """ conf = {} e = f.get_exposed_events() - for k, v in e.iteritems(): +# for k, v in e.iteritems(): + for k, v in e.items(): t = cinput.events[k] if t == cinput.EV_SYN: continue @@ -47,20 +49,28 @@ def pretty_conf_print(c): """ Function to print an entire configuration """ - for k, v in c.iteritems(): - print 'Input:', k[0], 'Type:', cinput.rev_events[k[1]] - for kk, vv in v.iteritems(): +# for k, v in c.iteritems(): + for k, v in c.items(): + print ('Input:', k[0], 'Type:', cinput.rev_events[k[1]]) +# for kk, vv in v.iteritems(): + for kk, vv in v.items(): n_ev_d, n_ev_t = vv['type'] - print ' ' * 4, - print cinput.rev_event_keys[k[1]][kk], - print ' → ([%d, %s], %s)' % (n_ev_d, - cinput.rev_events[n_ev_t], - cinput.rev_event_keys[n_ev_t][vv['code']]) + #Check for Python version to actually get pretty_conf_print in all versions 2.7-3.x... + if sys.version_info.major == 3: + print (' ' * 4, cinput.rev_event_keys[k[1]][kk], ' → ([%d, %s], %s)' % (n_ev_d, + cinput.rev_events[n_ev_t], + cinput.rev_event_keys[n_ev_t][vv['code']])) + else: + print (' ' * 4), + print (cinput.rev_event_keys[k[1]][kk]), + print (' → ([%d, %s], %s)' % (n_ev_d, + cinput.rev_events[n_ev_t], + cinput.rev_event_keys[n_ev_t][vv['code']])) if n_ev_t == cinput.EV_ABS: - print 'Properties: Max: %d Min: %d Fuzz: %d Flat: %d' % ( + print ('Properties: Max: %d Min: %d Fuzz: %d Flat: %d' % ( vv['prop']['max'], vv['prop']['min'], - vv['prop']['fuzz'], vv['prop']['flat']) + vv['prop']['fuzz'], vv['prop']['flat'])) def get_exported_device_count(c): """ @@ -68,8 +78,10 @@ def get_exported_device_count(c): (Rather simple at the moment) """ m = 0 - for _, v in c.iteritems(): - for _, o in v.iteritems(): +# for _, v in c.iteritems(): + for _, v in c.items(): +# for _, o in v.iteritems(): + for _, o in v.items(): m = max(m, o['type'][0]) return m + 1 @@ -105,8 +117,10 @@ def expose(self, d, fd): Expose exposes events to a uinput-device *d* with index *fd* from the config passed to __init__. """ - for (n, evt), v in self._config.iteritems(): - for code, dat in v.iteritems(): +# for (n, evt), v in self._config.iteritems(): + for (n, evt), v in self._config.items(): +# for code, dat in v.iteritems(): + for code, dat in v.items(): ofd, t = dat['type'] if ofd != fd: continue