Merge pull request #297 from lukhnos/remove-using-namespace-std

Remove the "using namespace" usage in McBopomofo's C++ and Objective-C++ code
This commit is contained in:
Lukhnos Liu 2022-02-20 08:10:19 -08:00 committed by GitHub
commit 9a29456914
8 changed files with 259 additions and 402 deletions

View File

@ -29,25 +29,27 @@ extern unsigned short vxSC2TCTable[];
const size_t vxTC2SCTableSize = 3059; const size_t vxTC2SCTableSize = 3059;
extern unsigned short vxTC2SCTable[]; extern unsigned short vxTC2SCTable[];
struct VXHCData struct VXHCData {
{
unsigned short key, value; unsigned short key, value;
}; };
int VXHCCompare(const void *a, const void *b) int VXHCCompare(const void *a, const void *b)
{ {
unsigned short x=((const struct VXHCData*)a)->key, y=((const struct VXHCData*)b)->key; unsigned short x = ((const struct VXHCData *)a)->key, y = ((const struct VXHCData *)b)->key;
if (x==y) return 0; if (x == y)
if (x<y) return -1; return 0;
if (x < y)
return -1;
return 1; return 1;
} }
unsigned short VXHCFind(unsigned key, unsigned short *table, size_t size) unsigned short VXHCFind(unsigned key, unsigned short *table, size_t size)
{ {
struct VXHCData k; struct VXHCData k;
k.key=key; k.key = key;
struct VXHCData *d=(struct VXHCData*)bsearch(&k, table, size, sizeof(struct VXHCData), VXHCCompare); struct VXHCData *d = (struct VXHCData *)bsearch(&k, table, size, sizeof(struct VXHCData), VXHCCompare);
if (!d) return 0; if (!d)
return 0;
return d->value; return d->value;
} }
@ -66,8 +68,8 @@ unsigned short VXUCS2SimpToTradChinese(unsigned short c)
+ (NSString *)convertToSimplifiedFrom:(NSString *)string NS_SWIFT_NAME(convertToSimplified(from:)) + (NSString *)convertToSimplifiedFrom:(NSString *)string NS_SWIFT_NAME(convertToSimplified(from:))
{ {
NSData *utf16Data = [string dataUsingEncoding:NSUTF16StringEncoding]; NSData *utf16Data = [string dataUsingEncoding:NSUTF16StringEncoding];
unsigned short * bytes = (unsigned short *)utf16Data.bytes; unsigned short *bytes = (unsigned short *)utf16Data.bytes;
for(NSInteger i = 0; i < utf16Data.length; i++) { for (NSInteger i = 0; i < utf16Data.length; i++) {
unsigned short c = bytes[i]; unsigned short c = bytes[i];
unsigned short value = VXUCS2TradToSimpChinese(c); unsigned short value = VXUCS2TradToSimpChinese(c);
bytes[i] = value ? value : c; bytes[i] = value ? value : c;
@ -79,8 +81,8 @@ unsigned short VXUCS2SimpToTradChinese(unsigned short c)
+ (NSString *)convertToTraditionalFrom:(NSString *)string NS_SWIFT_NAME(convertToTraditional(from:)) + (NSString *)convertToTraditionalFrom:(NSString *)string NS_SWIFT_NAME(convertToTraditional(from:))
{ {
NSData *utf16Data = [string dataUsingEncoding:NSUTF16StringEncoding]; NSData *utf16Data = [string dataUsingEncoding:NSUTF16StringEncoding];
unsigned short * bytes = (unsigned short *)utf16Data.bytes; unsigned short *bytes = (unsigned short *)utf16Data.bytes;
for(NSInteger i = 0; i < utf16Data.length; i++) { for (NSInteger i = 0; i < utf16Data.length; i++) {
unsigned short c = bytes[i]; unsigned short c = bytes[i];
unsigned short value = VXUCS2SimpToTradChinese(c); unsigned short value = VXUCS2SimpToTradChinese(c);
bytes[i] = value ? value : c; bytes[i] = value ? value : c;

View File

@ -25,7 +25,7 @@
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
using namespace McBopomofo; namespace McBopomofo {
McBopomofoLM::McBopomofoLM() McBopomofoLM::McBopomofoLM()
{ {
@ -87,43 +87,43 @@ void McBopomofoLM::loadPhraseReplacementMap(const char* phraseReplacementPath)
} }
} }
const vector<Bigram> McBopomofoLM::bigramsForKeys(const string& preceedingKey, const string& key) const std::vector<Formosa::Gramambular::Bigram> McBopomofoLM::bigramsForKeys(const std::string& preceedingKey, const std::string& key)
{ {
return vector<Bigram>(); return std::vector<Formosa::Gramambular::Bigram>();
} }
const vector<Unigram> McBopomofoLM::unigramsForKey(const string& key) const std::vector<Formosa::Gramambular::Unigram> McBopomofoLM::unigramsForKey(const std::string& key)
{ {
if (key == " ") { if (key == " ") {
vector<Unigram> spaceUnigrams; std::vector<Formosa::Gramambular::Unigram> spaceUnigrams;
Unigram g; Formosa::Gramambular::Unigram g;
g.keyValue.key = " "; g.keyValue.key = " ";
g.keyValue.value= " "; g.keyValue.value = " ";
g.score = 0; g.score = 0;
spaceUnigrams.push_back(g); spaceUnigrams.push_back(g);
return spaceUnigrams; return spaceUnigrams;
} }
vector<Unigram> allUnigrams; std::vector<Formosa::Gramambular::Unigram> allUnigrams;
vector<Unigram> userUnigrams; std::vector<Formosa::Gramambular::Unigram> userUnigrams;
unordered_set<string> excludedValues; std::unordered_set<std::string> excludedValues;
unordered_set<string> insertedValues; std::unordered_set<std::string> insertedValues;
if (m_excludedPhrases.hasUnigramsForKey(key)) { if (m_excludedPhrases.hasUnigramsForKey(key)) {
vector<Unigram> excludedUnigrams = m_excludedPhrases.unigramsForKey(key); std::vector<Formosa::Gramambular::Unigram> excludedUnigrams = m_excludedPhrases.unigramsForKey(key);
transform(excludedUnigrams.begin(), excludedUnigrams.end(), transform(excludedUnigrams.begin(), excludedUnigrams.end(),
inserter(excludedValues, excludedValues.end()), inserter(excludedValues, excludedValues.end()),
[](const Unigram& u) { return u.keyValue.value; }); [](const Formosa::Gramambular::Unigram& u) { return u.keyValue.value; });
} }
if (m_userPhrases.hasUnigramsForKey(key)) { if (m_userPhrases.hasUnigramsForKey(key)) {
vector<Unigram> rawUserUnigrams = m_userPhrases.unigramsForKey(key); std::vector<Formosa::Gramambular::Unigram> rawUserUnigrams = m_userPhrases.unigramsForKey(key);
userUnigrams = filterAndTransformUnigrams(rawUserUnigrams, excludedValues, insertedValues); userUnigrams = filterAndTransformUnigrams(rawUserUnigrams, excludedValues, insertedValues);
} }
if (m_languageModel.hasUnigramsForKey(key)) { if (m_languageModel.hasUnigramsForKey(key)) {
vector<Unigram> rawGlobalUnigrams = m_languageModel.unigramsForKey(key); std::vector<Formosa::Gramambular::Unigram> rawGlobalUnigrams = m_languageModel.unigramsForKey(key);
allUnigrams = filterAndTransformUnigrams(rawGlobalUnigrams, excludedValues, insertedValues); allUnigrams = filterAndTransformUnigrams(rawGlobalUnigrams, excludedValues, insertedValues);
} }
@ -131,7 +131,7 @@ const vector<Unigram> McBopomofoLM::unigramsForKey(const string& key)
return allUnigrams; return allUnigrams;
} }
bool McBopomofoLM::hasUnigramsForKey(const string& key) bool McBopomofoLM::hasUnigramsForKey(const std::string& key)
{ {
if (key == " ") { if (key == " ") {
return true; return true;
@ -164,36 +164,36 @@ bool McBopomofoLM::externalConverterEnabled()
return m_externalConverterEnabled; return m_externalConverterEnabled;
} }
void McBopomofoLM::setExternalConverter(std::function<string(string)> externalConverter) void McBopomofoLM::setExternalConverter(std::function<std::string(std::string)> externalConverter)
{ {
m_externalConverter = externalConverter; m_externalConverter = externalConverter;
} }
const vector<Unigram> McBopomofoLM::filterAndTransformUnigrams(const vector<Unigram> unigrams, const unordered_set<string>& excludedValues, unordered_set<string>& insertedValues) const std::vector<Formosa::Gramambular::Unigram> McBopomofoLM::filterAndTransformUnigrams(const std::vector<Formosa::Gramambular::Unigram> unigrams, const std::unordered_set<std::string>& excludedValues, std::unordered_set<std::string>& insertedValues)
{ {
vector<Unigram> results; std::vector<Formosa::Gramambular::Unigram> results;
for (auto&& unigram : unigrams) { for (auto&& unigram : unigrams) {
// excludedValues filters out the unigrams with the original value. // excludedValues filters out the unigrams with the original value.
// insertedValues filters out the ones with the converted value // insertedValues filters out the ones with the converted value
string originalValue = unigram.keyValue.value; std::string originalValue = unigram.keyValue.value;
if (excludedValues.find(originalValue) != excludedValues.end()) { if (excludedValues.find(originalValue) != excludedValues.end()) {
continue; continue;
} }
string value = originalValue; std::string value = originalValue;
if (m_phraseReplacementEnabled) { if (m_phraseReplacementEnabled) {
string replacement = m_phraseReplacement.valueForKey(value); std::string replacement = m_phraseReplacement.valueForKey(value);
if (replacement != "") { if (replacement != "") {
value = replacement; value = replacement;
} }
} }
if (m_externalConverterEnabled && m_externalConverter) { if (m_externalConverterEnabled && m_externalConverter) {
string replacement = m_externalConverter(value); std::string replacement = m_externalConverter(value);
value = replacement; value = replacement;
} }
if (insertedValues.find(value) == insertedValues.end()) { if (insertedValues.find(value) == insertedValues.end()) {
Unigram g; Formosa::Gramambular::Unigram g;
g.keyValue.value = value; g.keyValue.value = value;
g.keyValue.key = unigram.keyValue.key; g.keyValue.key = unigram.keyValue.key;
g.score = unigram.score; g.score = unigram.score;
@ -204,12 +204,14 @@ const vector<Unigram> McBopomofoLM::filterAndTransformUnigrams(const vector<Unig
return results; return results;
} }
const vector<std::string> McBopomofoLM::associatedPhrasesForKey(const string& key) const std::vector<std::string> McBopomofoLM::associatedPhrasesForKey(const std::string& key)
{ {
return m_associatedPhrases.valuesForKey(key); return m_associatedPhrases.valuesForKey(key);
} }
bool McBopomofoLM::hasAssociatedPhrasesForKey(const string& key) bool McBopomofoLM::hasAssociatedPhrasesForKey(const std::string& key)
{ {
return m_associatedPhrases.hasValuesForKey(key); return m_associatedPhrases.hasValuesForKey(key);
} }
} // namespace McBopomofo

View File

@ -24,17 +24,15 @@
#ifndef MCBOPOMOFOLM_H #ifndef MCBOPOMOFOLM_H
#define MCBOPOMOFOLM_H #define MCBOPOMOFOLM_H
#include <stdio.h> #include "AssociatedPhrases.h"
#include "UserPhrasesLM.h"
#include "ParselessLM.h" #include "ParselessLM.h"
#include "PhraseReplacementMap.h" #include "PhraseReplacementMap.h"
#include "AssociatedPhrases.h" #include "UserPhrasesLM.h"
#include <stdio.h>
#include <unordered_set> #include <unordered_set>
namespace McBopomofo { namespace McBopomofo {
using namespace Formosa::Gramambular;
/// McBopomofoLM is a facade for managing a set of models including /// McBopomofoLM is a facade for managing a set of models including
/// the input method language model, user phrases and excluded phrases. /// the input method language model, user phrases and excluded phrases.
/// ///
@ -57,7 +55,7 @@ using namespace Formosa::Gramambular;
/// model while launching and to load the user phrases anytime if the custom /// model while launching and to load the user phrases anytime if the custom
/// files are modified. It does not keep the reference of the data pathes but /// files are modified. It does not keep the reference of the data pathes but
/// you have to pass the paths when you ask it to do loading. /// you have to pass the paths when you ask it to do loading.
class McBopomofoLM : public LanguageModel { class McBopomofoLM : public Formosa::Gramambular::LanguageModel {
public: public:
McBopomofoLM(); McBopomofoLM();
~McBopomofoLM(); ~McBopomofoLM();
@ -83,14 +81,14 @@ public:
void loadPhraseReplacementMap(const char* phraseReplacementPath); void loadPhraseReplacementMap(const char* phraseReplacementPath);
/// Not implemented since we do not have data to provide bigram function. /// Not implemented since we do not have data to provide bigram function.
const vector<Bigram> bigramsForKeys(const string& preceedingKey, const string& key); const std::vector<Formosa::Gramambular::Bigram> bigramsForKeys(const std::string& preceedingKey, const std::string& key);
/// Returns a list of available unigram for the given key. /// Returns a list of available unigram for the given key.
/// @param key A string represents the BPMF reading or a symbol key. For /// @param key A string represents the BPMF reading or a symbol key. For
/// example, it you pass "ㄇㄚ", it returns "嗎", "媽", and so on. /// example, it you pass "ㄇㄚ", it returns "嗎", "媽", and so on.
const vector<Unigram> unigramsForKey(const string& key); const std::vector<Formosa::Gramambular::Unigram> unigramsForKey(const std::string& key);
/// If the model has unigrams for the given key. /// If the model has unigrams for the given key.
/// @param key The key. /// @param key The key.
bool hasUnigramsForKey(const string& key); bool hasUnigramsForKey(const std::string& key);
/// Enables or disables phrase replacement. /// Enables or disables phrase replacement.
void setPhraseReplacementEnabled(bool enabled); void setPhraseReplacementEnabled(bool enabled);
@ -102,23 +100,22 @@ public:
/// If the external converted is enabled or not. /// If the external converted is enabled or not.
bool externalConverterEnabled(); bool externalConverterEnabled();
/// Sets a lambda to let the values of unigrams could be converted by it. /// Sets a lambda to let the values of unigrams could be converted by it.
void setExternalConverter(std::function<string(string)> externalConverter); void setExternalConverter(std::function<std::string(std::string)> externalConverter);
const vector<std::string> associatedPhrasesForKey(const string& key);
bool hasAssociatedPhrasesForKey(const string& key);
const std::vector<std::string> associatedPhrasesForKey(const std::string& key);
bool hasAssociatedPhrasesForKey(const std::string& key);
protected: protected:
/// Filters and converts the input unigrams and return a new list of unigrams. /// Filters and converts the input unigrams and return a new list of unigrams.
/// ///
/// @param unigrams The unigrams to be processed. /// @param unigrams The unigrams to be processed.
/// @param excludedValues The values to excluded unigrams. /// @param excludedValues The values to excluded unigrams.
/// @param insertedValues The values for unigrams already in the results. /// @param insertedValues The values for unigrams already in the results.
/// It helps to prevent duplicated unigrams. Please note that the method /// It helps to prevent duplicated unigrams. Please note that the method
/// has a side effect that it inserts values to `insertedValues`. /// has a side effect that it inserts values to `insertedValues`.
const vector<Unigram> filterAndTransformUnigrams(const vector<Unigram> unigrams, const std::vector<Formosa::Gramambular::Unigram> filterAndTransformUnigrams(const std::vector<Formosa::Gramambular::Unigram> unigrams,
const std::unordered_set<string>& excludedValues, const std::unordered_set<std::string>& excludedValues,
std::unordered_set<string>& insertedValues); std::unordered_set<std::string>& insertedValues);
ParselessLM m_languageModel; ParselessLM m_languageModel;
UserPhrasesLM m_userPhrases; UserPhrasesLM m_userPhrases;
@ -127,7 +124,7 @@ protected:
AssociatedPhrases m_associatedPhrases; AssociatedPhrases m_associatedPhrases;
bool m_phraseReplacementEnabled; bool m_phraseReplacementEnabled;
bool m_externalConverterEnabled; bool m_externalConverterEnabled;
std::function<string(string)> m_externalConverter; std::function<std::string(std::string)> m_externalConverter;
}; };
}; };

View File

@ -31,31 +31,33 @@
#include <cmath> #include <cmath>
#include <sstream> #include <sstream>
using namespace McBopomofo; namespace McBopomofo {
// About 20 generations. // About 20 generations.
static const double DecayThreshould = 1.0 / 1048576.0; static const double DecayThreshould = 1.0 / 1048576.0;
static double Score(size_t eventCount, static double Score(size_t eventCount,
size_t totalCount, size_t totalCount,
double eventTimestamp, double eventTimestamp,
double timestamp, double timestamp,
double lambda); double lambda);
static bool IsEndingPunctuation(const string& value); static bool IsEndingPunctuation(const std::string& value);
static string WalkedNodesToKey(const std::vector<NodeAnchor>& walkedNodes, static std::string WalkedNodesToKey(const std::vector<Formosa::Gramambular::NodeAnchor>& walkedNodes,
size_t cursorIndex); size_t cursorIndex);
UserOverrideModel::UserOverrideModel(size_t capacity, double decayConstant) UserOverrideModel::UserOverrideModel(size_t capacity, double decayConstant)
: m_capacity(capacity) { : m_capacity(capacity)
{
assert(m_capacity > 0); assert(m_capacity > 0);
m_decayExponent = log(0.5) / decayConstant; m_decayExponent = log(0.5) / decayConstant;
} }
void UserOverrideModel::observe(const std::vector<NodeAnchor>& walkedNodes, void UserOverrideModel::observe(const std::vector<Formosa::Gramambular::NodeAnchor>& walkedNodes,
size_t cursorIndex, size_t cursorIndex,
const string& candidate, const std::string& candidate,
double timestamp) { double timestamp)
string key = WalkedNodesToKey(walkedNodes, cursorIndex); {
std::string key = WalkedNodesToKey(walkedNodes, cursorIndex);
auto mapIter = m_lruMap.find(key); auto mapIter = m_lruMap.find(key);
if (mapIter == m_lruMap.end()) { if (mapIter == m_lruMap.end()) {
auto keyValuePair = KeyObservationPair(key, Observation()); auto keyValuePair = KeyObservationPair(key, Observation());
@ -65,7 +67,7 @@ void UserOverrideModel::observe(const std::vector<NodeAnchor>& walkedNodes,
m_lruList.push_front(keyValuePair); m_lruList.push_front(keyValuePair);
auto listIter = m_lruList.begin(); auto listIter = m_lruList.begin();
auto lruKeyValue = std::pair<std::string, auto lruKeyValue = std::pair<std::string,
std::list<KeyObservationPair>::iterator>(key, listIter); std::list<KeyObservationPair>::iterator>(key, listIter);
m_lruMap.insert(lruKeyValue); m_lruMap.insert(lruKeyValue);
if (m_lruList.size() > m_capacity) { if (m_lruList.size() > m_capacity) {
@ -84,30 +86,31 @@ void UserOverrideModel::observe(const std::vector<NodeAnchor>& walkedNodes,
} }
} }
string UserOverrideModel::suggest(const std::vector<NodeAnchor>& walkedNodes, std::string UserOverrideModel::suggest(const std::vector<Formosa::Gramambular::NodeAnchor>& walkedNodes,
size_t cursorIndex, size_t cursorIndex,
double timestamp) { double timestamp)
string key = WalkedNodesToKey(walkedNodes, cursorIndex); {
std::string key = WalkedNodesToKey(walkedNodes, cursorIndex);
auto mapIter = m_lruMap.find(key); auto mapIter = m_lruMap.find(key);
if (mapIter == m_lruMap.end()) { if (mapIter == m_lruMap.end()) {
return string(); return std::string();
} }
auto listIter = mapIter->second; auto listIter = mapIter->second;
auto& keyValuePair = *listIter; auto& keyValuePair = *listIter;
const Observation& observation = keyValuePair.second; const Observation& observation = keyValuePair.second;
string candidate; std::string candidate;
double score = 0.0; double score = 0.0;
for (auto i = observation.overrides.begin(); for (auto i = observation.overrides.begin();
i != observation.overrides.end(); i != observation.overrides.end();
++i) { ++i) {
const Override& o = i->second; const Override& o = i->second;
double overrideScore = Score(o.count, double overrideScore = Score(o.count,
observation.count, observation.count,
o.timestamp, o.timestamp,
timestamp, timestamp,
m_decayExponent); m_decayExponent);
if (overrideScore == 0.0) { if (overrideScore == 0.0) {
continue; continue;
} }
@ -120,8 +123,9 @@ string UserOverrideModel::suggest(const std::vector<NodeAnchor>& walkedNodes,
return candidate; return candidate;
} }
void UserOverrideModel::Observation::update(const string& candidate, void UserOverrideModel::Observation::update(const std::string& candidate,
double timestamp) { double timestamp)
{
count++; count++;
auto& o = overrides[candidate]; auto& o = overrides[candidate];
o.timestamp = timestamp; o.timestamp = timestamp;
@ -129,10 +133,11 @@ void UserOverrideModel::Observation::update(const string& candidate,
} }
static double Score(size_t eventCount, static double Score(size_t eventCount,
size_t totalCount, size_t totalCount,
double eventTimestamp, double eventTimestamp,
double timestamp, double timestamp,
double lambda) { double lambda)
{
double decay = exp((timestamp - eventTimestamp) * lambda); double decay = exp((timestamp - eventTimestamp) * lambda);
if (decay < DecayThreshould) { if (decay < DecayThreshould) {
return 0.0; return 0.0;
@ -142,16 +147,17 @@ static double Score(size_t eventCount,
return prob * decay; return prob * decay;
} }
static bool IsEndingPunctuation(const string& value) { static bool IsEndingPunctuation(const std::string& value)
return value == "" || value == "" || value== "" || value == "" || {
value == "" || value == "" || value== "" || value == ""; return value == "" || value == "" || value == "" || value == "" || value == "" || value == "" || value == "" || value == "";
} }
static string WalkedNodesToKey(const std::vector<NodeAnchor>& walkedNodes, static std::string WalkedNodesToKey(const std::vector<Formosa::Gramambular::NodeAnchor>& walkedNodes,
size_t cursorIndex) { size_t cursorIndex)
{
std::stringstream s; std::stringstream s;
std::vector<NodeAnchor> n; std::vector<Formosa::Gramambular::NodeAnchor> n;
size_t ll = 0; size_t ll = 0;
for (std::vector<NodeAnchor>::const_iterator i = walkedNodes.begin(); for (std::vector<Formosa::Gramambular::NodeAnchor>::const_iterator i = walkedNodes.begin();
i != walkedNodes.end(); i != walkedNodes.end();
++i) { ++i) {
const auto& nn = *i; const auto& nn = *i;
@ -162,54 +168,54 @@ static string WalkedNodesToKey(const std::vector<NodeAnchor>& walkedNodes,
} }
} }
std::vector<NodeAnchor>::const_reverse_iterator r = n.rbegin(); std::vector<Formosa::Gramambular::NodeAnchor>::const_reverse_iterator r = n.rbegin();
if (r == n.rend()) { if (r == n.rend()) {
return ""; return "";
} }
string current = (*r).node->currentKeyValue().key; std::string current = (*r).node->currentKeyValue().key;
++r; ++r;
s.clear(); s.clear();
s.str(std::string()); s.str(std::string());
if (r != n.rend()) { if (r != n.rend()) {
string value = (*r).node->currentKeyValue().value; std::string value = (*r).node->currentKeyValue().value;
if (IsEndingPunctuation(value)) { if (IsEndingPunctuation(value)) {
s << "()"; s << "()";
r = n.rend(); r = n.rend();
} else { } else {
s << "(" s << "("
<< (*r).node->currentKeyValue().key << (*r).node->currentKeyValue().key
<< "," << ","
<< value << value
<< ")"; << ")";
++r; ++r;
} }
} else { } else {
s << "()"; s << "()";
} }
string prev = s.str(); std::string prev = s.str();
s.clear(); s.clear();
s.str(std::string()); s.str(std::string());
if (r != n.rend()) { if (r != n.rend()) {
string value = (*r).node->currentKeyValue().value; std::string value = (*r).node->currentKeyValue().value;
if (IsEndingPunctuation(value)) { if (IsEndingPunctuation(value)) {
s << "()"; s << "()";
r = n.rend(); r = n.rend();
} else { } else {
s << "(" s << "("
<< (*r).node->currentKeyValue().key << (*r).node->currentKeyValue().key
<< "," << ","
<< value << value
<< ")"; << ")";
++r; ++r;
} }
} else { } else {
s << "()"; s << "()";
} }
string anterior = s.str(); std::string anterior = s.str();
s.clear(); s.clear();
s.str(std::string()); s.str(std::string());
@ -217,3 +223,5 @@ static string WalkedNodesToKey(const std::vector<NodeAnchor>& walkedNodes,
return s.str(); return s.str();
} }
} // namespace McBopomofo

View File

@ -32,35 +32,40 @@
namespace McBopomofo { namespace McBopomofo {
using namespace Formosa::Gramambular;
class UserOverrideModel { class UserOverrideModel {
public: public:
UserOverrideModel(size_t capacity, double decayConstant); UserOverrideModel(size_t capacity, double decayConstant);
void observe(const std::vector<NodeAnchor>& walkedNodes, void observe(const std::vector<Formosa::Gramambular::NodeAnchor>& walkedNodes,
size_t cursorIndex, size_t cursorIndex,
const string& candidate, const std::string& candidate,
double timestamp); double timestamp);
string suggest(const std::vector<NodeAnchor>& walkedNodes, std::string suggest(const std::vector<Formosa::Gramambular::NodeAnchor>& walkedNodes,
size_t cursorIndex, size_t cursorIndex,
double timestamp); double timestamp);
private: private:
struct Override { struct Override {
size_t count; size_t count;
double timestamp; double timestamp;
Override() : count(0), timestamp(0.0) {} Override()
: count(0)
, timestamp(0.0)
{
}
}; };
struct Observation { struct Observation {
size_t count; size_t count;
std::map<std::string, Override> overrides; std::map<std::string, Override> overrides;
Observation() : count(0) {} Observation()
void update(const string& candidate, double timestamp); : count(0)
{
}
void update(const std::string& candidate, double timestamp);
}; };
typedef std::pair<std::string, Observation> KeyObservationPair; typedef std::pair<std::string, Observation> KeyObservationPair;
@ -71,7 +76,6 @@ private:
std::map<std::string, std::list<KeyObservationPair>::iterator> m_lruMap; std::map<std::string, std::list<KeyObservationPair>::iterator> m_lruMap;
}; };
}; // namespace McBopomofo }; // namespace McBopomofo
#endif #endif

View File

@ -21,30 +21,25 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#import "Mandarin.h" #import "KeyHandler.h"
#import "Gramambular.h" #import "Gramambular.h"
#import "LanguageModelManager+Privates.h"
#import "Mandarin.h"
#import "McBopomofo-Swift.h"
#import "McBopomofoLM.h" #import "McBopomofoLM.h"
#import "UserOverrideModel.h" #import "UserOverrideModel.h"
#import "LanguageModelManager+Privates.h"
#import "KeyHandler.h"
#import "McBopomofo-Swift.h"
#import <string> #import <string>
@import CandidateUI; @import CandidateUI;
@import NSStringUtils; @import NSStringUtils;
// C++ namespace usages
using namespace std;
using namespace Formosa::Mandarin;
using namespace Formosa::Gramambular;
using namespace McBopomofo;
InputMode InputModeBopomofo = @"org.openvanilla.inputmethod.McBopomofo.Bopomofo"; InputMode InputModeBopomofo = @"org.openvanilla.inputmethod.McBopomofo.Bopomofo";
InputMode InputModePlainBopomofo = @"org.openvanilla.inputmethod.McBopomofo.PlainBopomofo"; InputMode InputModePlainBopomofo = @"org.openvanilla.inputmethod.McBopomofo.PlainBopomofo";
static const double kEpsilon = 0.000001; static const double kEpsilon = 0.000001;
static double FindHighestScore(const vector<NodeAnchor> &nodes, double epsilon) { static double FindHighestScore(const std::vector<Formosa::Gramambular::NodeAnchor> &nodes, double epsilon)
{
double highestScore = 0.0; double highestScore = 0.0;
for (auto ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) { for (auto ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) {
double score = ni->node->highestUnigramScore(); double score = ni->node->highestUnigramScore();
@ -56,10 +51,10 @@ static double FindHighestScore(const vector<NodeAnchor> &nodes, double epsilon)
} }
// sort helper // sort helper
class NodeAnchorDescendingSorter class NodeAnchorDescendingSorter {
{
public: public:
bool operator()(const NodeAnchor &a, const NodeAnchor &b) const { bool operator()(const Formosa::Gramambular::NodeAnchor &a, const Formosa::Gramambular::NodeAnchor &b) const
{
return a.node->key().length() > b.node->key().length(); return a.node->key().length() > b.node->key().length();
} }
}; };
@ -70,9 +65,7 @@ public:
static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot"; static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot";
#endif #endif
@implementation KeyHandler {
@implementation KeyHandler
{
// the reading buffer that takes user input // the reading buffer that takes user input
Formosa::Mandarin::BopomofoReadingBuffer *_bpmfReadingBuffer; Formosa::Mandarin::BopomofoReadingBuffer *_bpmfReadingBuffer;
@ -102,7 +95,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
- (void)setInputMode:(NSString *)value - (void)setInputMode:(NSString *)value
{ {
NSString *newInputMode; NSString *newInputMode;
McBopomofoLM *newLanguageModel; McBopomofo::McBopomofoLM *newLanguageModel;
if ([value isKindOfClass:[NSString class]] && [value isEqual:InputModePlainBopomofo]) { if ([value isKindOfClass:[NSString class]] && [value isEqual:InputModePlainBopomofo]) {
newInputMode = InputModePlainBopomofo; newInputMode = InputModePlainBopomofo;
@ -122,7 +115,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
if (_builder) { if (_builder) {
delete _builder; delete _builder;
_builder = new BlockReadingBuilder(_languageModel); _builder = new Formosa::Gramambular::BlockReadingBuilder(_languageModel);
_builder->setJoinSeparator("-"); _builder->setJoinSeparator("-");
} }
@ -148,14 +141,14 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
{ {
self = [super init]; self = [super init];
if (self) { if (self) {
_bpmfReadingBuffer = new BopomofoReadingBuffer(BopomofoKeyboardLayout::StandardLayout()); _bpmfReadingBuffer = new Formosa::Mandarin::BopomofoReadingBuffer(Formosa::Mandarin::BopomofoKeyboardLayout::StandardLayout());
// create the lattice builder // create the lattice builder
_languageModel = [LanguageModelManager languageModelMcBopomofo]; _languageModel = [LanguageModelManager languageModelMcBopomofo];
_languageModel->setPhraseReplacementEnabled(Preferences.phraseReplacementEnabled); _languageModel->setPhraseReplacementEnabled(Preferences.phraseReplacementEnabled);
_userOverrideModel = [LanguageModelManager userOverrideModel]; _userOverrideModel = [LanguageModelManager userOverrideModel];
_builder = new BlockReadingBuilder(_languageModel); _builder = new Formosa::Gramambular::BlockReadingBuilder(_languageModel);
// each Mandarin syllable is separated by a hyphen // each Mandarin syllable is separated by a hyphen
_builder->setJoinSeparator("-"); _builder->setJoinSeparator("-");
@ -168,27 +161,27 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
{ {
NSInteger layout = Preferences.keyboardLayout; NSInteger layout = Preferences.keyboardLayout;
switch (layout) { switch (layout) {
case KeyboardLayoutStandard: case KeyboardLayoutStandard:
_bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::StandardLayout()); _bpmfReadingBuffer->setKeyboardLayout(Formosa::Mandarin::BopomofoKeyboardLayout::StandardLayout());
break; break;
case KeyboardLayoutEten: case KeyboardLayoutEten:
_bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::ETenLayout()); _bpmfReadingBuffer->setKeyboardLayout(Formosa::Mandarin::BopomofoKeyboardLayout::ETenLayout());
break; break;
case KeyboardLayoutHsu: case KeyboardLayoutHsu:
_bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::HsuLayout()); _bpmfReadingBuffer->setKeyboardLayout(Formosa::Mandarin::BopomofoKeyboardLayout::HsuLayout());
break; break;
case KeyboardLayoutEten26: case KeyboardLayoutEten26:
_bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::ETen26Layout()); _bpmfReadingBuffer->setKeyboardLayout(Formosa::Mandarin::BopomofoKeyboardLayout::ETen26Layout());
break; break;
case KeyboardLayoutHanyuPinyin: case KeyboardLayoutHanyuPinyin:
_bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::HanyuPinyinLayout()); _bpmfReadingBuffer->setKeyboardLayout(Formosa::Mandarin::BopomofoKeyboardLayout::HanyuPinyinLayout());
break; break;
case KeyboardLayoutIBM: case KeyboardLayoutIBM:
_bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::IBMLayout()); _bpmfReadingBuffer->setKeyboardLayout(Formosa::Mandarin::BopomofoKeyboardLayout::IBMLayout());
break; break;
default: default:
_bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::StandardLayout()); _bpmfReadingBuffer->setKeyboardLayout(Formosa::Mandarin::BopomofoKeyboardLayout::StandardLayout());
Preferences.keyboardLayout = KeyboardLayoutStandard; Preferences.keyboardLayout = KeyboardLayoutStandard;
} }
_languageModel->setExternalConverterEnabled(Preferences.chineseConversionStyle == 1); _languageModel->setExternalConverterEnabled(Preferences.chineseConversionStyle == 1);
} }
@ -196,8 +189,8 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
- (void)fixNodeWithValue:(NSString *)value - (void)fixNodeWithValue:(NSString *)value
{ {
size_t cursorIndex = [self _actualCandidateCursorIndex]; size_t cursorIndex = [self _actualCandidateCursorIndex];
string stringValue = [value UTF8String]; std::string stringValue(value.UTF8String);
NodeAnchor selectedNode = _builder->grid().fixNodeSelectedCandidate(cursorIndex, stringValue); Formosa::Gramambular::NodeAnchor selectedNode = _builder->grid().fixNodeSelectedCandidate(cursorIndex, stringValue);
if (_inputMode != InputModePlainBopomofo) { if (_inputMode != InputModePlainBopomofo) {
// If the length of the readings and the characters do not match, // If the length of the readings and the characters do not match,
// it often means it is a special symbol and it should not be stored // it often means it is a special symbol and it should not be stored
@ -218,10 +211,9 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
} }
[self _walk]; [self _walk];
if (Preferences.selectPhraseAfterCursorAsCandidate && if (Preferences.selectPhraseAfterCursorAsCandidate && Preferences.moveCursorAfterSelectingCandidate) {
Preferences.moveCursorAfterSelectingCandidate) {
size_t nextPosition = 0; size_t nextPosition = 0;
for (auto node: _walkedNodes) { for (auto node : _walkedNodes) {
if (nextPosition >= cursorIndex) { if (nextPosition >= cursorIndex) {
break; break;
} }
@ -240,10 +232,10 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
_walkedNodes.clear(); _walkedNodes.clear();
} }
- (string)_currentLayout - (std::string)_currentLayout
{ {
NSString *keyboardLayoutName = Preferences.keyboardLayoutName; NSString *keyboardLayoutName = Preferences.keyboardLayoutName;
string layout = string(keyboardLayoutName.UTF8String) + string("_"); std::string layout = std::string(keyboardLayoutName.UTF8String) + "_";
return layout; return layout;
} }
@ -260,9 +252,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
// if the composing buffer is empty and there's no reading, and there is some function key combination, we ignore it // if the composing buffer is empty and there's no reading, and there is some function key combination, we ignore it
BOOL isFunctionKey = ([input isCommandHold] || [input isOptionHold] || [input isNumericPad]) || [input isControlHotKey]; BOOL isFunctionKey = ([input isCommandHold] || [input isOptionHold] || [input isNumericPad]) || [input isControlHotKey];
if (![state isKindOfClass:[InputStateNotEmpty class]] && if (![state isKindOfClass:[InputStateNotEmpty class]] && ![state isKindOfClass:[InputStateAssociatedPhrases class]] && isFunctionKey) {
![state isKindOfClass:[InputStateAssociatedPhrases class]] &&
isFunctionKey) {
return NO; return NO;
} }
@ -321,8 +311,8 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
// MARK: Handle Marking // MARK: Handle Marking
if ([state isKindOfClass:[InputStateMarking class]]) { if ([state isKindOfClass:[InputStateMarking class]]) {
InputStateMarking *marking = (InputStateMarking *) state; InputStateMarking *marking = (InputStateMarking *)state;
if ([self _handleMarkingState:(InputStateMarking *) state input:input stateCallback:stateCallback errorCallback:errorCallback]) { if ([self _handleMarkingState:(InputStateMarking *)state input:input stateCallback:stateCallback errorCallback:errorCallback]) {
return YES; return YES;
} }
state = [marking convertToInputting]; state = [marking convertToInputting];
@ -335,8 +325,8 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
// MARK: Handle BPMF Keys // MARK: Handle BPMF Keys
// see if it's valid BPMF reading // see if it's valid BPMF reading
if (!skipBpmfHandling && _bpmfReadingBuffer->isValidKey((char) charCode)) { if (!skipBpmfHandling && _bpmfReadingBuffer->isValidKey((char)charCode)) {
_bpmfReadingBuffer->combineKey((char) charCode); _bpmfReadingBuffer->combineKey((char)charCode);
// if we have a tone marker, we have to insert the reading to the // if we have a tone marker, we have to insert the reading to the
// builder in other words, if we don't have a tone marker, we just // builder in other words, if we don't have a tone marker, we just
@ -354,7 +344,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
composeReading |= (!_bpmfReadingBuffer->isEmpty() && (charCode == 32 || charCode == 13)); composeReading |= (!_bpmfReadingBuffer->isEmpty() && (charCode == 32 || charCode == 13));
if (composeReading) { if (composeReading) {
// combine the reading // combine the reading
string reading = _bpmfReadingBuffer->syllable().composedString(); std::string reading = _bpmfReadingBuffer->syllable().composedString();
// see if we have a unigram for this // see if we have a unigram for this
if (!_languageModel->hasUnigramsForKey(reading)) { if (!_languageModel->hasUnigramsForKey(reading)) {
@ -371,12 +361,11 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
NSString *poppedText = [self _popOverflowComposingTextAndWalk]; NSString *poppedText = [self _popOverflowComposingTextAndWalk];
// get user override model suggestion // get user override model suggestion
string overrideValue = (_inputMode == InputModePlainBopomofo) ? "" : std::string overrideValue = (_inputMode == InputModePlainBopomofo) ? "" : _userOverrideModel->suggest(_walkedNodes, _builder->cursorIndex(), [[NSDate date] timeIntervalSince1970]);
_userOverrideModel->suggest(_walkedNodes, _builder->cursorIndex(), [[NSDate date] timeIntervalSince1970]);
if (!overrideValue.empty()) { if (!overrideValue.empty()) {
size_t cursorIndex = [self _actualCandidateCursorIndex]; size_t cursorIndex = [self _actualCandidateCursorIndex];
vector<NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex); std::vector<Formosa::Gramambular::NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex);
double highestScore = FindHighestScore(nodes, kEpsilon); double highestScore = FindHighestScore(nodes, kEpsilon);
_builder->grid().overrideNodeScoreForSelectedCandidate(cursorIndex, overrideValue, static_cast<float>(highestScore)); _builder->grid().overrideNodeScoreForSelectedCandidate(cursorIndex, overrideValue, static_cast<float>(highestScore));
} }
@ -420,16 +409,15 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
// MARK: Space and Down // MARK: Space and Down
// keyCode 125 = Down, charCode 32 = Space // keyCode 125 = Down, charCode 32 = Space
if (_bpmfReadingBuffer->isEmpty() && if (_bpmfReadingBuffer->isEmpty() &&
[state isKindOfClass:[InputStateNotEmpty class]] && [state isKindOfClass:[InputStateNotEmpty class]] && ([input isExtraChooseCandidateKey] || charCode == 32 || (input.useVerticalMode && ([input isVerticalModeOnlyChooseCandidateKey])))) {
([input isExtraChooseCandidateKey] || charCode == 32 || (input.useVerticalMode && ([input isVerticalModeOnlyChooseCandidateKey])))) {
if (charCode == 32) { if (charCode == 32) {
// if the spacebar is NOT set to be a selection key // if the spacebar is NOT set to be a selection key
if ([input isShiftHold] || !Preferences.chooseCandidateUsingSpace) { if ([input isShiftHold] || !Preferences.chooseCandidateUsingSpace) {
if (_builder->cursorIndex() >= _builder->length()) { if (_builder->cursorIndex() >= _builder->length()) {
NSString *composingBuffer = [(InputStateNotEmpty*) state composingBuffer]; NSString *composingBuffer = [(InputStateNotEmpty *)state composingBuffer];
if (composingBuffer.length) { if (composingBuffer.length) {
InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:composingBuffer]; InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:composingBuffer];
stateCallback (committing); stateCallback(committing);
} }
[self clear]; [self clear];
InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:@" "]; InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:@" "];
@ -444,10 +432,9 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
stateCallback(inputting); stateCallback(inputting);
} }
return YES; return YES;
} }
} }
InputStateChoosingCandidate *choosingCandidates = [self _buildCandidateState:(InputStateNotEmpty *) state useVerticalMode:input.useVerticalMode]; InputStateChoosingCandidate *choosingCandidates = [self _buildCandidateState:(InputStateNotEmpty *)state useVerticalMode:input.useVerticalMode];
stateCallback(choosingCandidates); stateCallback(choosingCandidates);
return YES; return YES;
} }
@ -501,10 +488,10 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
} }
// MARK: Punctuation list // MARK: Punctuation list
if ((char) charCode == '`') { if ((char)charCode == '`') {
if (_languageModel->hasUnigramsForKey(string("_punctuation_list"))) { if (_languageModel->hasUnigramsForKey("_punctuation_list")) {
if (_bpmfReadingBuffer->isEmpty()) { if (_bpmfReadingBuffer->isEmpty()) {
_builder->insertReadingAtCursor(string("_punctuation_list")); _builder->insertReadingAtCursor("_punctuation_list");
NSString *poppedText = [self _popOverflowComposingTextAndWalk]; NSString *poppedText = [self _popOverflowComposingTextAndWalk];
InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState];
inputting.poppedText = poppedText; inputting.poppedText = poppedText;
@ -521,28 +508,28 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
// MARK: Punctuation // MARK: Punctuation
// if nothing is matched, see if it's a punctuation key for current layout. // if nothing is matched, see if it's a punctuation key for current layout.
string punctuationNamePrefix; std::string punctuationNamePrefix;
if ([input isControlHold]) { if ([input isControlHold]) {
punctuationNamePrefix = string("_ctrl_punctuation_"); punctuationNamePrefix = "_ctrl_punctuation_";
} else if (Preferences.halfWidthPunctuationEnabled) { } else if (Preferences.halfWidthPunctuationEnabled) {
punctuationNamePrefix = string("_half_punctuation_"); punctuationNamePrefix = "_half_punctuation_";
} else { } else {
punctuationNamePrefix = string("_punctuation_"); punctuationNamePrefix = "_punctuation_";
} }
string layout = [self _currentLayout]; std::string layout = [self _currentLayout];
string customPunctuation = punctuationNamePrefix + layout + string(1, (char) charCode); std::string customPunctuation = punctuationNamePrefix + layout + std::string(1, (char)charCode);
if ([self _handlePunctuation:customPunctuation state:state usingVerticalMode:input.useVerticalMode stateCallback:stateCallback errorCallback:errorCallback]) { if ([self _handlePunctuation:customPunctuation state:state usingVerticalMode:input.useVerticalMode stateCallback:stateCallback errorCallback:errorCallback]) {
return YES; return YES;
} }
// if nothing is matched, see if it's a punctuation key. // if nothing is matched, see if it's a punctuation key.
string punctuation = punctuationNamePrefix + string(1, (char) charCode); std::string punctuation = punctuationNamePrefix + std::string(1, (char)charCode);
if ([self _handlePunctuation:punctuation state:state usingVerticalMode:input.useVerticalMode stateCallback:stateCallback errorCallback:errorCallback]) { if ([self _handlePunctuation:punctuation state:state usingVerticalMode:input.useVerticalMode stateCallback:stateCallback errorCallback:errorCallback]) {
return YES; return YES;
} }
if ([state isKindOfClass:[InputStateNotEmpty class]] && (char) charCode >= 'A' && (char) charCode <= 'Z') { if ([state isKindOfClass:[InputStateNotEmpty class]] && (char)charCode >= 'A' && (char)charCode <= 'Z') {
string letter = string("_letter_") + string(1, (char) charCode); std::string letter = std::string("_letter_") + std::string(1, (char)charCode);
if ([self _handlePunctuation:letter state:state usingVerticalMode:input.useVerticalMode stateCallback:stateCallback errorCallback:errorCallback]) { if ([self _handlePunctuation:letter state:state usingVerticalMode:input.useVerticalMode stateCallback:stateCallback errorCallback:errorCallback]) {
return YES; return YES;
} }
@ -607,7 +594,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
return YES; return YES;
} }
InputStateInputting *currentState = (InputStateInputting *) state; InputStateInputting *currentState = (InputStateInputting *)state;
if ([input isShiftHold]) { if ([input isShiftHold]) {
// Shift + left // Shift + left
@ -645,7 +632,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
return YES; return YES;
} }
InputStateInputting *currentState = (InputStateInputting *) state; InputStateInputting *currentState = (InputStateInputting *)state;
if ([input isShiftHold]) { if ([input isShiftHold]) {
// Shift + Right // Shift + Right
@ -809,7 +796,6 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
return YES; return YES;
} }
- (BOOL)_handleEnterWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback - (BOOL)_handleEnterWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback
{ {
if (![state isKindOfClass:[InputStateInputting class]]) { if (![state isKindOfClass:[InputStateInputting class]]) {
@ -818,7 +804,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
[self clear]; [self clear];
InputStateInputting *current = (InputStateInputting *) state; InputStateInputting *current = (InputStateInputting *)state;
NSString *composingBuffer = current.composingBuffer; NSString *composingBuffer = current.composingBuffer;
InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:composingBuffer]; InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:composingBuffer];
stateCallback(committing); stateCallback(committing);
@ -827,7 +813,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
return YES; return YES;
} }
- (BOOL)_handlePunctuation:(string)customPunctuation state:(InputState *)state usingVerticalMode:(BOOL)useVerticalMode stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback - (BOOL)_handlePunctuation:(std::string)customPunctuation state:(InputState *)state usingVerticalMode:(BOOL)useVerticalMode stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback
{ {
if (!_languageModel->hasUnigramsForKey(customPunctuation)) { if (!_languageModel->hasUnigramsForKey(customPunctuation)) {
return NO; return NO;
@ -863,7 +849,6 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
return YES; return YES;
} }
- (BOOL)_handleMarkingState:(InputStateMarking *)state - (BOOL)_handleMarkingState:(InputStateMarking *)state
input:(KeyHandlerInput *)input input:(KeyHandlerInput *)input
stateCallback:(void (^)(InputState *))stateCallback stateCallback:(void (^)(InputState *))stateCallback
@ -890,7 +875,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
// Shift + left // Shift + left
if (([input isCursorBackward] || input.emacsKey == McBopomofoEmacsKeyBackward) if (([input isCursorBackward] || input.emacsKey == McBopomofoEmacsKeyBackward)
&& ([input isShiftHold])) { && ([input isShiftHold])) {
NSUInteger index = state.markerIndex; NSUInteger index = state.markerIndex;
if (index > 0) { if (index > 0) {
index = [state.composingBuffer previousUtf16PositionFor:index]; index = [state.composingBuffer previousUtf16PositionFor:index];
@ -912,7 +897,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
// Shift + Right // Shift + Right
if (([input isCursorForward] || input.emacsKey == McBopomofoEmacsKeyForward) if (([input isCursorForward] || input.emacsKey == McBopomofoEmacsKeyForward)
&& ([input isShiftHold])) { && ([input isShiftHold])) {
NSUInteger index = state.markerIndex; NSUInteger index = state.markerIndex;
if (index < state.composingBuffer.length) { if (index < state.composingBuffer.length) {
index = [state.composingBuffer nextUtf16PositionFor:index]; index = [state.composingBuffer nextUtf16PositionFor:index];
@ -933,7 +918,6 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
return NO; return NO;
} }
- (BOOL)_handleCandidateState:(InputState *)state - (BOOL)_handleCandidateState:(InputState *)state
input:(KeyHandlerInput *)input input:(KeyHandlerInput *)input
stateCallback:(void (^)(InputState *))stateCallback stateCallback:(void (^)(InputState *))stateCallback
@ -946,12 +930,11 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
BOOL cancelCandidateKey = (charCode == 27) || (charCode == 8) || [input isDelete]; BOOL cancelCandidateKey = (charCode == 27) || (charCode == 8) || [input isDelete];
if (cancelCandidateKey) { if (cancelCandidateKey) {
if ([state isKindOfClass: [InputStateAssociatedPhrases class]]) { if ([state isKindOfClass:[InputStateAssociatedPhrases class]]) {
[self clear]; [self clear];
InputStateEmptyIgnoringPreviousState *empty = [[InputStateEmptyIgnoringPreviousState alloc] init]; InputStateEmptyIgnoringPreviousState *empty = [[InputStateEmptyIgnoringPreviousState alloc] init];
stateCallback(empty); stateCallback(empty);
} } else if (_inputMode == InputModePlainBopomofo) {
else if (_inputMode == InputModePlainBopomofo) {
[self clear]; [self clear];
InputStateEmptyIgnoringPreviousState *empty = [[InputStateEmptyIgnoringPreviousState alloc] init]; InputStateEmptyIgnoringPreviousState *empty = [[InputStateEmptyIgnoringPreviousState alloc] init];
stateCallback(empty); stateCallback(empty);
@ -963,7 +946,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
} }
if (charCode == 13 || [input isEnter]) { if (charCode == 13 || [input isEnter]) {
if ([state isKindOfClass: [InputStateAssociatedPhrases class]]) { if ([state isKindOfClass:[InputStateAssociatedPhrases class]]) {
[self clear]; [self clear];
InputStateEmptyIgnoringPreviousState *empty = [[InputStateEmptyIgnoringPreviousState alloc] init]; InputStateEmptyIgnoringPreviousState *empty = [[InputStateEmptyIgnoringPreviousState alloc] init];
stateCallback(empty); stateCallback(empty);
@ -1077,9 +1060,9 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
NSArray *candidates; NSArray *candidates;
if ([state isKindOfClass: [InputStateChoosingCandidate class]]) { if ([state isKindOfClass:[InputStateChoosingCandidate class]]) {
candidates = [(InputStateChoosingCandidate *)state candidates]; candidates = [(InputStateChoosingCandidate *)state candidates];
} else if ([state isKindOfClass: [InputStateAssociatedPhrases class]]) { } else if ([state isKindOfClass:[InputStateAssociatedPhrases class]]) {
candidates = [(InputStateAssociatedPhrases *)state candidates]; candidates = [(InputStateAssociatedPhrases *)state candidates];
} }
@ -1131,23 +1114,22 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
} }
if (_inputMode == InputModePlainBopomofo) { if (_inputMode == InputModePlainBopomofo) {
string layout = [self _currentLayout]; std::string layout = [self _currentLayout];
string punctuationNamePrefix; std::string punctuationNamePrefix;
if ([input isControlHold]) { if ([input isControlHold]) {
punctuationNamePrefix = string("_ctrl_punctuation_"); punctuationNamePrefix = "_ctrl_punctuation_";
} else if (Preferences.halfWidthPunctuationEnabled) { } else if (Preferences.halfWidthPunctuationEnabled) {
punctuationNamePrefix = string("_half_punctuation_"); punctuationNamePrefix = "_half_punctuation_";
} else { } else {
punctuationNamePrefix = string("_punctuation_"); punctuationNamePrefix = "_punctuation_";
} }
string customPunctuation = punctuationNamePrefix + layout + string(1, (char) charCode); std::string customPunctuation = punctuationNamePrefix + layout + std::string(1, (char)charCode);
string punctuation = punctuationNamePrefix + string(1, (char) charCode); std::string punctuation = punctuationNamePrefix + std::string(1, (char)charCode);
BOOL shouldAutoSelectCandidate = _bpmfReadingBuffer->isValidKey((char) charCode) || _languageModel->hasUnigramsForKey(customPunctuation) || BOOL shouldAutoSelectCandidate = _bpmfReadingBuffer->isValidKey((char)charCode) || _languageModel->hasUnigramsForKey(customPunctuation) || _languageModel->hasUnigramsForKey(punctuation);
_languageModel->hasUnigramsForKey(punctuation);
if (!shouldAutoSelectCandidate && (char) charCode >= 'A' && (char) charCode <= 'Z') { if (!shouldAutoSelectCandidate && (char)charCode >= 'A' && (char)charCode <= 'Z') {
string letter = string("_letter_") + string(1, (char) charCode); std::string letter = std::string("_letter_") + std::string(1, (char)charCode);
if (_languageModel->hasUnigramsForKey(letter)) { if (_languageModel->hasUnigramsForKey(letter)) {
shouldAutoSelectCandidate = YES; shouldAutoSelectCandidate = YES;
} }
@ -1187,9 +1169,9 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
// we must do some Unicode codepoint counting to find the actual cursor location for the client // we must do some Unicode codepoint counting to find the actual cursor location for the client
// i.e. we need to take UTF-16 into consideration, for which a surrogate pair takes 2 UniChars // i.e. we need to take UTF-16 into consideration, for which a surrogate pair takes 2 UniChars
// locations // locations
for (vector<NodeAnchor>::iterator wi = _walkedNodes.begin(), we = _walkedNodes.end(); wi != we; ++wi) { for (std::vector<Formosa::Gramambular::NodeAnchor>::iterator wi = _walkedNodes.begin(), we = _walkedNodes.end(); wi != we; ++wi) {
if ((*wi).node) { if ((*wi).node) {
string nodeStr = (*wi).node->currentKeyValue().value; std::string nodeStr = (*wi).node->currentKeyValue().value;
NSString *valueString = [NSString stringWithUTF8String:nodeStr.c_str()]; NSString *valueString = [NSString stringWithUTF8String:nodeStr.c_str()];
[composingBuffer appendString:valueString]; [composingBuffer appendString:valueString];
@ -1221,14 +1203,14 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
} }
if (builderCursorIndex == 0) { if (builderCursorIndex == 0) {
tooltip = [NSString stringWithFormat:NSLocalizedString(@"Cursor is before \"%@\".", @""), tooltip = [NSString stringWithFormat:NSLocalizedString(@"Cursor is before \"%@\".", @""),
[NSString stringWithUTF8String:_builder->readings()[builderCursorIndex].c_str()]]; [NSString stringWithUTF8String:_builder->readings()[builderCursorIndex].c_str()]];
} else if (builderCursorIndex >= _builder->readings().size()) { } else if (builderCursorIndex >= _builder->readings().size()) {
tooltip = [NSString stringWithFormat:NSLocalizedString(@"Cursor is after \"%@\".", @""), tooltip = [NSString stringWithFormat:NSLocalizedString(@"Cursor is after \"%@\".", @""),
[NSString stringWithUTF8String:_builder->readings()[_builder->readings().size() - 1].c_str()]]; [NSString stringWithUTF8String:_builder->readings()[_builder->readings().size() - 1].c_str()]];
} else { } else {
tooltip = [NSString stringWithFormat:NSLocalizedString(@"Cursor is between \"%@\" and \"%@\".", @""), tooltip = [NSString stringWithFormat:NSLocalizedString(@"Cursor is between \"%@\" and \"%@\".", @""),
[NSString stringWithUTF8String:_builder->readings()[builderCursorIndex - 1].c_str()], [NSString stringWithUTF8String:_builder->readings()[builderCursorIndex - 1].c_str()],
[NSString stringWithUTF8String:_builder->readings()[builderCursorIndex].c_str()]]; [NSString stringWithUTF8String:_builder->readings()[builderCursorIndex].c_str()]];
} }
} }
} }
@ -1255,7 +1237,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
// retrieve the most likely trellis, i.e. a Maximum Likelihood Estimation // retrieve the most likely trellis, i.e. a Maximum Likelihood Estimation
// of the best possible Mandarain characters given the input syllables, // of the best possible Mandarain characters given the input syllables,
// using the Viterbi algorithm implemented in the Gramambular library // using the Viterbi algorithm implemented in the Gramambular library
Walker walker(&_builder->grid()); Formosa::Gramambular::Walker walker(&_builder->grid());
// the reverse walk traces the trellis from the end // the reverse walk traces the trellis from the end
_walkedNodes = walker.reverseWalk(_builder->grid().width()); _walkedNodes = walker.reverseWalk(_builder->grid().width());
@ -1265,7 +1247,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
// if DEBUG is defined, a GraphViz file is written to kGraphVizOutputfile // if DEBUG is defined, a GraphViz file is written to kGraphVizOutputfile
#if DEBUG #if DEBUG
string dotDump = _builder->grid().dumpDOT(); std::string dotDump = _builder->grid().dumpDOT();
NSString *dotStr = [NSString stringWithUTF8String:dotDump.c_str()]; NSString *dotStr = [NSString stringWithUTF8String:dotDump.c_str()];
NSError *error = nil; NSError *error = nil;
@ -1286,9 +1268,9 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
NSString *poppedText = @""; NSString *poppedText = @"";
NSInteger composingBufferSize = Preferences.composingBufferSize; NSInteger composingBufferSize = Preferences.composingBufferSize;
if (_builder->grid().width() > (size_t) composingBufferSize) { if (_builder->grid().width() > (size_t)composingBufferSize) {
if (_walkedNodes.size() > 0) { if (_walkedNodes.size() > 0) {
NodeAnchor &anchor = _walkedNodes[0]; Formosa::Gramambular::NodeAnchor &anchor = _walkedNodes[0];
poppedText = [NSString stringWithUTF8String:anchor.node->currentKeyValue().value.c_str()]; poppedText = [NSString stringWithUTF8String:anchor.node->currentKeyValue().value.c_str()];
_builder->removeHeadReadings(anchor.spanningLength); _builder->removeHeadReadings(anchor.spanningLength);
} }
@ -1303,15 +1285,15 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
NSMutableArray *candidatesArray = [[NSMutableArray alloc] init]; NSMutableArray *candidatesArray = [[NSMutableArray alloc] init];
size_t cursorIndex = [self _actualCandidateCursorIndex]; size_t cursorIndex = [self _actualCandidateCursorIndex];
vector<NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex); std::vector<Formosa::Gramambular::NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex);
// sort the nodes, so that longer nodes (representing longer phrases) are placed at the top of the candidate list // sort the nodes, so that longer nodes (representing longer phrases) are placed at the top of the candidate list
stable_sort(nodes.begin(), nodes.end(), NodeAnchorDescendingSorter()); stable_sort(nodes.begin(), nodes.end(), NodeAnchorDescendingSorter());
// then use the C++ trick to retrieve the candidates for each node at/crossing the cursor // then use the C++ trick to retrieve the candidates for each node at/crossing the cursor
for (vector<NodeAnchor>::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) { for (std::vector<Formosa::Gramambular::NodeAnchor>::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) {
const vector<KeyValuePair> &candidates = (*ni).node->candidates(); const std::vector<Formosa::Gramambular::KeyValuePair> &candidates = (*ni).node->candidates();
for (vector<KeyValuePair>::const_iterator ci = candidates.begin(), ce = candidates.end(); ci != ce; ++ci) { for (std::vector<Formosa::Gramambular::KeyValuePair>::const_iterator ci = candidates.begin(), ce = candidates.end(); ci != ce; ++ci) {
[candidatesArray addObject:[NSString stringWithUTF8String:(*ci).value.c_str()]]; [candidatesArray addObject:[NSString stringWithUTF8String:(*ci).value.c_str()]];
} }
} }
@ -1340,8 +1322,8 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
- (NSArray *)_currentReadings - (NSArray *)_currentReadings
{ {
NSMutableArray *readingsArray = [[NSMutableArray alloc] init]; NSMutableArray *readingsArray = [[NSMutableArray alloc] init];
vector<std::string> v = _builder->readings(); std::vector<std::string> v = _builder->readings();
for (vector<std::string>::iterator it_i = v.begin(); it_i != v.end(); ++it_i) { for (std::vector<std::string>::iterator it_i = v.begin(); it_i != v.end(); ++it_i) {
[readingsArray addObject:[NSString stringWithUTF8String:it_i->c_str()]]; [readingsArray addObject:[NSString stringWithUTF8String:it_i->c_str()]];
} }
return readingsArray; return readingsArray;
@ -1349,11 +1331,11 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
- (nullable InputState *)buildAssociatePhraseStateWithKey:(NSString *)key useVerticalMode:(BOOL)useVerticalMode - (nullable InputState *)buildAssociatePhraseStateWithKey:(NSString *)key useVerticalMode:(BOOL)useVerticalMode
{ {
string cppKey = string(key.UTF8String); std::string cppKey(key.UTF8String);
if (_languageModel->hasAssociatedPhrasesForKey(cppKey)) { if (_languageModel->hasAssociatedPhrasesForKey(cppKey)) {
vector<string> phrases = _languageModel->associatedPhrasesForKey(cppKey); std::vector<std::string> phrases = _languageModel->associatedPhrasesForKey(cppKey);
NSMutableArray <NSString *> *array = [NSMutableArray array]; NSMutableArray<NSString *> *array = [NSMutableArray array];
for (auto phrase: phrases) { for (auto phrase : phrases) {
NSString *item = [[NSString alloc] initWithUTF8String:phrase.c_str()]; NSString *item = [[NSString alloc] initWithUTF8String:phrase.c_str()];
[array addObject:item]; [array addObject:item];
} }

View File

@ -28,15 +28,12 @@
@import VXHanConvert; @import VXHanConvert;
@import OpenCCBridge; @import OpenCCBridge;
using namespace std;
using namespace McBopomofo;
static const int kUserOverrideModelCapacity = 500; static const int kUserOverrideModelCapacity = 500;
static const double kObservedOverrideHalflife = 5400.0; // 1.5 hr. static const double kObservedOverrideHalflife = 5400.0; // 1.5 hr.
static McBopomofoLM gLanguageModelMcBopomofo; static McBopomofo::McBopomofoLM gLanguageModelMcBopomofo;
static McBopomofoLM gLanguageModelPlainBopomofo; static McBopomofo::McBopomofoLM gLanguageModelPlainBopomofo;
static UserOverrideModel gUserOverrideModel(kUserOverrideModelCapacity, kObservedOverrideHalflife); static McBopomofo::UserOverrideModel gUserOverrideModel(kUserOverrideModelCapacity, kObservedOverrideHalflife);
static NSString *const kUserDataTemplateName = @"template-data"; static NSString *const kUserDataTemplateName = @"template-data";
static NSString *const kExcludedPhrasesMcBopomofoTemplateName = @"template-exclude-phrases"; static NSString *const kExcludedPhrasesMcBopomofoTemplateName = @"template-exclude-phrases";
@ -46,14 +43,14 @@ static NSString *const kTemplateExtension = @".txt";
@implementation LanguageModelManager @implementation LanguageModelManager
static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, McBopomofoLM &lm) static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, McBopomofo::McBopomofoLM &lm)
{ {
Class cls = NSClassFromString(@"McBopomofoInputMethodController"); Class cls = NSClassFromString(@"McBopomofoInputMethodController");
NSString *dataPath = [[NSBundle bundleForClass:cls] pathForResource:filenameWithoutExtension ofType:@"txt"]; NSString *dataPath = [[NSBundle bundleForClass:cls] pathForResource:filenameWithoutExtension ofType:@"txt"];
lm.loadLanguageModel([dataPath UTF8String]); lm.loadLanguageModel([dataPath UTF8String]);
} }
static void LTLoadAssociatedPhrases(McBopomofoLM &lm) static void LTLoadAssociatedPhrases(McBopomofo::McBopomofoLM &lm)
{ {
Class cls = NSClassFromString(@"McBopomofoInputMethodController"); Class cls = NSClassFromString(@"McBopomofoInputMethodController");
NSString *dataPath = [[NSBundle bundleForClass:cls] pathForResource:@"associated-phrases" ofType:@"txt"]; NSString *dataPath = [[NSBundle bundleForClass:cls] pathForResource:@"associated-phrases" ofType:@"txt"];
@ -104,7 +101,7 @@ static void LTLoadAssociatedPhrases(McBopomofoLM &lm)
+ (void)setupDataModelValueConverter + (void)setupDataModelValueConverter
{ {
auto converter = [] (string input) { auto converter = [](std::string input) {
if (!Preferences.chineseConversionEnabled) { if (!Preferences.chineseConversionEnabled) {
return input; return input;
} }
@ -116,11 +113,10 @@ static void LTLoadAssociatedPhrases(McBopomofoLM &lm)
NSString *text = [NSString stringWithUTF8String:input.c_str()]; NSString *text = [NSString stringWithUTF8String:input.c_str()];
if (Preferences.chineseConversionEngine == 1) { if (Preferences.chineseConversionEngine == 1) {
text = [VXHanConvert convertToSimplifiedFrom:text]; text = [VXHanConvert convertToSimplifiedFrom:text];
} } else {
else {
text = [OpenCCBridge convertToSimplified:text]; text = [OpenCCBridge convertToSimplified:text];
} }
return string(text.UTF8String); return std::string(text.UTF8String);
}; };
gLanguageModelMcBopomofo.setExternalConverter(converter); gLanguageModelMcBopomofo.setExternalConverter(converter);
@ -195,10 +191,10 @@ static void LTLoadAssociatedPhrases(McBopomofoLM &lm)
+ (BOOL)checkIfUserPhraseExist:(NSString *)userPhrase key:(NSString *)key NS_SWIFT_NAME(checkIfExist(userPhrase:key:)) + (BOOL)checkIfUserPhraseExist:(NSString *)userPhrase key:(NSString *)key NS_SWIFT_NAME(checkIfExist(userPhrase:key:))
{ {
string unigramKey = string(key.UTF8String); std::string unigramKey(key.UTF8String);
vector<Unigram> unigrams = gLanguageModelMcBopomofo.unigramsForKey(unigramKey); std::vector<Formosa::Gramambular::Unigram> unigrams = gLanguageModelMcBopomofo.unigramsForKey(unigramKey);
string userPhraseString = string(userPhrase.UTF8String); std::string userPhraseString(userPhrase.UTF8String);
for (auto unigram: unigrams) { for (auto unigram : unigrams) {
if (unigram.keyValue.value == userPhraseString) { if (unigram.keyValue.value == userPhraseString) {
return YES; return YES;
} }
@ -249,9 +245,9 @@ static void LTLoadAssociatedPhrases(McBopomofoLM &lm)
[writeFile writeData:data]; [writeFile writeData:data];
[writeFile closeFile]; [writeFile closeFile];
// We use FSEventStream to monitor the change of the user phrase folder, // We use FSEventStream to monitor the change of the user phrase folder,
// so we don't have to load data here. // so we don't have to load data here.
// [self loadUserPhrases]; // [self loadUserPhrases];
return YES; return YES;
} }
@ -283,12 +279,12 @@ static void LTLoadAssociatedPhrases(McBopomofoLM &lm)
return [[self dataFolderPath] stringByAppendingPathComponent:@"phrases-replacement.txt"]; return [[self dataFolderPath] stringByAppendingPathComponent:@"phrases-replacement.txt"];
} }
+ (McBopomofoLM *)languageModelMcBopomofo + (McBopomofo::McBopomofoLM *)languageModelMcBopomofo
{ {
return &gLanguageModelMcBopomofo; return &gLanguageModelMcBopomofo;
} }
+ (McBopomofoLM *)languageModelPlainBopomofo + (McBopomofo::McBopomofoLM *)languageModelPlainBopomofo
{ {
return &gLanguageModelPlainBopomofo; return &gLanguageModelPlainBopomofo;
} }

View File

@ -1,134 +0,0 @@
//
// tistool.m
//
// Copyright (c) 2010-2011 Lukhnos D. Liu (lukhnos at lukhnos dot org)
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#import "OVInputSourceHelper.h"
static void PrintUsage();
int main(int argc, char **argv)
{
// we'll let the OS clean up this pool for us
[NSAutoreleasePool new];
if (argc < 2) {
PrintUsage();
return 1;
}
int opt;
while ((opt = getopt(argc, argv, "lr:e:d:s:")) != -1) {
switch (opt) {
case 'l':
{
for (id source in [OVInputSourceHelper allInstalledInputSources]) {
if (TISGetInputSourceProperty((TISInputSourceRef)source, kTISPropertyInputSourceType) != kTISTypeKeyboardInputMode) {
printf("%s\n", [(id)TISGetInputSourceProperty((TISInputSourceRef)source, kTISPropertyInputSourceID) UTF8String]);
}
}
break;
}
case 'r':
{
NSURL *bundle = [NSURL fileURLWithPath:[NSString stringWithUTF8String:optarg]];
if (bundle) {
BOOL status = [OVInputSourceHelper registerInputSource:bundle];
NSLog(@"register input source at: %@, result: %d", [bundle absoluteString], status);
}
break;
}
case 'e':
{
TISInputSourceRef inputSource = [OVInputSourceHelper inputSourceForInputSourceID:[NSString stringWithUTF8String:optarg]];
if (!inputSource) {
NSLog(@"Cannot find input source: %s", optarg);
return 1;
}
BOOL status = [OVInputSourceHelper enableInputSource:inputSource];
NSLog(@"Enable input source: %s, result: %d", optarg, status);
return status;
}
case 'd':
{
TISInputSourceRef inputSource = [OVInputSourceHelper inputSourceForInputSourceID:[NSString stringWithUTF8String:optarg]];
if (!inputSource) {
NSLog(@"Cannot find input source: %s", optarg);
return 1;
}
BOOL status = [OVInputSourceHelper disableInputSource:inputSource];
NSLog(@"Disable input source: %s, result: %d", optarg, status);
return status;
}
case 's':
{
TISInputSourceRef inputSource = [OVInputSourceHelper inputSourceForInputSourceID:[NSString stringWithUTF8String:optarg]];
if (!inputSource) {
NSLog(@"Cannot find input source: %s", optarg);
return 1;
}
BOOL status = [OVInputSourceHelper inputSourceEnabled:inputSource];
NSLog(@"Input source: %s, enabled: %@", optarg, (status ? @"yes" : @"no"));
return 0;
}
default:
PrintUsage();
return 1;
}
}
return 0;
}
static void PrintUsage()
{
fprintf(stderr, "usage: tistool [options]\n"
"options:\n"
" -l list all input sources\n"
" -r <path> register an input source\n"
" -e <id> enable an input source\n"
" -d <id> disable an input source\n"
" -s <id> check if an input source is enabled\n\n"
"<id> is an input source id, a few examples:\n"
" com.apple.inputmethod.Kotoeri (Apple's Japanese input method)\n"
" com.apple.CharacterPaletteIM (Keyboard/Character Viewer palettes)\n"
" com.apple.keylayout.German (German keyboard layout)\n"
"\n"
"<path> must be a bundle in one of the directories:\n"
" ~/Library/Input Methods/\n"
" /Library/Input Methods/\n"
" ~/Library/Keyboard Layouts/\n"
" /Library/Keyboard Layouts/\n"
"\n"
);
}