IME support

Dialogs still need to be adapted to this. Only works for documents as of
now.

Change-Id: I0fb1114e279a9e563943f3f65dd5a577523e9841
This commit is contained in:
Pranav Kant 2018-02-08 00:00:45 +05:30
parent 1fabfd9fe3
commit ad1da235d3
9 changed files with 102 additions and 11 deletions

View file

@ -300,6 +300,11 @@ struct _LibreOfficeKitDocumentClass
/// @see lok::Document::setViewLanguage().
void (*setViewLanguage) (LibreOfficeKitDocument* pThis, int nId, const char* language);
/// @see lok::Document::postExtTextInputEvent
void (*postExtTextInputEvent) (LibreOfficeKitDocument* pThis,
int nType,
const char* pText);
#endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
};

View file

@ -537,6 +537,17 @@ public:
mpDoc->pClass->setViewLanguage(mpDoc, nId, language);
}
/**
* Post the text input from external input window, like IME
*
* @param nType see LibreOfficeKitExtTextInputType
* @param pText Text for LOK_EXT_TEXTINPUT
*/
void postExtTextInputEvent(int nType, const char* pText)
{
mpDoc->pClass->postExtTextInputEvent(mpDoc, nType, pText);
}
#endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
};

View file

@ -267,6 +267,11 @@ typedef enum
/**
* The size and/or the position of the cell cursor changed.
*
* Payload format: "x, y, width, height, column, row", where the first
* 4 numbers are document coordinates, in twips, and the last 2 are table
* coordinates starting from 0.
* When the cursor is not shown the payload format is the "EMPTY" string.
*
* Rectangle format is the same as LOK_CALLBACK_INVALIDATE_TILES.
*/
LOK_CALLBACK_CELL_CURSOR = 17,
@ -509,11 +514,12 @@ typedef enum
* The column/row header is no more valid because of a column/row insertion
* or a similar event. Clients must query a new column/row header set.
*
* The payload says if we are invalidating a row or column header.
* The payload says if we are invalidating a row or column header. So,
* payload values can be: "row", "column", "all".
*/
LOK_CALLBACK_INVALIDATE_HEADER = 33,
/**
* The text content of the address field in Calc.
* The text content of the address field in Calc. Eg: "A7"
*/
LOK_CALLBACK_CELL_ADDRESS = 34,
/**
@ -534,7 +540,32 @@ typedef enum
*/
LOK_CALLBACK_RULER_UPDATE = 35,
/**
* Dialog invalidation
* Window related callbacks are emitted under this category. It includes
* external windows like dialogs, autopopups for now.
*
* The payload format is:
*
* {
* "id": "unique integer id of the dialog",
* "action": "<see below>",
* "type": "<see below>"
* "rectangle": "x, y, width, height"
* }
*
* "type" tells the type of the window the action is associated with
* - "dialog" - window is a dialog
* - "child" - window is a floating window (combo boxes, etc.)
*
* "action" can take following values:
* - "created" - window is created in the backend, client can render it now
* - "title_changed" - window's title is changed
* - "size_changed" - window's size is changed
* - "invalidate" - the area as described by "rectangle" is invalidated
* Clients must request the new area
* - "cursor_invalidate" - cursor is invalidated. New position is in "rectangle"
* - "cursor_visible" - cursor visible status is changed. Status is availabe
* in "visible" field
* - "close" - window is closed
*/
LOK_CALLBACK_WINDOW = 36,
}
@ -549,6 +580,17 @@ typedef enum
}
LibreOfficeKitKeyEventType;
typedef enum
{
/// cf. SalEvent::ExtTextInput
LOK_EXT_TEXTINPUT,
/// cf. SalEvent::ExtTextInputPos
LOK_EXT_TEXTINPUT_POS,
/// cf. SalEvent::EndExtTextInput
LOK_EXT_TEXTINPUT_END
}
LibreOfficeKitExtTextInputType;
typedef enum
{
/// A pressed gesture has started.

View file

@ -134,7 +134,7 @@ namespace LOOLProtocol
bool getTokenString(const std::string& token, const std::string& name, std::string& value)
{
if (token.size() > (name.size() + 1) &&
if (token.size() >= (name.size() + 1) &&
token.compare(0, name.size(), name) == 0 &&
token[name.size()] == '=')
{

View file

@ -227,6 +227,7 @@ bool ChildSession::_handleInput(const char *buffer, int length)
tokens[0] == "paste" ||
tokens[0] == "insertfile" ||
tokens[0] == "key" ||
tokens[0] == "textinput" ||
tokens[0] == "windowkey" ||
tokens[0] == "mouse" ||
tokens[0] == "windowmouse" ||
@ -275,6 +276,10 @@ bool ChildSession::_handleInput(const char *buffer, int length)
{
return keyEvent(buffer, length, tokens, LokEventTargetEnum::Document);
}
else if (tokens[0] == "textinput")
{
return extTextInputEvent(buffer, length, tokens);
}
else if (tokens[0] == "windowkey")
{
return keyEvent(buffer, length, tokens, LokEventTargetEnum::Window);
@ -763,6 +768,28 @@ bool ChildSession::insertFile(const char* /*buffer*/, int /*length*/, const std:
return true;
}
bool ChildSession::extTextInputEvent(const char* /*buffer*/, int /*length*/,
const std::vector<std::string>& tokens)
{
int type;
std::string text;
if (tokens.size() < 3 ||
!getTokenKeyword(tokens[1], "type",
{{"input", LOK_EXT_TEXTINPUT}, {"end", LOK_EXT_TEXTINPUT_END}},
type) ||
!getTokenString(tokens[2], "text", text))
{
sendTextFrame("error: cmd=" + std::string(tokens[0]) + " kind=syntax");
return false;
}
std::unique_lock<std::mutex> lock(_docManager.getDocumentMutex());
getLOKitDocument()->setView(_viewId);
getLOKitDocument()->postExtTextInputEvent(type, text.c_str());
return true;
}
bool ChildSession::keyEvent(const char* /*buffer*/, int /*length*/,
const std::vector<std::string>& tokens,
const LokEventTargetEnum target)

View file

@ -188,6 +188,7 @@ private:
bool paste(const char* buffer, int length, const std::vector<std::string>& tokens);
bool insertFile(const char* buffer, int length, const std::vector<std::string>& tokens);
bool keyEvent(const char* buffer, int length, const std::vector<std::string>& tokens, const LokEventTargetEnum target);
bool extTextInputEvent(const char* /*buffer*/, int /*length*/, const std::vector<std::string>& tokens);
bool dialogKeyEvent(const char* buffer, int length, const std::vector<std::string>& tokens);
bool mouseEvent(const char* buffer, int length, const std::vector<std::string>& tokens, const LokEventTargetEnum target);
bool unoCommand(const char* buffer, int length, const std::vector<std::string>& tokens);

View file

@ -294,15 +294,18 @@ L.Map.Keyboard = L.Handler.extend({
if (e.type === 'compositionstart' || e.type === 'compositionupdate') {
this._isComposing = true; // we are starting composing with IME
var txt = '';
for (var i = 0; i < e.originalEvent.data.length; i++) {
txt += e.originalEvent.data[i];
}
if (txt) {
this._map._socket.sendMessage('textinput type=input text=' + txt);
}
}
if (e.type === 'compositionend') {
this._isComposing = false; // stop of composing with IME
// get the composited char codes
var compCharCodes = [];
for (var i = 0; i < e.originalEvent.data.length; i++) {
compCharCodes.push(e.originalEvent.data[i].charCodeAt());
}
// clear the input now - best to do this ASAP so the input
// is clear for the next word
this._map._textArea.value = '';
@ -350,9 +353,7 @@ L.Map.Keyboard = L.Handler.extend({
}
if (e.type === 'compositionend') {
// Set all keycodes to zero
for (var idx = 0; i < compCharCodes.length; ++i) {
postEventFn.call(eventObject, 'input', compCharCodes[idx], 0);
}
this._map._socket.sendMessage('textinput type=end text=void');
} else {
postEventFn.call(eventObject, 'input', charCode, unoKeyCode);
}

View file

@ -58,6 +58,9 @@ void WhiteBoxTests::testLOOLProtocolFunctions()
CPPUNIT_ASSERT(LOOLProtocol::getTokenString("bar=hello-sailor", "bar", bar));
CPPUNIT_ASSERT_EQUAL(std::string("hello-sailor"), bar);
CPPUNIT_ASSERT(LOOLProtocol::getTokenString("bar=", "bar", bar));
CPPUNIT_ASSERT_EQUAL(std::string(""), bar);
int mumble;
std::map<std::string, int> map { { "hello", 1 }, { "goodbye", 2 }, { "adieu", 3 } };

View file

@ -136,6 +136,7 @@ bool ClientSession::_handleInput(const char *buffer, int length)
tokens[0] != "paste" &&
tokens[0] != "insertfile" &&
tokens[0] != "key" &&
tokens[0] != "textinput" &&
tokens[0] != "windowkey" &&
tokens[0] != "mouse" &&
tokens[0] != "windowmouse" &&