Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tsf): accomplish candidate UI interfaces #156

Merged
merged 23 commits into from
Mar 31, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
57fe8c3
feat: display UI in text service, support UI-less mode
nameoverflow Mar 25, 2018
1828cc7
ci(appveyor.install): add additional boost lib
nameoverflow Mar 25, 2018
b919015
build(WeaselTSF): revert building options
nameoverflow Mar 25, 2018
8ca8b77
fix(CandidateList): ensure correct owner
nameoverflow Mar 26, 2018
06aaab1
feat(ipc): implement style deserializer
nameoverflow Mar 26, 2018
156583c
refactor(server): move tray icon out of WeaselUI
nameoverflow Mar 26, 2018
9406729
feat(RimeWithWeasel): sync style settings with frontend; only show UI…
nameoverflow Mar 26, 2018
c477eb8
feat(composition): handle unfocus
nameoverflow Mar 26, 2018
75754ac
fix(tray_icon): fix tray icon
nameoverflow Mar 26, 2018
a113519
fix(CandidateList): fix COM reference count
nameoverflow Mar 26, 2018
145cbdc
fix(tsf): fix the order of initialization
nameoverflow Mar 26, 2018
34cbdc9
feat(tsf): make candidate window work with TSF composition
nameoverflow Mar 27, 2018
4ca3864
fix(tsf): candidate position
nameoverflow Mar 28, 2018
19c211f
refactor: COM smart pointer
nameoverflow Mar 28, 2018
77b94a2
Merge remote-tracking branch 'rime/master' into frontend
nameoverflow Mar 28, 2018
7533ac9
feat(RimeWithWeasel): sync UI style after switching to new schema
nameoverflow Mar 29, 2018
d61e4e9
feat(tsf): improve unfocus behavior
nameoverflow Mar 29, 2018
3dfb9e7
feat(tsf): update server input position
nameoverflow Mar 31, 2018
df0b4d6
feat(tsf): implement `ITfIntegratableCandidateListUIElement` for `Can…
nameoverflow Mar 31, 2018
6886697
chore(weasel.sln): revert solution file to VS2015 format
Prcuvu Mar 31, 2018
9009008
chore(tsf): implement ITfTextInputProcessorEx
Prcuvu Mar 31, 2018
8b17b3a
chore(tsf): fix typo
Prcuvu Mar 31, 2018
1720e32
Merge pull request #3 from Prcuvu/patch-1
nameoverflow Mar 31, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ weasel.props
*.swp
.vs
Thumbs.db
/.idea
/cmake-build-debug
217 changes: 139 additions & 78 deletions RimeWithWeasel/RimeWithWeasel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
#include <StringAlgorithm.hpp>
#include <WeaselUtility.h>
#include <WeaselVersion.h>
#include <algorithm>
#include <list>
#include <set>
#include <string>

#include <rime_api.h>

Expand All @@ -17,7 +13,10 @@ int expand_ibus_modifier(int m)
}

RimeWithWeaselHandler::RimeWithWeaselHandler(weasel::UI *ui)
: m_ui(ui), m_active_session(0), m_disabled(true)
: m_ui(ui)
, m_active_session(0)
, m_disabled(true)
, _UpdateUICallback(NULL)
{
_Setup();
}
Expand Down Expand Up @@ -252,6 +251,35 @@ void RimeWithWeaselHandler::_ReadClientInfo(UINT session_id, LPWSTR buffer)
RimeSetOption(session_id, "soft_cursor", Bool(!inline_preedit));
}

void RimeWithWeaselHandler::_GetCandidateInfo(weasel::CandidateInfo & cinfo, RimeContext & ctx)
{
cinfo.candies.resize(ctx.menu.num_candidates);
cinfo.comments.resize(ctx.menu.num_candidates);
cinfo.labels.resize(ctx.menu.num_candidates);
for (int i = 0; i < ctx.menu.num_candidates; ++i)
{
cinfo.candies[i].str = utf8towcs(ctx.menu.candidates[i].text);
if (ctx.menu.candidates[i].comment)
{
cinfo.comments[i].str = utf8towcs(ctx.menu.candidates[i].comment);
}
if (RIME_STRUCT_HAS_MEMBER(ctx, ctx.select_labels) && ctx.select_labels)
{
cinfo.labels[i].str = utf8towcs(ctx.select_labels[i]);
}
else if (ctx.menu.select_keys)
{
cinfo.labels[i].str = std::wstring(1, ctx.menu.select_keys[i]);
}
else
{
cinfo.labels[i].str = std::to_wstring((i + 1) % 10);
}
}
cinfo.highlighted = ctx.menu.highlighted_candidate_index;
cinfo.currentPage = ctx.menu.page_no;
}

void RimeWithWeaselHandler::StartMaintenance()
{
Finalize();
Expand All @@ -267,6 +295,12 @@ void RimeWithWeaselHandler::EndMaintenance()
}
}

void RimeWithWeaselHandler::OnUpdateUI(std::function<void()> const &cb)
{
_UpdateUICallback = cb;
}


bool RimeWithWeaselHandler::_IsDeployerRunning()
{
HANDLE hMutex = CreateMutex(NULL, TRUE, L"WeaselDeployerMutex");
Expand All @@ -284,88 +318,36 @@ void RimeWithWeaselHandler::_UpdateUI(UINT session_id)
weasel::Status weasel_status;
weasel::Context weasel_context;

bool is_tsf = _IsSessionTSF(session_id);

if (session_id == 0)
weasel_status.disabled = m_disabled;

RIME_STRUCT(RimeStatus, status);
if (RimeGetStatus(session_id, &status))
{
std::string schema_id = status.schema_id;
if (schema_id != m_last_schema_id)
{
m_last_schema_id = schema_id;
_LoadSchemaSpecificSettings(schema_id);
}
weasel_status.schema_name = utf8towcs(status.schema_name);
weasel_status.ascii_mode = !!status.is_ascii_mode;
weasel_status.composing = !!status.is_composing;
weasel_status.disabled = !!status.is_disabled;
RimeFreeStatus(&status);
}
_GetStatus(weasel_status, session_id);

RIME_STRUCT(RimeContext, ctx);
if (RimeGetContext(session_id, &ctx))
{
if (ctx.composition.length > 0)
{
weasel_context.preedit.str = utf8towcs(ctx.composition.preedit);
if (ctx.composition.sel_start < ctx.composition.sel_end)
{
weasel::TextAttribute attr;
attr.type = weasel::HIGHLIGHTED;
attr.range.start = utf8towcslen(ctx.composition.preedit, ctx.composition.sel_start);
attr.range.end = utf8towcslen(ctx.composition.preedit, ctx.composition.sel_end);

weasel_context.preedit.attributes.push_back(attr);
}
}
if (ctx.menu.num_candidates)
{
weasel::CandidateInfo &cinfo(weasel_context.cinfo);
cinfo.candies.resize(ctx.menu.num_candidates);
cinfo.comments.resize(ctx.menu.num_candidates);
cinfo.labels.resize(ctx.menu.num_candidates);
for (int i = 0; i < ctx.menu.num_candidates; ++i)
{
cinfo.candies[i].str = utf8towcs(ctx.menu.candidates[i].text);
if (ctx.menu.candidates[i].comment)
{
cinfo.comments[i].str = utf8towcs(ctx.menu.candidates[i].comment);
}
if (RIME_STRUCT_HAS_MEMBER(ctx, ctx.select_labels) && ctx.select_labels)
{
cinfo.labels[i].str = utf8towcs(ctx.select_labels[i]);
}
else if (ctx.menu.select_keys)
{
cinfo.labels[i].str = std::wstring(1, ctx.menu.select_keys[i]);
}
else
{
cinfo.labels[i].str = std::to_wstring((i + 1) % 10);
}
}
cinfo.highlighted = ctx.menu.highlighted_candidate_index;
cinfo.currentPage = ctx.menu.page_no;
}
RimeFreeContext(&ctx);
if (!is_tsf) {
_GetContext(weasel_context, session_id);
}

if (!m_ui) return;
if (RimeGetOption(session_id, "inline_preedit"))
m_ui->style().client_caps |= weasel::INLINE_PREEDIT_CAPABLE;
else
m_ui->style().client_caps &= ~weasel::INLINE_PREEDIT_CAPABLE;


if (weasel_status.composing)
{
m_ui->Update(weasel_context, weasel_status);
m_ui->Show();
if (!is_tsf) m_ui->Show();
}
else if (!_ShowMessage(weasel_context, weasel_status))
{
m_ui->Hide();
m_ui->Update(weasel_context, weasel_status);
}

if (_UpdateUICallback) _UpdateUICallback();

m_message_type.clear();
m_message_value.clear();
Expand Down Expand Up @@ -458,7 +440,7 @@ bool RimeWithWeaselHandler::_Respond(UINT session_id, EatLine eat)
actions.insert("ctx");
switch (m_ui->style().preedit_type)
{
case weasel::PREVIEW:
case weasel::UIStyle::PREVIEW:
if (ctx.commit_text_preview != NULL)
{
std::string first = ctx.commit_text_preview;
Expand All @@ -469,7 +451,7 @@ bool RimeWithWeaselHandler::_Respond(UINT session_id, EatLine eat)
break;
}
// no preview, fall back to composition
case weasel::COMPOSITION:
case weasel::UIStyle::COMPOSITION:
messages.push_back(std::string("ctx.preedit=") + ctx.composition.preedit + '\n');
if (ctx.composition.sel_start <= ctx.composition.sel_end)
{
Expand All @@ -480,13 +462,36 @@ bool RimeWithWeaselHandler::_Respond(UINT session_id, EatLine eat)
break;
}
}
if (ctx.menu.num_candidates)
{
weasel::CandidateInfo cinfo;
std::wstringstream ss;
boost::archive::text_woarchive oa(ss);
_GetCandidateInfo(cinfo, ctx);

oa << cinfo;

messages.push_back(std::string("ctx.cand=") + wcstoutf8(ss.str().c_str()) + '\n');
}
RimeFreeContext(&ctx);
}

// configuration information
actions.insert("config");
messages.push_back(std::string("config.inline_preedit=") + std::to_string((int)m_ui->style().inline_preedit) + '\n');

// style
bool has_synced = RimeGetOption(session_id, "__synced");
if (!has_synced) {
std::wstringstream ss;
boost::archive::text_woarchive oa(ss);
oa << m_ui->style();

actions.insert("style");
messages.push_back(std::string("style=") + wcstoutf8(ss.str().c_str()) + '\n');
RimeSetOption(session_id, "__synced", true);
}

// summarize

if (actions.empty())
Expand Down Expand Up @@ -519,6 +524,7 @@ static inline COLORREF blend_colors(COLORREF fcolor, COLORREF bcolor)
static void _UpdateUIStyle(RimeConfig* config, weasel::UI* ui, bool initialize)
{
if (!ui) return;

weasel::UIStyle &style(ui->style());

const int BUF_SIZE = 99;
Expand All @@ -538,9 +544,9 @@ static void _UpdateUIStyle(RimeConfig* config, weasel::UI* ui, bool initialize)
if (RimeConfigGetString(config, "style/preedit_type", preedit_type, sizeof(preedit_type) - 1))
{
if (!std::strcmp(preedit_type, "composition"))
style.preedit_type = weasel::COMPOSITION;
style.preedit_type = weasel::UIStyle::COMPOSITION;
else if (!std::strcmp(preedit_type, "preview"))
style.preedit_type = weasel::PREVIEW;
style.preedit_type = weasel::UIStyle::PREVIEW;
}
Bool display_tray_icon = False;
if (RimeConfigGetBool(config, "style/display_tray_icon", &display_tray_icon) || initialize)
Expand All @@ -550,13 +556,13 @@ static void _UpdateUIStyle(RimeConfig* config, weasel::UI* ui, bool initialize)
Bool horizontal = False;
if (RimeConfigGetBool(config, "style/horizontal", &horizontal) || initialize)
{
style.layout_type = horizontal ? weasel::LAYOUT_HORIZONTAL : weasel::LAYOUT_VERTICAL;
style.layout_type = horizontal ? weasel::UIStyle::LAYOUT_HORIZONTAL : weasel::UIStyle::LAYOUT_VERTICAL;
}
Bool fullscreen = False;
if (RimeConfigGetBool(config, "style/fullscreen", &fullscreen) && fullscreen)
{
style.layout_type = (style.layout_type == weasel::LAYOUT_HORIZONTAL)
? weasel::LAYOUT_HORIZONTAL_FULLSCREEN : weasel::LAYOUT_VERTICAL_FULLSCREEN;
style.layout_type = (style.layout_type == weasel::UIStyle::LAYOUT_HORIZONTAL)
? weasel::UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN : weasel::UIStyle::LAYOUT_VERTICAL_FULLSCREEN;
}
char label_text_format[128] = { 0 };
if (RimeConfigGetString(config, "style/label_format", label_text_format, sizeof(label_text_format) - 1))
Expand All @@ -568,13 +574,13 @@ static void _UpdateUIStyle(RimeConfig* config, weasel::UI* ui, bool initialize)
if (RimeConfigGetString(config, "style/layout/type", layout_type, sizeof(layout_type) - 1))
{
if (!std::strcmp(layout_type, "vertical"))
style.layout_type = weasel::LAYOUT_VERTICAL;
style.layout_type = weasel::UIStyle::LAYOUT_VERTICAL;
else if (!std::strcmp(layout_type, "horizontal"))
style.layout_type = weasel::LAYOUT_HORIZONTAL;
style.layout_type = weasel::UIStyle::LAYOUT_HORIZONTAL;
if (!std::strcmp(layout_type, "vertical+fullscreen"))
style.layout_type = weasel::LAYOUT_VERTICAL_FULLSCREEN;
style.layout_type = weasel::UIStyle::LAYOUT_VERTICAL_FULLSCREEN;
else if (!std::strcmp(layout_type, "horizontal+fullscreen"))
style.layout_type = weasel::LAYOUT_HORIZONTAL_FULLSCREEN;
style.layout_type = weasel::UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN;
else
LOG(WARNING) << "Invalid style type: " << layout_type;
}
Expand Down Expand Up @@ -658,3 +664,58 @@ static void _LoadAppOptions(RimeConfig* config, AppOptionsByAppName& app_options
}
RimeConfigEnd(&app_iter);
}

void RimeWithWeaselHandler::_GetStatus(weasel::Status & stat, UINT session_id)
{
RIME_STRUCT(RimeStatus, status);
if (RimeGetStatus(session_id, &status))
{
std::string schema_id = status.schema_id;
if (schema_id != m_last_schema_id)
{
m_last_schema_id = schema_id;
RimeSetOption(session_id, "__synced", false); // Sync new schema options with front end
_LoadSchemaSpecificSettings(schema_id);
}
stat.schema_name = utf8towcs(status.schema_name);
stat.ascii_mode = !!status.is_ascii_mode;
stat.composing = !!status.is_composing;
stat.disabled = !!status.is_disabled;
RimeFreeStatus(&status);
}

}

void RimeWithWeaselHandler::_GetContext(weasel::Context & weasel_context, UINT session_id)
{
RIME_STRUCT(RimeContext, ctx);
if (RimeGetContext(session_id, &ctx))
{
if (ctx.composition.length > 0)
{
weasel_context.preedit.str = utf8towcs(ctx.composition.preedit);
if (ctx.composition.sel_start < ctx.composition.sel_end)
{
weasel::TextAttribute attr;
attr.type = weasel::HIGHLIGHTED;
attr.range.start = utf8towcslen(ctx.composition.preedit, ctx.composition.sel_start);
attr.range.end = utf8towcslen(ctx.composition.preedit, ctx.composition.sel_end);

weasel_context.preedit.attributes.push_back(attr);
}
}
if (ctx.menu.num_candidates)
{
weasel::CandidateInfo &cinfo(weasel_context.cinfo);
_GetCandidateInfo(cinfo, ctx);
}
RimeFreeContext(&ctx);
}
}

bool RimeWithWeaselHandler::_IsSessionTSF(UINT session_id)
{
static char client_type[20] = { 0 };
RimeGetProperty(session_id, "client_type", client_type, sizeof(client_type) - 1);
return std::string(client_type) == "tsf";
}
23 changes: 0 additions & 23 deletions RimeWithWeasel/WeaselUtility.cpp
Original file line number Diff line number Diff line change
@@ -1,29 +1,6 @@
#include "stdafx.h"
#include <string>

const char* wcstoutf8(const WCHAR* wstr)
{
const int buffer_len = 1024;
static char buffer[buffer_len];
memset(buffer, 0, sizeof(buffer));
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, buffer, buffer_len - 1, NULL, NULL);
return buffer;
}

const WCHAR* utf8towcs(const char* utf8_str)
{
const int buffer_len = 4096;
static WCHAR buffer[buffer_len];
memset(buffer, 0, sizeof(buffer));
MultiByteToWideChar(CP_UTF8, 0, utf8_str, -1, buffer, buffer_len - 1);
return buffer;
}

int utf8towcslen(const char* utf8_str, int utf8_len)
{
return MultiByteToWideChar(CP_UTF8, 0, utf8_str, utf8_len, NULL, 0);
}

std::wstring WeaselUserDataPath() {
WCHAR path[MAX_PATH] = {0};
const WCHAR KEY[] = L"Software\\Rime\\Weasel";
Expand Down
7 changes: 7 additions & 0 deletions RimeWithWeasel/stdafx.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,14 @@
#pragma warning(disable : 4819)

#include <boost/interprocess/streams/bufferstream.hpp>
#include <boost/archive/text_woarchive.hpp>
#include <boost/archive/text_oarchive.hpp>

#pragma warning(default : 4819)
#include <algorithm>
#include <list>
#include <set>
#include <string>
#include <sstream>

using boost::interprocess::wbufferstream;
Loading