--- hatari/tools/hconsole/hconsole.py 2019/04/09 08:51:30 1.1.1.3 +++ hatari/tools/hconsole/hconsole.py 2019/04/09 08:54:53 1.1.1.6 @@ -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-2012 by Eero Tamminen +# Copyright (C) 2008-2014 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" @@ -64,7 +100,7 @@ class Hatari: controlpath = "/tmp/hatari-console-" + str(os.getpid()) + ".socket" hataribin = "hatari" - def __init__(self, args = None): + def __init__(self, args): # collect hatari process zombies without waitpid() signal.signal(signal.SIGCHLD, signal.SIG_IGN) self._assert_hatari_compatibility() @@ -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: @@ -131,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) @@ -145,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 "): @@ -299,6 +367,7 @@ class Tokens: "--ym-mixing", "--debug", "--bios-intercept", + "--conout", "--trace", "--trace-file", "--parse", @@ -377,7 +446,7 @@ class Tokens: "trace" ] - def __init__(self, hatari): + def __init__(self, hatari, do_exit = True): self.process_tokens = { "kill": hatari.kill_hatari, "pause": hatari.toggle_pause @@ -391,6 +460,8 @@ class Tokens: "verbose": hatari.toggle_verbose } self.hatari = hatari + # whether to exit when Hatari disappears + self.do_exit = do_exit def get_tokens(self): tokens = [] @@ -468,10 +539,13 @@ give help when you give them invalid inp def process_command(self, line): if not self.hatari.is_running(): - print("Exiting as there's no Hatari (anymore)...") + print("There's no Hatari (anymore)!") + if not self.do_exit: + return False + print("Exiting...") sys.exit(0) if not line: - return + return False first = line.split()[0] # multiple items @@ -496,13 +570,14 @@ give help when you give them invalid inp self.help_tokens[line]() else: print("ERROR: unknown hatari-console command:", line) - + return False + return True class Main: - def __init__(self): - args, self.file, self.exit = self.parse_args(sys.argv) + def __init__(self, options, do_exit=True): + args, self.file, self.exit = self.parse_args(options) hatari = Hatari(args) - self.tokens = Tokens(hatari) + self.tokens = Tokens(hatari, do_exit) self.command = CommandInput(self.tokens.get_tokens()) def parse_args(self, args): @@ -569,9 +644,9 @@ For example: self.tokens.do_script("script " + filename) def run(self, line): - "helper method for scripts using hatari-console" - self.tokens.process_command(line) + "helper method for running Hatari commands with hatari-console, returns False on error" + return self.tokens.process_command(line) if __name__ == "__main__": - Main().loop() + Main(sys.argv).loop()