mirror of
https://github.com/TomHarte/CLK.git
synced 2024-08-16 16:28:59 +00:00
130 lines
4.0 KiB
C++
130 lines
4.0 KiB
C++
//
|
|
// Typer.hpp
|
|
// Clock Signal
|
|
//
|
|
// Created by Thomas Harte on 19/06/2016.
|
|
// Copyright © 2016 Thomas Harte. All rights reserved.
|
|
//
|
|
|
|
#ifndef Typer_hpp
|
|
#define Typer_hpp
|
|
|
|
#include <memory>
|
|
#include "KeyboardMachine.hpp"
|
|
#include "../ClockReceiver/ClockReceiver.hpp"
|
|
|
|
namespace Utility {
|
|
|
|
/*!
|
|
An interface that provides a mapping from logical characters to the sequence of keys
|
|
necessary to type that character on a given machine.
|
|
*/
|
|
class CharacterMapper {
|
|
public:
|
|
/// @returns The EndSequence-terminated sequence of keys that would cause @c character to be typed.
|
|
virtual uint16_t *sequence_for_character(char character) = 0;
|
|
|
|
/// Terminates a key sequence.
|
|
static const uint16_t EndSequence = 0xffff;
|
|
|
|
/*!
|
|
If returned as the first entry in a key sequence, indicates that the requested character
|
|
cannot be mapped.
|
|
*/
|
|
static const uint16_t NotMapped = 0xfffe;
|
|
|
|
protected:
|
|
typedef uint16_t KeySequence[16];
|
|
|
|
/*!
|
|
Provided in the base class as a convenience: given the lookup table of key sequences @c sequences,
|
|
with @c length entries, returns the sequence for character @c character if it exists; otherwise
|
|
returns @c nullptr.
|
|
*/
|
|
uint16_t *table_lookup_sequence_for_character(KeySequence *sequences, size_t length, char character);
|
|
};
|
|
|
|
/*!
|
|
Provides a stateful mechanism for typing a sequence of characters. Each character is mapped to a key sequence
|
|
by a character mapper. That key sequence is then replayed to a delegate.
|
|
|
|
Being given a delay and frequency at construction, the run_for interface can be used to produce time-based
|
|
typing. Alternatively, an owner may decline to use run_for and simply call type_next_character each time a
|
|
fresh key transition is ready to be consumed.
|
|
*/
|
|
class Typer {
|
|
public:
|
|
class Delegate: public KeyboardMachine::Machine {
|
|
public:
|
|
virtual void typer_reset(Typer *typer) = 0;
|
|
};
|
|
|
|
Typer(const char *string, HalfCycles delay, HalfCycles frequency, std::unique_ptr<CharacterMapper> character_mapper, Delegate *delegate);
|
|
~Typer();
|
|
|
|
void run_for(const HalfCycles duration);
|
|
bool type_next_character();
|
|
|
|
bool is_completed();
|
|
|
|
const char BeginString = 0x02; // i.e. ASCII start of text
|
|
const char EndString = 0x03; // i.e. ASCII end of text
|
|
|
|
private:
|
|
char *string_;
|
|
size_t string_pointer_;
|
|
|
|
HalfCycles frequency_;
|
|
HalfCycles counter_;
|
|
int phase_;
|
|
|
|
Delegate *delegate_;
|
|
std::unique_ptr<CharacterMapper> character_mapper_;
|
|
|
|
bool try_type_next_character();
|
|
};
|
|
|
|
/*!
|
|
Provides a default base class for type recipients: classes that want to attach a single typer at a time and
|
|
which may or may not want to nominate an initial delay and typing frequency.
|
|
*/
|
|
class TypeRecipient: public Typer::Delegate {
|
|
public:
|
|
/// Attaches a typer to this class that will type @c string using @c character_mapper as a source.
|
|
void set_typer_for_string(const char *string, std::unique_ptr<CharacterMapper> character_mapper) {
|
|
typer_.reset(new Typer(string, get_typer_delay(), get_typer_frequency(), std::move(character_mapper), this));
|
|
}
|
|
|
|
/*!
|
|
Provided as a hook for subclasses to implement so that external callers can install a typer
|
|
without needing inside knowledge as to where the character mapper comes from.
|
|
*/
|
|
virtual void set_typer_for_string(const char *string) = 0;
|
|
|
|
/*!
|
|
Provided in order to conform to that part of the Typer::Delegate interface that goes above and
|
|
beyond KeyboardMachine::Machine; responds to the end of typing by clearing all keys.
|
|
*/
|
|
void typer_reset(Typer *typer) {
|
|
clear_all_keys();
|
|
|
|
// It's unsafe to deallocate typer right now, since it is the caller, but also it has a small
|
|
// memory footprint and it's desireable not to imply that the subclass need call it any more.
|
|
// So shuffle it off into a siding.
|
|
previous_typer_ = std::move(typer_);
|
|
typer_ = nullptr;
|
|
}
|
|
|
|
protected:
|
|
virtual HalfCycles get_typer_delay() { return HalfCycles(0); }
|
|
virtual HalfCycles get_typer_frequency() { return HalfCycles(0); }
|
|
std::unique_ptr<Typer> typer_;
|
|
|
|
private:
|
|
std::unique_ptr<Typer> previous_typer_;
|
|
};
|
|
|
|
}
|
|
|
|
#endif /* Typer_hpp */
|