Skip to content

Commit 3da5196

Browse files
committed
Fix #1
1. Make sure the preedit is correctly clearer when m17n report empty. 2. Commit preedit upon deactivate input method. 3. Fix key translation: Last commit tries to avoid normalization, this is actually only partial correct because for raw symbol, Shift mask should still be ignored. Alt+o -> Alt+o Shift+: -> : 4. Add test for Wijesekera.
1 parent becda82 commit 3da5196

8 files changed

+226
-6
lines changed

CMakeLists.txt

+21-2
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,46 @@ include(FeatureSummary)
88
include(GNUInstallDirs)
99
include(ECMUninstallTarget)
1010

11+
option(ENABLE_TEST "Build Test" On)
12+
option(ENABLE_COVERAGE "Build the project with gcov support (Need ENABLE_TEST=On)" Off)
13+
set(GCOV_TOOL "gcov" CACHE STRING "Path to gcov tool used by coverage.")
14+
1115
find_package(Fcitx5Core 5.0.2 REQUIRED)
16+
find_package(Fcitx5Module REQUIRED COMPONENTS TestFrontend)
1217
find_package(Gettext REQUIRED)
18+
find_package(Pthread REQUIRED)
1319
find_package(fmt REQUIRED)
1420
find_package(PkgConfig REQUIRED)
1521
pkg_check_modules(M17NGui IMPORTED_TARGET "m17n-gui>=1.6.3" REQUIRED)
22+
# Required for data and testing
23+
pkg_check_modules(M17NDB "m17n-db" REQUIRED)
1624

1725
if (TARGET fmt::fmt-header-only)
1826
set(FMT_TARGET fmt::fmt-header-only)
1927
else()
2028
set(FMT_TARGET fmt::fmt)
2129
endif ()
2230

