Initial commit: added current work/poc
This commit is contained in:
commit
9514c8d53e
9 changed files with 299 additions and 0 deletions
23
.clang-format
Normal file
23
.clang-format
Normal file
|
@ -0,0 +1,23 @@
|
|||
BasedOnStyle: Microsoft
|
||||
|
||||
UseTab: ForIndentation
|
||||
TabWidth: 4
|
||||
BreakBeforeBraces: Linux
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
PointerAlignment: Left
|
||||
|
||||
AlignAfterOpenBracket: Align
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
|
||||
|
||||
AlignConsecutiveAssignments: Consecutive
|
||||
AlignConsecutiveBitFields: Consecutive
|
||||
AlignConsecutiveDeclarations: Consecutive
|
||||
AlignConsecutiveMacros: Consecutive
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: AlignAfterOperator
|
||||
AlignTrailingComments: true
|
||||
|
||||
ColumnLimit: 80
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
build/
|
8
CMakeLists.txt
Normal file
8
CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
cmake_minimum_required(VERSION 3.21)
|
||||
project(fcitx5-ipa-sil)
|
||||
|
||||
find_package(Fcitx5Core REQUIRED)
|
||||
# Setup some compiler option that is generally useful and compatible with Fcitx 5 (C++17)
|
||||
include("${FCITX_INSTALL_CMAKECONFIG_DIR}/Fcitx5Utils/Fcitx5CompilerSettings.cmake")
|
||||
|
||||
add_subdirectory(src)
|
28
README.md
Normal file
28
README.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
# fcitx5-ipa-sil
|
||||
|
||||
This is an IME for [Fctix 5](https://fcitx-im.org/wiki/Fcitx_5) that brings support for the [SIL IPA](https://keyman.com/keyboards/sil_ipa) input method.
|
||||
|
||||
This allows the user to type IPA characters fairly easly by inputing only ASCII.
|
||||
|
||||
Here are a few examples of SIL to IPA conversions:
|
||||
|
||||
| IPA | SIL |
|
||||
|-----|------|
|
||||
| ə | `e=` |
|
||||
| ʃ | `s=` |
|
||||
| ŋ | `n>` |
|
||||
| a | `a` |
|
||||
|
||||
**This is still a work-in-progress**! This is mostly a rough draft to allow me to follow my phonetics class on a computer. I didn't put much thought into getting it to work for other people's needs! Feel free to send me suggestions though \:)
|
||||
|
||||
## Building & trying it out!
|
||||
|
||||
```console
|
||||
$ mkdir -p build/
|
||||
$ cd build/
|
||||
$ cmake ../ -DCMAKE_INSTALL_PREFIX=/usr
|
||||
$ make
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
You can then restart fcitx, and add the "SIL IPA" input method to your available input methods!
|
12
src/CMakeLists.txt
Normal file
12
src/CMakeLists.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
add_library(ipa-sil SHARED ipa-sil.cpp)
|
||||
target_link_libraries(ipa-sil PRIVATE Fcitx5::Core)
|
||||
set_target_properties(ipa-sil PROPERTIES PREFIX "")
|
||||
install(TARGETS ipa-sil DESTINATION "${FCITX_INSTALL_LIBDIR}/fcitx5")
|
||||
|
||||
# Addon config file
|
||||
# We need additional layer of conversion because we want PROJECT_VERSION in it.
|
||||
configure_file(ipa-sil-addon.conf.in ipa-sil-addon.conf)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ipa-sil-addon.conf" RENAME ipa-sil.conf DESTINATION "${FCITX_INSTALL_PKGDATADIR}/addon")
|
||||
|
||||
# Input Method registration file
|
||||
install(FILES "ipa-sil.conf" DESTINATION "${FCITX_INSTALL_PKGDATADIR}/inputmethod")
|
8
src/ipa-sil-addon.conf.in
Normal file
8
src/ipa-sil-addon.conf.in
Normal file
|
@ -0,0 +1,8 @@
|
|||
[Addon]
|
||||
Name=IPA SIL
|
||||
Category=InputMethod
|
||||
Version=@PROJECT_VERSION@
|
||||
Library=ipa-sil
|
||||
Type=SharedLibrary
|
||||
OnDemand=True
|
||||
Configurable=True
|
13
src/ipa-sil.conf
Normal file
13
src/ipa-sil.conf
Normal file
|
@ -0,0 +1,13 @@
|
|||
[InputMethod]
|
||||
# Translatable name of the input method
|
||||
Name=IPA SIL
|
||||
# Icon name
|
||||
Icon=fcitx-ipa-sil
|
||||
# A short label that present the name of input method
|
||||
Label=sil
|
||||
# ISO 639 language code
|
||||
LangCode=en_GB
|
||||
# Match addon name
|
||||
Addon=ipa-sil
|
||||
# Whether this input method support customization
|
||||
# Configurable=True
|
138
src/ipa-sil.cpp
Normal file
138
src/ipa-sil.cpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Yuki Joou <yukijoou [a] kemonomimi [-] gay>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include "ipa-sil.hpp"
|
||||
|
||||
#include <fcitx/inputpanel.h>
|
||||
#include <fcitx/instance.h>
|
||||
|
||||
std::optional<std::string> getIPAForSIL(std::string baseCharacter,
|
||||
fcitx::KeySym silModifier)
|
||||
{
|
||||
// TODO: Use a proper data structure, like a hash map
|
||||
// Even better: load that data off of a file!
|
||||
if (baseCharacter == "s") {
|
||||
if (silModifier == FcitxKey_equal) return "ʃ";
|
||||
}
|
||||
|
||||
if (baseCharacter == "z") {
|
||||
if (silModifier == FcitxKey_equal) return "ʒ";
|
||||
}
|
||||
|
||||
if (baseCharacter == "t") {
|
||||
if (silModifier == FcitxKey_equal) return "θ";
|
||||
}
|
||||
|
||||
if (baseCharacter == "d") {
|
||||
if (silModifier == FcitxKey_equal) return "ð";
|
||||
}
|
||||
|
||||
if (baseCharacter == "n") {
|
||||
if (silModifier == FcitxKey_greater) return "ŋ";
|
||||
}
|
||||
|
||||
if (baseCharacter == "i") {
|
||||
if (silModifier == FcitxKey_equal) return "ɪ";
|
||||
}
|
||||
|
||||
if (baseCharacter == "e") {
|
||||
if (silModifier == FcitxKey_equal) return "ə";
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool isSILModifier(fcitx::KeySym key)
|
||||
{
|
||||
return key == FcitxKey_less || key == FcitxKey_greater ||
|
||||
key == FcitxKey_equal;
|
||||
}
|
||||
|
||||
void SILState::handleAlphaKey(fcitx::Key key)
|
||||
{
|
||||
if (!isSILModifier(key.sym()) || !m_lastKey.has_value()) {
|
||||
m_lastKey = key.toString();
|
||||
m_buffer.type(key.sym());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSILModifier(key.sym())) {
|
||||
auto ipaChar = getIPAForSIL(*m_lastKey, key.sym());
|
||||
if (ipaChar) {
|
||||
m_buffer.backspace();
|
||||
m_buffer.type(*ipaChar);
|
||||
}
|
||||
m_lastKey.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void SILState::keyEvent(fcitx::KeyEvent& keyEvent)
|
||||
{
|
||||
// If it's not a simple letter key, and we have no text input yet, let it
|
||||
// through.
|
||||
if (m_buffer.empty() && !keyEvent.key().isSimple()) return;
|
||||
|
||||
if (keyEvent.key().check(FcitxKey_Return)) {
|
||||
m_ic->commitString(m_buffer.userInput());
|
||||
reset();
|
||||
} else if (keyEvent.key().check(FcitxKey_space)) {
|
||||
m_ic->commitString(m_buffer.userInput());
|
||||
m_ic->commitString(" ");
|
||||
reset();
|
||||
} else if (keyEvent.key().check(FcitxKey_BackSpace))
|
||||
m_buffer.backspace();
|
||||
else if (keyEvent.key().isSimple())
|
||||
handleAlphaKey(keyEvent.key());
|
||||
// m_buffer.type(keyEvent.key().sym());
|
||||
updateUI();
|
||||
|
||||
keyEvent.filterAndAccept();
|
||||
}
|
||||
|
||||
void SILState::updateUI()
|
||||
{
|
||||
auto& inputPanel = m_ic->inputPanel();
|
||||
inputPanel.reset();
|
||||
|
||||
if (m_ic->capabilityFlags().test(fcitx::CapabilityFlag::Preedit)) {
|
||||
fcitx::Text preedit(m_buffer.userInput(),
|
||||
fcitx::TextFormatFlag::HighLight);
|
||||
inputPanel.setClientPreedit(preedit);
|
||||
} else {
|
||||
fcitx::Text preedit(m_buffer.userInput());
|
||||
inputPanel.setPreedit(preedit);
|
||||
}
|
||||
m_ic->updateUserInterface(fcitx::UserInterfaceComponent::InputPanel);
|
||||
m_ic->updatePreedit();
|
||||
}
|
||||
|
||||
SILEngine::SILEngine(fcitx::Instance* instance)
|
||||
: m_factory(
|
||||
[this](fcitx::InputContext& ic) { return new SILState(this, &ic); })
|
||||
{
|
||||
instance->inputContextManager().registerProperty("silState", &m_factory);
|
||||
}
|
||||
|
||||
void SILEngine::keyEvent(const fcitx::InputMethodEntry&,
|
||||
fcitx::KeyEvent& keyEvent)
|
||||
{
|
||||
if (keyEvent.isRelease() || keyEvent.key().states()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto ic = keyEvent.inputContext();
|
||||
auto* state = ic->propertyFor(&m_factory);
|
||||
state->keyEvent(keyEvent);
|
||||
}
|
||||
|
||||
void SILEngine::reset(const fcitx::InputMethodEntry&,
|
||||
fcitx::InputContextEvent& event)
|
||||
{
|
||||
auto* state = event.inputContext()->propertyFor(&m_factory);
|
||||
state->reset();
|
||||
}
|
||||
|
||||
FCITX_ADDON_FACTORY(SILEngineFactory);
|
68
src/ipa-sil.hpp
Normal file
68
src/ipa-sil.hpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Yuki Joou <yukijoou [a] kemonomimi [-] gay>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <fcitx-utils/inputbuffer.h>
|
||||
#include <fcitx/addonfactory.h>
|
||||
#include <fcitx/addonmanager.h>
|
||||
#include <fcitx/inputcontextproperty.h>
|
||||
#include <fcitx/inputmethodengine.h>
|
||||
#include <fcitx/instance.h>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
class SILEngine;
|
||||
|
||||
class SILState : public fcitx::InputContextProperty
|
||||
{
|
||||
public:
|
||||
SILState(SILEngine* engine, fcitx::InputContext* ic)
|
||||
: m_engine(engine), m_ic(ic)
|
||||
{
|
||||
}
|
||||
|
||||
void handleAlphaKey(fcitx::Key);
|
||||
void keyEvent(fcitx::KeyEvent& keyEvent);
|
||||
|
||||
void updateUI();
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_buffer.clear();
|
||||
updateUI();
|
||||
}
|
||||
|
||||
private:
|
||||
SILEngine* m_engine;
|
||||
fcitx::InputContext* m_ic;
|
||||
fcitx::InputBuffer m_buffer{{fcitx::InputBufferOption::NoOption}};
|
||||
|
||||
std::optional<std::string> m_lastKey{};
|
||||
};
|
||||
|
||||
class SILEngine : public fcitx::InputMethodEngineV2
|
||||
{
|
||||
public:
|
||||
SILEngine(fcitx::Instance*);
|
||||
|
||||
void keyEvent(const fcitx::InputMethodEntry&, fcitx::KeyEvent&) override;
|
||||
void reset(const fcitx::InputMethodEntry&,
|
||||
fcitx::InputContextEvent&) override;
|
||||
|
||||
private:
|
||||
fcitx::FactoryFor<SILState> m_factory;
|
||||
};
|
||||
|
||||
class SILEngineFactory : public fcitx::AddonFactory
|
||||
{
|
||||
fcitx::AddonInstance* create(fcitx::AddonManager* manager) override
|
||||
{
|
||||
FCITX_UNUSED(manager);
|
||||
return new SILEngine(manager->instance());
|
||||
}
|
||||
};
|
Loading…
Reference in a new issue