From 0c839f419a462f01c75baff91f5a443ad449f05b Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Sat, 14 Sep 2013 18:21:10 +0800 Subject: [PATCH 1/9] Move hidden input to the same position with cursor view. This is required to make IME's input bubble follow the cursor. --- src/editor.coffee | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/editor.coffee b/src/editor.coffee index e5ed37af5..15a86f5a4 100644 --- a/src/editor.coffee +++ b/src/editor.coffee @@ -88,6 +88,7 @@ class Editor extends View @configure() @bindKeys() @handleEvents() + @handleImeEvents() @cursorViews = [] @selectionViews = [] @pendingChanges = [] @@ -696,6 +697,10 @@ class Editor extends View else @gutter.addClass('drop-shadow') + handleImeEvents: -> + @on 'cursor:moved', => + @hiddenInput.offset(@getCursorView().offset()) + selectOnMousemoveUntilMouseup: -> lastMoveEvent = null moveHandler = (event = lastMoveEvent) => From c9d4c761bbc2ca17ca4fa69c1d2e20917f14f6ff Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Sat, 14 Sep 2013 19:51:15 +0800 Subject: [PATCH 2/9] Show IME's composition text on screen. The composition text should only show on screen temporarily and gets disappered when input is cancelled or done. We simply mark the composition as selected, so it can not only indicate this is composition text instead of normal text, but also updates the composition without adding new interfaces. --- src/editor.coffee | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/editor.coffee b/src/editor.coffee index 15a86f5a4..b14ae350b 100644 --- a/src/editor.coffee +++ b/src/editor.coffee @@ -699,7 +699,18 @@ class Editor extends View handleImeEvents: -> @on 'cursor:moved', => - @hiddenInput.offset(@getCursorView().offset()) + cursorView = @getCursorView() + @hiddenInput.offset(cursorView.offset()) if cursorView.is(':visible') + + startScreenPosition = null + @hiddenInput.on 'compositionstart', => + startScreenPosition = @getCursorScreenPosition() + @hiddenInput.on 'compositionupdate', (e) => + @insertText(e.originalEvent.data) + @selectToScreenPosition(startScreenPosition) + @hiddenInput.on 'compositionend', => + @delete() + startScreenPosition = null selectOnMousemoveUntilMouseup: -> lastMoveEvent = null From a92a65929aa9b165cccc869df6d54380253129eb Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Sat, 14 Sep 2013 20:10:36 +0800 Subject: [PATCH 3/9] Make hiddentInput bigger when inputing with IME. Some IME's input bubble would have strange behavior when they thought the target input box is small. --- src/editor.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/editor.coffee b/src/editor.coffee index b14ae350b..8ba98fa7e 100644 --- a/src/editor.coffee +++ b/src/editor.coffee @@ -705,11 +705,13 @@ class Editor extends View startScreenPosition = null @hiddenInput.on 'compositionstart', => startScreenPosition = @getCursorScreenPosition() + @hiddenInput.css('width', '100%') @hiddenInput.on 'compositionupdate', (e) => @insertText(e.originalEvent.data) @selectToScreenPosition(startScreenPosition) @hiddenInput.on 'compositionend', => @delete() + @hiddenInput.css('width', '1px') startScreenPosition = null selectOnMousemoveUntilMouseup: -> From dee9cce2e31cdbe93f2ad3093800c0b715f6fec2 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Sat, 14 Sep 2013 20:20:45 +0800 Subject: [PATCH 4/9] Select the text while inserting. --- src/editor.coffee | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/editor.coffee b/src/editor.coffee index 8ba98fa7e..6aba170a8 100644 --- a/src/editor.coffee +++ b/src/editor.coffee @@ -702,17 +702,13 @@ class Editor extends View cursorView = @getCursorView() @hiddenInput.offset(cursorView.offset()) if cursorView.is(':visible') - startScreenPosition = null @hiddenInput.on 'compositionstart', => - startScreenPosition = @getCursorScreenPosition() @hiddenInput.css('width', '100%') @hiddenInput.on 'compositionupdate', (e) => - @insertText(e.originalEvent.data) - @selectToScreenPosition(startScreenPosition) + @insertText(e.originalEvent.data, select: true) @hiddenInput.on 'compositionend', => @delete() @hiddenInput.css('width', '1px') - startScreenPosition = null selectOnMousemoveUntilMouseup: -> lastMoveEvent = null From f4e3f7a0555de438bcd69eec6969caa8a22b65ee Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 16 Sep 2013 10:43:34 +0800 Subject: [PATCH 5/9] Skip the undo stack when changing composition text. --- src/editor.coffee | 4 ++-- src/selection.coffee | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/editor.coffee b/src/editor.coffee index 6aba170a8..486053625 100644 --- a/src/editor.coffee +++ b/src/editor.coffee @@ -705,9 +705,9 @@ class Editor extends View @hiddenInput.on 'compositionstart', => @hiddenInput.css('width', '100%') @hiddenInput.on 'compositionupdate', (e) => - @insertText(e.originalEvent.data, select: true) + @insertText(e.originalEvent.data, {select: true, skipUndo: true}) @hiddenInput.on 'compositionend', => - @delete() + @insertText('', skipUndo: true) @hiddenInput.css('width', '1px') selectOnMousemoveUntilMouseup: -> diff --git a/src/selection.coffee b/src/selection.coffee index 0284176b3..0192e2e7b 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -296,6 +296,8 @@ class Selection # + autoDecreaseIndent: # if `true`, decreases indent level appropriately (for example, when a # closing bracket is inserted) + # + skipUndo: + # if `true`, skips the undo stack for this operation. insertText: (text, options={}) -> oldBufferRange = @getBufferRange() @editSession.destroyFoldsContainingBufferRow(oldBufferRange.end.row) @@ -306,7 +308,7 @@ class Selection if options.indentBasis? and not options.autoIndent text = @normalizeIndents(text, options.indentBasis) - newBufferRange = @editSession.buffer.change(oldBufferRange, text) + newBufferRange = @editSession.buffer.change(oldBufferRange, text, skipUndo: options.skipUndo) if options.select @setBufferRange(newBufferRange, isReversed: wasReversed) else From 54e25677b60926d9c1935effdf97e52771b8a406 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 16 Sep 2013 10:44:15 +0800 Subject: [PATCH 6/9] Restore previous selected text after IME composition is done. --- src/editor.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/editor.coffee b/src/editor.coffee index 486053625..3c85991a9 100644 --- a/src/editor.coffee +++ b/src/editor.coffee @@ -702,12 +702,14 @@ class Editor extends View cursorView = @getCursorView() @hiddenInput.offset(cursorView.offset()) if cursorView.is(':visible') + selectedText = null @hiddenInput.on 'compositionstart', => + selectedText = @getSelectedText() @hiddenInput.css('width', '100%') @hiddenInput.on 'compositionupdate', (e) => @insertText(e.originalEvent.data, {select: true, skipUndo: true}) @hiddenInput.on 'compositionend', => - @insertText('', skipUndo: true) + @insertText(selectedText, {select: true, skipUndo: true}) @hiddenInput.css('width', '1px') selectOnMousemoveUntilMouseup: -> From 666d202eb67410b73473d82fe6a3b4d705e05979 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 16 Sep 2013 11:03:40 +0800 Subject: [PATCH 7/9] Add spec for syncing cursorView and hiddenInput's position. --- spec/editor-spec.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/editor-spec.coffee b/spec/editor-spec.coffee index 9d3895a52..ed617f9f0 100644 --- a/spec/editor-spec.coffee +++ b/spec/editor-spec.coffee @@ -884,6 +884,10 @@ describe "Editor", -> expect(editor.getSelection().isEmpty()).toBeTruthy() expect(cursorView).toBeVisible() + it "moves the hiddenInput to the same position with cursor's view", -> + editor.setCursorScreenPosition(row: 2, column: 2) + expect(editor.getCursorView().offset()).toEqual(editor.hiddenInput.offset()) + describe "when the editor is using a variable-width font", -> beforeEach -> editor.setFontFamily('sans-serif') From 80244a1ae7459a8dc1d9a1101ecd998b20879ec9 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 16 Sep 2013 15:38:18 +0800 Subject: [PATCH 8/9] Work around of the accented character suggestion feature in OS X. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On OS X, press and hold `c` could show an accent menu to replace `c` with accented ones like `ć`, there is no corresponding events in W3C, so we detected it by checking whether the text in input box are selected (this is how Chrome implemented this feature). And also note that IME inputs were handled the same way in Chrome, the compostion text would be marked as selected and got replaced with final inputs. However the compostion text won't trigger textInput event, so it's distinguished by checking whether the hiddenInput's value are changed by Chrome. Fixes atom/atom-shell#50. --- src/editor.coffee | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/editor.coffee b/src/editor.coffee index 3c85991a9..ce36240de 100644 --- a/src/editor.coffee +++ b/src/editor.coffee @@ -88,7 +88,7 @@ class Editor extends View @configure() @bindKeys() @handleEvents() - @handleImeEvents() + @handleInputEvents() @cursorViews = [] @selectionViews = [] @pendingChanges = [] @@ -678,10 +678,6 @@ class Editor extends View @selectOnMousemoveUntilMouseup() unless e.ctrlKey or e.originalEvent.which > 1 - @on "textInput", (e) => - @insertText(e.originalEvent.data) - false - unless @mini @scrollView.on 'mousewheel', (e) => if delta = e.originalEvent.wheelDeltaY @@ -697,7 +693,7 @@ class Editor extends View else @gutter.addClass('drop-shadow') - handleImeEvents: -> + handleInputEvents: -> @on 'cursor:moved', => cursorView = @getCursorView() @hiddenInput.offset(cursorView.offset()) if cursorView.is(':visible') @@ -712,6 +708,20 @@ class Editor extends View @insertText(selectedText, {select: true, skipUndo: true}) @hiddenInput.css('width', '1px') + lastInput = '' + @on "textInput", (e) => + # Work around of the accented character suggestion feature in OS X. + selectedLength = @hiddenInput[0].selectionEnd - @hiddenInput[0].selectionStart + if selectedLength is 1 and lastInput is @hiddenInput.val() + position = @getCursorScreenPosition() + position.column -= 1 + @selectToScreenPosition(position) + + lastInput = e.originalEvent.data + @insertText(lastInput) + @hiddenInput.val(lastInput) + false + selectOnMousemoveUntilMouseup: -> lastMoveEvent = null moveHandler = (event = lastMoveEvent) => From 486de96751ed7940e276566fd9e235b446135495 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 16 Sep 2013 18:05:44 +0800 Subject: [PATCH 9/9] Make accented character suggestion work for multiple cursors. --- src/editor.coffee | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/editor.coffee b/src/editor.coffee index ce36240de..8a8fb4091 100644 --- a/src/editor.coffee +++ b/src/editor.coffee @@ -713,9 +713,7 @@ class Editor extends View # Work around of the accented character suggestion feature in OS X. selectedLength = @hiddenInput[0].selectionEnd - @hiddenInput[0].selectionStart if selectedLength is 1 and lastInput is @hiddenInput.val() - position = @getCursorScreenPosition() - position.column -= 1 - @selectToScreenPosition(position) + @selectLeft() lastInput = e.originalEvent.data @insertText(lastInput)