23-
option(ENABLE_TEST "standalone test program" Off)
24-
2531
include("${FCITX_INSTALL_CMAKECONFIG_DIR}/Fcitx5Utils/Fcitx5CompilerSettings.cmake")
2632
add_definitions(-DFCITX_GETTEXT_DOMAIN=\"fcitx5-m17n\" -D_GNU_SOURCE)
2733
fcitx5_add_i18n_definition()
2834

2935
add_subdirectory(po)
3036
add_subdirectory(im)
3137

38+
if (ENABLE_TEST)
39+
enable_testing()
40+
add_subdirectory(test)
41+
42+
if (ENABLE_COVERAGE)
43+
add_custom_target(coverage
44+
COMMAND "${CMAKE_CTEST_COMMAND}"
45+
COMMAND lcov --gcov-tool "${GCOV_TOOL}" --no-external --capture --directory ./ -b "${CMAKE_CURRENT_SOURCE_DIR}" --output-file coverage.info
46+
COMMAND genhtml coverage.info --output-directory "coverage_pages"
47+
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
48+
endif()
49+
endif ()
50+
3251
fcitx5_translate_desktop_file(org.fcitx.Fcitx5.Addon.M17N.metainfo.xml.in
3352
org.fcitx.Fcitx5.Addon.M17N.metainfo.xml XML)
3453

cmake/FindPthread.cmake

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Try to find Pthread functionality
2+
# Once done this will define
3+
#
4+
# PTHREAD_FOUND - system has Pthread
5+
# PTHREAD_INCLUDE_DIR - Pthread include directory
6+
# PTHREAD_LIBRARIES - Libraries needed to use Pthread
7+
#
8+
# TODO: This will enable translations only if Gettext functionality is
9+
# present in libc. Must have more robust system for release, where Gettext
10+
# functionality can also reside in standalone Gettext library, or the one
11+
# embedded within kdelibs (cf. gettext.m4 from Gettext source).
12+
#
13+
# Copyright (c) 2006, Chusslove Illich, <[email protected]>
14+
# Copyright (c) 2007, Alexander Neundorf, <[email protected]>
15+
# Copyright (c) 2016, Xuetian Weng <[email protected]>
16+
#
17+
# Redistribution and use is allowed according to the terms of the BSD license.
18+
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
19+
20+
find_path(PTHREAD_INCLUDE_DIR NAMES pthread.h)
21+
22+
if(PTHREAD_INCLUDE_DIR)
23+
include(CheckFunctionExists)
24+
check_function_exists(pthread_create PTHREAD_LIBC_HAS_PTHREAD_CREATE)
25+
26+
if (PTHREAD_LIBC_HAS_PTHREAD_CREATE)
27+
set(PTHREAD_LIBRARIES)
28+
set(PTHREAD_LIB_FOUND TRUE)
29+
else (PTHREAD_LIBC_HAS_PTHREAD_CREATE)
30+
find_library(PTHREAD_LIBRARIES NAMES pthread libpthread )
31+
if(PTHREAD_LIBRARIES)
32+
set(PTHREAD_LIB_FOUND TRUE)
33+
endif(PTHREAD_LIBRARIES)
34+
endif (PTHREAD_LIBC_HAS_PTHREAD_CREATE)
35+
36+
endif(PTHREAD_INCLUDE_DIR)
37+
38+
include(FindPackageHandleStandardArgs)
39+
find_package_handle_standard_args(Pthread
40+
FOUND_VAR
41+
PTHREAD_FOUND
42+
REQUIRED_VARS
43+
PTHREAD_INCLUDE_DIR PTHREAD_LIB_FOUND
44+
)
45+
46+
if(PTHREAD_FOUND AND NOT TARGET Pthread::Pthread)
47+
if (PTHREAD_LIBRARIES)
48+
add_library(Pthread::Pthread UNKNOWN IMPORTED)
49+
set_target_properties(Pthread::Pthread PROPERTIES
50+
IMPORTED_LOCATION "${PTHREAD_LIBRARIES}")
51+
else()
52+
add_library(Pthread::Pthread INTERFACE IMPORTED )
53+
endif()
54+
set_target_properties(Pthread::Pthread PROPERTIES
55+
INTERFACE_INCLUDE_DIRECTORIES "${PTHREAD_INCLUDE_DIR}"
56+
)
57+
endif()
58+
59+
mark_as_advanced(PTHREAD_INCLUDE_DIR PTHREAD_LIBRARIES PTHREAD_LIBC_HAS_PTHREAD_CREATE PTHREAD_LIB_FOUND)

im/engine.cpp

+33-4
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,14 @@ MSymbol KeySymToSymbol(Key key) {
8686
if (key.sym() >= FcitxKey_space && key.sym() <= FcitxKey_asciitilde) {
8787
KeySym c = key.sym();
8888

89-
if (key.sym() == FcitxKey_space && key.states().test(KeyState::Shift))
89+
if (key.sym() == FcitxKey_space && key.states().test(KeyState::Shift)) {
9090
mask |= KeyState::Shift;
91+
}
9192

9293
if (key.states().test(KeyState::Ctrl)) {
93-
if (c >= FcitxKey_a && c <= FcitxKey_z)
94+
if (c >= FcitxKey_a && c <= FcitxKey_z) {
9495
c = static_cast<KeySym>(c + FcitxKey_A - FcitxKey_a);
96+
}
9597
mask |= KeyState::Ctrl;
9698
}
9799

@@ -105,7 +107,9 @@ MSymbol KeySymToSymbol(Key key) {
105107
}
106108
}
107109

108-
mask |= key.states() & (KeyState::UsedMask);
110+
mask |=
111+
key.states() & KeyStates{KeyState::Mod1, KeyState::Mod5, KeyState::Meta,
112+
KeyState::Super, KeyState::Hyper};
109113

110114
// we have 7 possible below, then 20 is long enough (7 x 2 = 14 < 20)
111115
char prefix[20] = "";
@@ -169,7 +173,6 @@ inline static void SetPreedit(InputContext *ic, const std::string &s,
169173

170174
if (ic->capabilityFlags().test(CapabilityFlag::Preedit)) {
171175
ic->inputPanel().setClientPreedit(preedit);
172-
ic->updatePreedit();
173176
} else {
174177
ic->inputPanel().setPreedit(preedit);
175178
}
@@ -363,6 +366,16 @@ std::vector<InputMethodEntry> M17NEngine::listInputMethods() {
363366

364367
void M17NEngine::activate(const InputMethodEntry &, InputContextEvent &) {}
365368

369+
void M17NEngine::deactivate(const InputMethodEntry &,
370+
InputContextEvent &event) {
371+
auto inputContext = event.inputContext();
372+
auto state = inputContext->propertyFor(&factory_);
373+
if (event.type() == EventType::InputContextSwitchInputMethod) {
374+
state->commitPreedit();
375+
}
376+
state->reset();
377+
}
378+
366379
void M17NEngine::keyEvent(const InputMethodEntry &entry, KeyEvent &keyEvent) {
367380
if (keyEvent.isRelease()) {
368381
return;
@@ -486,7 +499,9 @@ void M17NState::updateUI() {
486499
if (!preedit.empty()) {
487500
SetPreedit(ic_, preedit, mic_->cursor_pos);
488501
}
502+
FCITX_M17N_DEBUG() << "IM preedit changed to " << preedit;
489503
}
504+
ic_->updatePreedit();
490505

491506
if (mic_->status) {
492507
auto mstatus = MTextToUTF8(mic_->status);
@@ -513,6 +528,20 @@ void M17NState::reset() {
513528
updateUI();
514529
}
515530

531+
void M17NState::commitPreedit() {
532+
if (!mic_) {
533+
return;
534+
}
535+
536+
if (!mic_->preedit) {
537+
return;
538+
}
539+
auto preedit = MTextToUTF8(mic_->preedit);
540+
if (!preedit.empty()) {
541+
ic_->commitString(preedit);
542+
}
543+
}
544+
516545
void M17NState::select(int index) {
517546
if (!mic_) {
518547
return;

im/engine.h

+3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class M17NState : public InputContextProperty {
4848
void updateUI();
4949
void select(int index);
5050
void reset();
51+
void commitPreedit();
5152
bool keyEvent(const Key &key);
5253

5354
static void callback(MInputContext *context, MSymbol command);
@@ -64,6 +65,8 @@ class M17NEngine : public InputMethodEngine {
6465

6566
void activate(const fcitx::InputMethodEntry &,
6667
fcitx::InputContextEvent &) override;
68+
void deactivate(const fcitx::InputMethodEntry &entry,
69+
fcitx::InputContextEvent &event) override;
6770
void keyEvent(const fcitx::InputMethodEntry &entry,
6871
fcitx::KeyEvent &keyEvent) override;
6972
void reloadConfig() override;

test/CMakeLists.txt

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
configure_file(testdir.h.in ${CMAKE_CURRENT_BINARY_DIR}/testdir.h @ONLY)
3+
include_directories(${CMAKE_CURRENT_BINARY_DIR})
4+
5+
add_subdirectory(addon)
6+
add_executable(testm17n testm17n.cpp)
7+
target_link_libraries(testm17n Fcitx5::Core Fcitx5::Module::TestFrontend Pthread::Pthread)
8+
add_dependencies(testm17n m17n copy-addon)
9+
add_test(testm17n testm17n)

test/addon/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
add_custom_target(copy-addon DEPENDS m17n.conf.in-fmt)
2+
add_custom_command(TARGET copy-addon COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/im/m17n.conf ${CMAKE_CURRENT_BINARY_DIR}/m17n.conf)

test/testdir.h.in

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2021~2021 CSSlayer <[email protected]>
3+
*
4+
* SPDX-License-Identifier: GPL-2.0-or-later
5+
*/
6+
#ifndef _TEST_TESTDIR_H_
7+
#define _TEST_TESTDIR_H_
8+
9+
#define TESTING_SOURCE_DIR "@CMAKE_SOURCE_DIR@"
10+
#define TESTING_BINARY_DIR "@CMAKE_BINARY_DIR@"
11+
12+
#endif // _TEST_TESTDIR_H_

test/testm17n.cpp

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2021-2021 CSSlayer <[email protected]>
3+
*
4+
* SPDX-License-Identifier: GPL-2.0-or-later
5+
*
6+
*/
7+
#include "testdir.h"
8+
#include "testfrontend_public.h"
9+
#include <fcitx-utils/eventdispatcher.h>
10+
#include <fcitx-utils/log.h>
11+
#include <fcitx-utils/standardpath.h>
12+
#include <fcitx-utils/testing.h>
13+
#include <fcitx/addonmanager.h>
14+
#include <fcitx/inputcontextmanager.h>
15+
#include <fcitx/inputmethodmanager.h>
16+
#include <fcitx/instance.h>
17+
#include <iostream>
18+
#include <thread>
19+
20+
using namespace fcitx;
21+
22+
void scheduleEvent(EventDispatcher *dispatcher, Instance *instance) {
23+
dispatcher->schedule([dispatcher, instance]() {
24+
auto *m17n = instance->addonManager().addon("m17n", true);
25+
FCITX_ASSERT(m17n);
26+
auto defaultGroup = instance->inputMethodManager().currentGroup();
27+
defaultGroup.inputMethodList().clear();
28+
defaultGroup.inputMethodList().push_back(
29+
InputMethodGroupItem("keyboard-us"));
30+
defaultGroup.inputMethodList().push_back(
31+
InputMethodGroupItem("m17n_si_wijesekera"));
32+
defaultGroup.setDefaultInputMethod("");
33+
instance->inputMethodManager().setGroup(defaultGroup);
34+
auto *testfrontend = instance->addonManager().addon("testfrontend");
35+
auto uuid =
36+
testfrontend->call<ITestFrontend::createInputContext>("testapp");
37+
auto ic = instance->inputContextManager().findByUUID(uuid);
38+
ic->focusIn();
39+
testfrontend->call<ITestFrontend::pushCommitExpectation>("");
40+
testfrontend->call<ITestFrontend::pushCommitExpectation>("");
41+
testfrontend->call<ITestFrontend::pushCommitExpectation>("");
42+
testfrontend->call<ITestFrontend::pushCommitExpectation>("");
43+
testfrontend->call<ITestFrontend::pushCommitExpectation>("");
44+
testfrontend->call<ITestFrontend::pushCommitExpectation>(":");
45+
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("Control+space"),
46+
false);
47+
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("Alt+o"), false);
48+
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("Alt+period"),
49+
false);
50+
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("period"), false);
51+
testfrontend->call<ITestFrontend::keyEvent>(
52+
uuid, Key(FcitxKey_bracketleft), false);
53+
testfrontend->call<ITestFrontend::keyEvent>(
54+
uuid, Key(FcitxKey_braceleft), false);
55+
testfrontend->call<ITestFrontend::keyEvent>(
56+
uuid, Key(FcitxKey_braceright), false);
57+
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("Control+space"),
58+
false);
59+
60+
dispatcher->schedule([dispatcher, instance]() {
61+
dispatcher->detach();
62+
instance->exit();
63+
});
64+
});
65+
}
66+
67+
void runInstance() {}
68+
69+
int main() {
70+
setupTestingEnvironment(TESTING_BINARY_DIR, {TESTING_BINARY_DIR "/im"},
71+
{TESTING_BINARY_DIR "/test"});
72+
// fcitx::Log::setLogRule("default=5,table=5,libime-table=5");
73+
char arg0[] = "testm17n";
74+
char arg1[] = "--disable=all";
75+
char arg2[] = "--enable=testim,testfrontend,m17n,testui";
76+
char *argv[] = {arg0, arg1, arg2};
77+
fcitx::Log::setLogRule("default=5,m17n=5");
78+
Instance instance(FCITX_ARRAY_SIZE(argv), argv);
79+
instance.addonManager().registerDefaultLoader(nullptr);
80+
EventDispatcher dispatcher;
81+
dispatcher.attach(&instance.eventLoop());
82+
std::thread thread(scheduleEvent, &dispatcher, &instance);
83+
instance.exec();
84+
thread.join();
85+
86+
return 0;
87+
}

0 commit comments

Comments
 (0)