--- hatari/tools/hconsole/hconsole.py 2019/04/09 08:49:54 1.1 +++ hatari/tools/hconsole/hconsole.py 2019/04/09 08:52:26 1.1.1.4 @@ -5,7 +5,7 @@ # devices and changing Hatari command line options (even for things you # cannot change from the UI) from the console while Hatari is running. # -# Copyright (C) 2008-2011 by Eero Tamminen +# Copyright (C) 2008-2012 by Eero Tamminen # # 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 @@ -33,10 +33,46 @@ if str is bytes: def input(prompt): return raw_input(prompt) -# Atari scancodes for special keys, needed when wanting to -# output something else than alphanumberic keys to Hatari -# (when using keypress/down/up commands) class Scancode: + "Atari scancodes for keys without alphanumeric characters" + # US keyboard scancode mapping for characters which need shift + Shifted = { + '!': "0x2", + '@': "0x3", + '#': "0x4", + '$': "0x5", + '%': "0x6", + '^': "0x7", + '&': "0x8", + '*': "0x9", + '(': "10", + ')': "11", + '_': "12", + '+': "13", + '~': "41", + '{': "26", + '}': "27", + ':': "39", + '"': "40", + '|': "43", + '<': "51", + '>': "52", + '?': "53" + } + # US keyboard scancode mapping for characters which don't need shift + UnShifted = { + '-': "12", + '=': "13", + '[': "26", + ']': "27", + ';': "39", + "'": "40", + '\\': "43", + '",': "51", + '.': "52", + '/': "53" + } + # special keys without corresponding character Tab = "15" Return = "28" Enter = "114" @@ -80,14 +116,24 @@ class Hatari: if not self.run_hatari(args): print("ERROR: failed to run Hatari") sys.exit(1) + self.shiftdown = False self.verbose = False def _assert_hatari_compatibility(self): - for line in os.popen(self.hataribin + " -h").readlines(): + "check Hatari compatibility and return error string if it's not" + error = True + pipe = os.popen(self.hataribin + " -h") + for line in pipe.readlines(): if line.find("--control-socket") >= 0: - return - print("ERROR: Hatari not found or it doesn't support the required --control-socket option!") - sys.exit(-1) + error = False + break + try: + pipe.close() + except IOError: + pass + if error: + print("ERROR: %s" % error) + sys.exit(-1) def is_running(self): if not self.pid: @@ -97,6 +143,9 @@ class Hatari: except OSError as value: print("Hatari PID %d had exited in the meanwhile:\n\t%s" % (self.pid, value)) self.pid = 0 + if self.control: + self.control.close() + self.control = None return False return True @@ -128,7 +177,7 @@ class Hatari: self.control.sendall(bytes(msg + "\n", "ASCII")) # KLUDGE: wait so that Hatari output comes before next prompt if fast: - interval = self.interval/2 + interval = self.interval/4 else: interval = self.interval time.sleep(interval) @@ -142,16 +191,38 @@ class Hatari: def trigger_shortcut(self, shortcut): return self.send_message("hatari-shortcut %s" % shortcut) + + def _shift_up(self): + if self.shiftdown: + self.shiftdown = False + return self.send_message("hatari-event keyup %s" % Scancode.LeftShift, True) + return True + + def _unshifted_keypress(self, key): + self._shift_up() + if key == ' ': + # white space gets stripped, use scancode instead + key = Scancode.Space + return self.send_message("hatari-event keypress %s" % key, True) + + def _shifted_keypress(self, key): + if not self.shiftdown: + self.shiftdown = True + self.send_message("hatari-event keydown %s" % Scancode.LeftShift, True) + return self.send_message("hatari-event keypress %s" % key, True) def send_string(self, text): print("string:", text) - for item in text: - if item == ' ': - # white space gets stripped, use scancode instead - item = "57" - if not self.send_message("hatari-event keypress %s" % item, True): + for key in text: + if key in Scancode.Shifted: + ok = self._shifted_keypress(Scancode.Shifted[key]) + elif key in Scancode.UnShifted: + ok = self._unshifted_keypress(Scancode.UnShifted[key]) + else: + ok = self._unshifted_keypress(key) + if not ok: return False - return True + return self._shift_up() def insert_event(self, event): if event.startswith("text "): @@ -181,11 +252,13 @@ class Hatari: print("debug output", self.verbose) def kill_hatari(self): - if self.pid: + if self.is_running(): os.kill(self.pid, signal.SIGKILL) print("killed hatari with PID %d" % self.pid) - self.control = None self.pid = 0 + if self.control: + self.control.close() + self.control = None # command line parsing with readline @@ -218,36 +291,40 @@ class CommandInput: class Tokens: - # update with: hatari -h|grep -- --|sed 's/^ *\(--[^ ]*\).*$/ "\1",/' + # update with: hatari -h|grep -- --|sed 's/^ *\(--[^ ]*\).*$/ "\1",/'|grep -v -e control-socket -e 'joy<' option_tokens = [ "--help", "--version", "--confirm-quit", "--configfile", + "--keymap", "--fast-forward", "--mono", "--monitor", "--fullscreen", "--window", "--grab", - "--zoom", - "--max-width", - "--max-height", - "--aspect", - "--borders", "--frameskips", "--statusbar", "--drive-led", - "--spec512", "--bpp", + "--borders", + "--desktop-st", + "--spec512", + "--zoom", + "--desktop", + "--max-width", + "--max-height", + "--force-max", + "--aspect", "--vdi", "--vdi-planes", "--vdi-width", "--vdi-height", + "--crop", "--avirecord", "--avi-vcodec", "--avi-fps", - "--avi-crop", "--avi-file", "--joy0", "--joy1", @@ -263,7 +340,7 @@ class Tokens: "--rs232-out", "--disk-a", "--disk-b", - "--slowfdc", + "--fastfdc", "--protect-floppy", "--protect-hd", "--harddrive", @@ -271,24 +348,30 @@ class Tokens: "--ide-master", "--ide-slave", "--memsize", + "--memstate", "--tos", + "--patch-tos", "--cartridge", - "--memstate", "--cpulevel", "--cpuclock", "--compatible", "--machine", "--blitter", - "--timer-d", "--dsp", + "--timer-d", + "--fast-boot", + "--rtc", + "--mic", "--sound", - "--keymap", + "--sound-buffer-size", + "--ym-mixing", "--debug", "--bios-intercept", "--trace", "--trace-file", "--parse", "--saveconfig", + "--no-parachute", "--log-file", "--log-level", "--alert-level", @@ -343,8 +426,8 @@ class Tokens: "dspreg", "dspsymbols", "evaluate", - "exec", "help", + "history", "info", "loadbin", "lock", @@ -352,6 +435,8 @@ class Tokens: "memdump", "memwrite", "parse", + "profile", + "quit", "savebin", "setopt", "stateload",