// // Typer.cpp // Clock Signal // // Created by Thomas Harte on 19/06/2016. // Copyright © 2016 Thomas Harte. All rights reserved. // #include "Typer.hpp" #include using namespace Utility; Typer::Typer(const char *string, HalfCycles delay, HalfCycles frequency, std::unique_ptr character_mapper, Delegate *delegate) : counter_(-delay), frequency_(frequency), string_pointer_(0), delegate_(delegate), phase_(0), character_mapper_(std::move(character_mapper)) { size_t string_size = strlen(string) + 3; string_ = (char *)malloc(string_size); snprintf(string_, string_size, "%c%s%c", Typer::BeginString, string, Typer::EndString); } void Typer::run_for(const HalfCycles duration) { if(string_) { if(counter_ < 0 && counter_ + duration >= 0) { if(!type_next_character()) { delegate_->typer_reset(this); } } counter_ += duration; while(string_ && counter_ > frequency_) { counter_ -= frequency_; if(!type_next_character()) { delegate_->typer_reset(this); } } } } bool Typer::try_type_next_character() { uint16_t *sequence = character_mapper_->sequence_for_character(string_[string_pointer_]); if(!sequence || sequence[0] == CharacterMapper::NotMapped) { return false; } if(!phase_) delegate_->clear_all_keys(); else { delegate_->set_key_state(sequence[phase_ - 1], true); return sequence[phase_] == CharacterMapper::EndSequence; } return true; } bool Typer::type_next_character() { if(string_ == nullptr) return false; if(!try_type_next_character()) { phase_ = 0; if(!string_[string_pointer_]) { free(string_); string_ = nullptr; return false; } string_pointer_++; } else { phase_++; } return true; } Typer::~Typer() { free(string_); } #pragma mark - Character mapper uint16_t *CharacterMapper::table_lookup_sequence_for_character(KeySequence *sequences, size_t length, char character) { size_t ucharacter = (size_t)((unsigned char)character); if(ucharacter > (length / sizeof(KeySequence))) return nullptr; if(sequences[ucharacter][0] == NotMapped) return nullptr; return sequences[ucharacter]; }