kit/ChildSession.cpp | 12 ++- loleaflet/src/control/Control.LokDialog.js | 93 +++++++++++++++++++++++------ loleaflet/src/layer/tile/TileLayer.js | 5 + loleaflet/src/map/handler/Map.Keyboard.js | 33 +++++----- 4 files changed, 107 insertions(+), 36 deletions(-)
New commits: commit 199b582e06a3234a1803553bf5be88c4d462ffc6 Author: Pranav Kant <[email protected]> Date: Wed Feb 14 18:11:31 2018 +0530 Use real input element for user input instead of canvas This allows moving the IME candidate window according to where the cursor in the lok dialog is. Change-Id: Icf17f1fc1d3f6af619c8e0037c32109d2b4721fc diff --git a/loleaflet/src/control/Control.LokDialog.js b/loleaflet/src/control/Control.LokDialog.js index e6c92e77..20fe4b74 100644 --- a/loleaflet/src/control/Control.LokDialog.js +++ b/loleaflet/src/control/Control.LokDialog.js @@ -2,7 +2,7 @@ * L.Control.LokDialog used for displaying LOK dialogs */ -/* global $ map */ +/* global $ map L */ L.Control.LokDialog = L.Control.extend({ dialogIdPrefix: 'lokdialog-', @@ -145,12 +145,7 @@ L.Control.LokDialog = L.Control.extend({ var y = parseInt(rectangle[1]); height = parseInt(rectangle[3]); - var dialogCursor = L.DomUtil.get(strDlgId + '-cursor'); - L.DomUtil.setStyle(dialogCursor, 'height', height + 'px'); - L.DomUtil.setStyle(dialogCursor, 'display', this._dialogs[e.id].cursorVisible ? 'block' : 'none'); - // set the position of the cursor container element - L.DomUtil.setStyle(this._dialogs[e.id].cursor, 'left', x + 'px'); - L.DomUtil.setStyle(this._dialogs[e.id].cursor, 'top', y + 'px'); + this._updateDialogCursor(e.id, x, y, height); } } else if (e.action === 'title_changed') { if (e.title && this._dialogs[parseInt(e.id)]) { @@ -176,7 +171,20 @@ L.Control.LokDialog = L.Control.extend({ this._map.sendUnoCommand(e.uno); }, - _launchDialogCursor: function(dialogId) { + _updateDialogCursor: function(dlgId, x, y, height) { + var strDlgId = this._toDlgPrefix(dlgId); + var dialogCursor = L.DomUtil.get(strDlgId + '-cursor'); + L.DomUtil.setStyle(dialogCursor, 'height', height + 'px'); + L.DomUtil.setStyle(dialogCursor, 'display', this._dialogs[dlgId].cursorVisible ? 'block' : 'none'); + // set the position of the cursor container element + L.DomUtil.setStyle(this._dialogs[dlgId].cursor, 'left', x + 'px'); + L.DomUtil.setStyle(this._dialogs[dlgId].cursor, 'top', y + 'px'); + + // update the input as well + this._updateDialogInput(dlgId); + }, + + _createDialogCursor: function(dialogId) { var id = this._toRawDlgId(dialogId); this._dialogs[id].cursor = L.DomUtil.create('div', 'leaflet-cursor-container', L.DomUtil.get(dialogId)); var cursor = L.DomUtil.create('div', 'leaflet-cursor lokdialog-cursor', this._dialogs[id].cursor); @@ -184,6 +192,39 @@ L.Control.LokDialog = L.Control.extend({ L.DomUtil.addClass(cursor, 'blinking-cursor'); }, + _createDialogInput: function(dialogId) { + var id = this._toRawDlgId(dialogId); + var clipDlgContainer = L.DomUtil.create('div', 'clipboard-container', L.DomUtil.get(dialogId)); + clipDlgContainer.id = dialogId + '-clipboard-container'; + var dlgTextArea = L.DomUtil.create('input', 'clipboard', clipDlgContainer); + dlgTextArea.setAttribute('type', 'text'); + dlgTextArea.setAttribute('autocorrect', 'off'); + dlgTextArea.setAttribute('autocapitalize', 'off'); + dlgTextArea.setAttribute('autocomplete', 'off'); + dlgTextArea.setAttribute('spellcheck', 'false'); + this._dialogs[id].input = dlgTextArea; + + return dlgTextArea; + }, + + _updateDialogInput: function(dlgId) { + if (!this._dialogs[dlgId].input) + return; + + var strDlgId = this._toDlgPrefix(dlgId); + var left = parseInt(L.DomUtil.getStyle(this._dialogs[dlgId].cursor, 'left')); + var top = parseInt(L.DomUtil.getStyle(this._dialogs[dlgId].cursor, 'top')); + var dlgContainer = L.DomUtil.get(strDlgId + '-clipboard-container'); + L.DomUtil.setPosition(dlgContainer, new L.Point(left, top)); + }, + + focus: function(dlgId) { + if (!this._isOpen(dlgId) || !this._dialogs[dlgId].input) + return; + + this._dialogs[dlgId].input.focus(); + }, + _launchDialog: function(strDlgId, width, height, title) { var dialogContainer = L.DomUtil.create('div', 'lokdialog', document.body); L.DomUtil.setStyle(dialogContainer, 'padding', '0px'); @@ -194,8 +235,6 @@ L.Control.LokDialog = L.Control.extend({ var dialogCanvas = L.DomUtil.create('canvas', 'lokdialog_canvas', dialogContainer); dialogCanvas.width = width; dialogCanvas.height = height; - dialogCanvas.tabIndex = '0'; - dialogCanvas.contentEditable = true; dialogCanvas.id = strDlgId + '-canvas'; L.DomEvent.on(dialogCanvas, 'contextmenu', L.DomEvent.preventDefault); @@ -225,31 +264,38 @@ L.Control.LokDialog = L.Control.extend({ // don't make 'TAB' focus on this button; we want to cycle focus in the lok dialog with each TAB $('.lokdialog_container button.ui-dialog-titlebar-close').attr('tabindex', '-1').blur(); + this._createDialogCursor(strDlgId); + var dlgInput = this._createDialogInput(strDlgId); + L.DomEvent.on(dialogCanvas, 'mousedown mouseup', function(e) { var buttons = 0; buttons |= e.button === map['mouse'].JSButtons.left ? map['mouse'].LOButtons.left : 0; buttons |= e.button === map['mouse'].JSButtons.middle ? map['mouse'].LOButtons.middle : 0; buttons |= e.button === map['mouse'].JSButtons.right ? map['mouse'].LOButtons.right : 0; + // 'mousedown' -> 'buttondown' var lokEventType = e.type.replace('mouse', 'button'); this._postWindowMouseEvent(lokEventType, this._toRawDlgId(strDlgId), e.offsetX, e.offsetY, 1, buttons, 0); + dlgInput.focus(); }, this); - L.DomEvent.on(dialogCanvas, - 'keyup keypress keydown compositionstart compositionupdate compositionend', + L.DomEvent.on(dlgInput, + 'keyup keypress keydown compositionstart compositionupdate compositionend textInput', function(e) { e.originalEvent = e; // _onKeyDown fn below requires real event in e.originalEvent - var fn = this._postWindowKeyboardEvent; - if (e.type.startsWith('composition')) { - fn = this._postWindowCompositionEvent; - } - map['keyboard']._onKeyDown(e, L.bind(fn, - this, - this._toRawDlgId(strDlgId))); + map['keyboard']._onKeyDown(e, + L.bind(this._postWindowKeyboardEvent, + this, + this._toRawDlgId(strDlgId)), + L.bind(this._postWindowCompositionEvent, + this, + this._toRawDlgId(strDlgId)), + dlgInput); + + // keep map active while user is playing with dialog + this._map.lastActiveTime = Date.now(); }, this); - L.DomEvent.on(dialogCanvas, 'contextmenu', function() { + L.DomEvent.on(dlgInput, 'contextmenu', function() { return false; }); - - this._launchDialogCursor(strDlgId); }, _postWindowCompositionEvent: function(winid, type, text) { @@ -283,6 +329,7 @@ L.Control.LokDialog = L.Control.extend({ var img = new Image(); var canvas = document.getElementById(strDlgId + '-canvas'); var ctx = canvas.getContext('2d'); + var that = this; img.onload = function() { var x = 0; var y = 0; @@ -297,6 +344,7 @@ L.Control.LokDialog = L.Control.extend({ // if dialog is hidden, show it var dialogContainer = L.DomUtil.get(strDlgId); $(dialogContainer).parent().show(); + that.focus(dialogId); }; img.src = imgData; }, diff --git a/loleaflet/src/map/handler/Map.Keyboard.js b/loleaflet/src/map/handler/Map.Keyboard.js index 7080751d..5f63b447 100644 --- a/loleaflet/src/map/handler/Map.Keyboard.js +++ b/loleaflet/src/map/handler/Map.Keyboard.js @@ -239,7 +239,7 @@ L.Map.Keyboard = L.Handler.extend({ return this.keymap[keyCode] || keyCode; }, - _onKeyDown: function (e, keyEventFn, compEventFn) { + _onKeyDown: function (e, keyEventFn, compEventFn, inputEle) { if (this._map.slideShow && this._map.slideShow.fullscreen) { return; } @@ -252,6 +252,9 @@ L.Map.Keyboard = L.Handler.extend({ // document has winid=0 compEventFn = L.bind(docLayer._postCompositionEvent, docLayer, 0 /* winid */); } + if (!inputEle) { + inputEle = this._map._textArea; + } this.modifier = 0; var shift = e.originalEvent.shiftKey ? this.keyModifier.shift : 0; var ctrl = e.originalEvent.ctrlKey ? this.keyModifier.ctrl : 0; @@ -310,13 +313,13 @@ L.Map.Keyboard = L.Handler.extend({ // get the composited char codes // clear the input now - best to do this ASAP so the input // is clear for the next word - this._map._textArea.value = ''; + inputEle.value = ''; } if (!this._isComposing && e.type === 'keyup') { // not compositing and keyup, clear the input so it is ready // for next word (or char only) - this._map._textArea.value = ''; + inputEle.value = ''; } var unoKeyCode = this._toUNOKeyCode(keyCode); commit 6d4f02ac2aff539132e66bce237ed4b6c20cc43f Author: Pranav Kant <[email protected]> Date: Tue Feb 13 23:05:54 2018 +0530 Adapt to IME API changes; better reuse of Map's key handler Change-Id: I670243ea155ac698c694531d3fc16a574f418bf4 diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp index c002e5e3..ef9bfd3d 100644 --- a/kit/ChildSession.cpp +++ b/kit/ChildSession.cpp @@ -771,13 +771,15 @@ bool ChildSession::insertFile(const char* /*buffer*/, int /*length*/, const std: bool ChildSession::extTextInputEvent(const char* /*buffer*/, int /*length*/, const std::vector<std::string>& tokens) { - int type; + int id, type; std::string text; - if (tokens.size() < 3 || - !getTokenKeyword(tokens[1], "type", + if (tokens.size() < 4 || + !getTokenInteger(tokens[1], "id", id) || id < 0 || + !getTokenKeyword(tokens[2], "type", {{"input", LOK_EXT_TEXTINPUT}, {"end", LOK_EXT_TEXTINPUT_END}}, type) || - !getTokenString(tokens[2], "text", text)) + !getTokenString(tokens[3], "text", text)) + { sendTextFrame("error: cmd=" + std::string(tokens[0]) + " kind=syntax"); return false; @@ -785,7 +787,7 @@ bool ChildSession::extTextInputEvent(const char* /*buffer*/, int /*length*/, std::unique_lock<std::mutex> lock(_docManager.getDocumentMutex()); getLOKitDocument()->setView(_viewId); - getLOKitDocument()->postExtTextInputEvent(type, text.c_str()); + getLOKitDocument()->postExtTextInputEvent(id, type, text.c_str()); return true; } diff --git a/loleaflet/src/control/Control.LokDialog.js b/loleaflet/src/control/Control.LokDialog.js index 7086fcac..e6c92e77 100644 --- a/loleaflet/src/control/Control.LokDialog.js +++ b/loleaflet/src/control/Control.LokDialog.js @@ -233,11 +233,18 @@ L.Control.LokDialog = L.Control.extend({ var lokEventType = e.type.replace('mouse', 'button'); this._postWindowMouseEvent(lokEventType, this._toRawDlgId(strDlgId), e.offsetX, e.offsetY, 1, buttons, 0); }, this); - L.DomEvent.on(dialogCanvas, 'keyup keypress keydown', function(e) { - // _onKeyDown fn below requires this kind of structure but leaflet DomEvent.on doesn't pass it - e.originalEvent = e; - map['keyboard']._onKeyDown(e, L.bind(this._postWindowKeyboardEvent, this, this._toRawDlgId(strDlgId))); - }, this); + L.DomEvent.on(dialogCanvas, + 'keyup keypress keydown compositionstart compositionupdate compositionend', + function(e) { + e.originalEvent = e; // _onKeyDown fn below requires real event in e.originalEvent + var fn = this._postWindowKeyboardEvent; + if (e.type.startsWith('composition')) { + fn = this._postWindowCompositionEvent; + } + map['keyboard']._onKeyDown(e, L.bind(fn, + this, + this._toRawDlgId(strDlgId))); + }, this); L.DomEvent.on(dialogCanvas, 'contextmenu', function() { return false; }); @@ -245,6 +252,10 @@ L.Control.LokDialog = L.Control.extend({ this._launchDialogCursor(strDlgId); }, + _postWindowCompositionEvent: function(winid, type, text) { + this._map._docLayer._postCompositionEvent(winid, type, text); + }, + _postWindowMouseEvent: function(type, winid, x, y, count, buttons, modifier) { this._map._socket.sendMessage('windowmouse id=' + winid + ' type=' + type + ' x=' + x + ' y=' + y + ' count=' + count + diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js index aebeaf79..93ac3cd7 100644 --- a/loleaflet/src/layer/tile/TileLayer.js +++ b/loleaflet/src/layer/tile/TileLayer.js @@ -1468,6 +1468,11 @@ L.TileLayer = L.GridLayer.extend({ ' char=' + charcode + ' key=' + keycode); }, + // if winId=0, then event is posted on the document + _postCompositionEvent: function(winId, type, text) { + this._map._socket.sendMessage('textinput id=' + winId + ' type=' + type + ' text=' + text); + }, + _postSelectGraphicEvent: function(type, x, y) { this._map._socket.sendMessage('selectgraphic type=' + type + ' x=' + x + ' y=' + y); diff --git a/loleaflet/src/map/handler/Map.Keyboard.js b/loleaflet/src/map/handler/Map.Keyboard.js index 39103dd3..7080751d 100644 --- a/loleaflet/src/map/handler/Map.Keyboard.js +++ b/loleaflet/src/map/handler/Map.Keyboard.js @@ -239,16 +239,18 @@ L.Map.Keyboard = L.Handler.extend({ return this.keymap[keyCode] || keyCode; }, - _onKeyDown: function (e, postEventFn) { + _onKeyDown: function (e, keyEventFn, compEventFn) { if (this._map.slideShow && this._map.slideShow.fullscreen) { return; } var docLayer = this._map._docLayer; - var eventObject; - if (!postEventFn) { + if (!keyEventFn) { // default is to post keyboard events on the document - postEventFn = docLayer._postKeyboardEvent; - eventObject = docLayer; + keyEventFn = L.bind(docLayer._postKeyboardEvent, docLayer); + } + if (!compEventFn) { + // document has winid=0 + compEventFn = L.bind(docLayer._postCompositionEvent, docLayer, 0 /* winid */); } this.modifier = 0; var shift = e.originalEvent.shiftKey ? this.keyModifier.shift : 0; @@ -299,7 +301,7 @@ L.Map.Keyboard = L.Handler.extend({ txt += e.originalEvent.data[i]; } if (txt) { - this._map._socket.sendMessage('textinput type=input text=' + txt); + compEventFn('input', txt); } } @@ -322,7 +324,7 @@ L.Map.Keyboard = L.Handler.extend({ if (this.modifier) { unoKeyCode |= this.modifier; if (e.type !== 'keyup' && (this.modifier !== shift || (keyCode === 32 && !docLayer._isCursorVisible))) { - postEventFn.call(eventObject, 'input', charCode, unoKeyCode); + keyEventFn('input', charCode, unoKeyCode); e.originalEvent.preventDefault(); return; } @@ -336,7 +338,7 @@ L.Map.Keyboard = L.Handler.extend({ this._bufferedTextInputEvent = null; if (this._handleOnKeyDown(keyCode, this.modifier) && charCode === 0) { - postEventFn.call(eventObject, 'input', charCode, unoKeyCode); + keyEventFn('input', charCode, unoKeyCode); } } else if ((e.type === 'keypress' || e.type === 'compositionend') && @@ -353,9 +355,9 @@ L.Map.Keyboard = L.Handler.extend({ } if (e.type === 'compositionend') { // Set all keycodes to zero - this._map._socket.sendMessage('textinput type=end text=void'); + compEventFn('end', ''); } else { - postEventFn.call(eventObject, 'input', charCode, unoKeyCode); + keyEventFn('input', charCode, unoKeyCode); } this._keyHandled = true; @@ -388,7 +390,7 @@ L.Map.Keyboard = L.Handler.extend({ keyEventFn('input', textInputData[idx].charCodeAt(), 0); } } - postEventFn.call(eventObject, 'up', charCode, unoKeyCode); + keyEventFn('up', charCode, unoKeyCode); this._keyHandled = true; this._bufferedTextInputEvent = null; @@ -414,7 +416,7 @@ L.Map.Keyboard = L.Handler.extend({ else if (key in this._panKeys && e.originalEvent.shiftKey && docLayer._selections.getLayers().length !== 0) { // if there is a selection and the user wants to modify it - postEventFn.call(eventObject, 'input', charCode, unoKeyCode); + keyEventFn('input', charCode, unoKeyCode); } else if (key in this._zoomKeys) { map.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]); _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
