diff --git a/README.md b/README.md index 023f308..a2f0b71 100644 --- a/README.md +++ b/README.md @@ -329,6 +329,14 @@ yes = true ; Be quiet, suppress all notices/warnings, default: no quiet = true +; Define hotkey for pausing recording (suspending capture of output), +; default: C-\ +pause_key = C-p + +; Define hotkey prefix key - when defined other recording hotkeys must +; be preceeded by it, default: no prefix +prefix_key = C-a + [play] ; Playback speed (can be fractional), default: 1 diff --git a/asciinema/commands/record.py b/asciinema/commands/record.py index 904ba5a..b91d472 100644 --- a/asciinema/commands/record.py +++ b/asciinema/commands/record.py @@ -28,6 +28,10 @@ class RecordCommand(Command): self.writer = raw.writer if args.raw else v2.writer self.notifier = notifier.get_notifier(config.notifications_enabled, config.notifications_command) self.env = env + self.key_bindings = { + 'prefix': config.record_prefix_key, + 'pause': config.record_pause_key + } def execute(self): upload = False @@ -78,7 +82,8 @@ class RecordCommand(Command): capture_env=vars, rec_stdin=self.rec_stdin, writer=self.writer, - notifier=self.notifier + notifier=self.notifier, + key_bindings=self.key_bindings ) except v2.LoadError: self.print_error("can only append to asciicast v2 format recordings") diff --git a/asciinema/config.py b/asciinema/config.py index 3121a49..a7ae0b5 100644 --- a/asciinema/config.py +++ b/asciinema/config.py @@ -109,6 +109,14 @@ class Config: def record_quiet(self): return self.config.getboolean('record', 'quiet', fallback=False) + @property + def record_prefix_key(self): + return self.__get_key('record', 'prefix') + + @property + def record_pause_key(self): + return self.__get_key('record', 'pause', 'C-\\') + @property def play_idle_time_limit(self): fallback = self.config.getfloat('play', 'maxwait', fallback=None) # pre 2.0 @@ -126,6 +134,20 @@ class Config: def notifications_command(self): return self.config.get('notifications', 'command', fallback=None) + def __get_key(self, section, name, default=None): + key = self.config.get(section, f'{name}_key', fallback=default) + + if key: + if len(key) == 3: + upper_key = key.upper() + + if upper_key[0] == 'C' and upper_key[1] == '-': + return bytes([ord(upper_key[2]) - 0x40]) + else: + raise ConfigError(f'invalid {name} key definition \'{key}\' - use: {name}_key = C-x (with control key modifier), or {name}_key = x (with no modifier)') + else: + return key.encode('utf-8') + def get_config_home(env=os.environ): env_asciinema_config_home = env.get("ASCIINEMA_CONFIG_HOME") diff --git a/asciinema/pty.py b/asciinema/pty.py index 8489bab..e5d66a6 100644 --- a/asciinema/pty.py +++ b/asciinema/pty.py @@ -15,10 +15,13 @@ import time from asciinema.term import raw -def record(command, writer, env=os.environ, rec_stdin=False, time_offset=0, notifier=None): +def record(command, writer, env=os.environ, rec_stdin=False, time_offset=0, notifier=None, key_bindings={}): master_fd = None start_time = None pause_time = None + prefix_mode = False + prefix_key = key_bindings.get('prefix') + pause_key = key_bindings.get('pause') def _notify(text): if notifier: @@ -64,20 +67,30 @@ def record(command, writer, env=os.environ, rec_stdin=False, time_offset=0, noti nonlocal pause_time nonlocal start_time + nonlocal prefix_mode - if data == b'\x10': # ctrl+p - if pause_time: - start_time = start_time + (time.time() - pause_time) - pause_time = None - _notify('Resumed recording') - else: - pause_time = time.time() - _notify('Paused recording') - else: - _write_master(data) + if not prefix_mode and prefix_key and data == prefix_key: + prefix_mode = True + return - if rec_stdin and not pause_time: - writer.write_stdin(time.time() - start_time, data) + if prefix_mode or (not prefix_key and data in [pause_key]): + prefix_mode = False + + if data == pause_key: + if pause_time: + start_time = start_time + (time.time() - pause_time) + pause_time = None + _notify('Resumed recording') + else: + pause_time = time.time() + _notify('Paused recording') + + return + + _write_master(data) + + if rec_stdin and not pause_time: + writer.write_stdin(time.time() - start_time, data) def _signals(signal_list): old_handlers = [] diff --git a/asciinema/recorder.py b/asciinema/recorder.py index 41a5202..1c02d49 100644 --- a/asciinema/recorder.py +++ b/asciinema/recorder.py @@ -9,7 +9,8 @@ from asciinema.async_worker import async_worker def record(path, command=None, append=False, idle_time_limit=None, rec_stdin=False, title=None, metadata=None, command_env=None, - capture_env=None, writer=v2.writer, record=pty.record, notifier=None): + capture_env=None, writer=v2.writer, record=pty.record, notifier=None, + key_bindings={}): if command is None: command = os.environ.get('SHELL') or 'sh' @@ -53,7 +54,8 @@ def record(path, command=None, append=False, idle_time_limit=None, command_env, rec_stdin, time_offset, - n + n, + key_bindings )