Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
MrYangLu
vscode
提交
fd052288
V
vscode
项目概览
MrYangLu
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
fd052288
编写于
8月 24, 2016
作者:
A
Alex Dima
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Backport IME related changes (Microsoft/monaco-editor#104)
上级
8302cd72
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
569 addition
and
226 deletion
+569
-226
src/vs/base/browser/browser.ts
src/vs/base/browser/browser.ts
+2
-0
src/vs/editor/browser/controller/input/textAreaWrapper.ts
src/vs/editor/browser/controller/input/textAreaWrapper.ts
+187
-0
src/vs/editor/browser/controller/keyboardHandler.ts
src/vs/editor/browser/controller/keyboardHandler.ts
+58
-183
src/vs/editor/browser/editorBrowser.ts
src/vs/editor/browser/editorBrowser.ts
+1
-0
src/vs/editor/browser/view/viewImpl.ts
src/vs/editor/browser/view/viewImpl.ts
+3
-0
src/vs/editor/common/controller/textAreaHandler.ts
src/vs/editor/common/controller/textAreaHandler.ts
+37
-35
src/vs/editor/common/controller/textAreaState.ts
src/vs/editor/common/controller/textAreaState.ts
+37
-3
src/vs/editor/test/browser/controller/imeTester.html
src/vs/editor/test/browser/controller/imeTester.html
+57
-0
src/vs/editor/test/browser/controller/imeTester.ts
src/vs/editor/test/browser/controller/imeTester.ts
+179
-0
src/vs/editor/test/common/mocks/mockTextAreaWrapper.ts
src/vs/editor/test/common/mocks/mockTextAreaWrapper.ts
+8
-5
未找到文件。
src/vs/base/browser/browser.ts
浏览文件 @
fd052288
...
...
@@ -56,6 +56,8 @@ export const isIE9 = (userAgent.indexOf('MSIE 9') >= 0);
export
const
isIE11orEarlier
=
isIE11
||
isIE10
||
isIE9
;
export
const
isIE10orEarlier
=
isIE10
||
isIE9
;
export
const
isIE10orLater
=
isIE11
||
isIE10
;
export
const
isEdge
=
(
userAgent
.
indexOf
(
'
Edge/
'
)
>=
0
);
export
const
isEdgeOrIE
=
isEdge
||
isIE11
||
isIE10
||
isIE9
;
export
const
isOpera
=
(
userAgent
.
indexOf
(
'
Opera
'
)
>=
0
);
export
const
isFirefox
=
(
userAgent
.
indexOf
(
'
Firefox
'
)
>=
0
);
...
...
src/vs/editor/browser/controller/input/textAreaWrapper.ts
0 → 100644
浏览文件 @
fd052288
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
Event
,
{
Emitter
}
from
'
vs/base/common/event
'
;
import
{
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
*
as
browser
from
'
vs/base/browser/browser
'
;
import
*
as
dom
from
'
vs/base/browser/dom
'
;
import
{
IKeyboardEvent
}
from
'
vs/base/browser/keyboardEvent
'
;
import
{
IClipboardEvent
,
ICompositionEvent
,
IKeyboardEventWrapper
,
ITextAreaWrapper
}
from
'
vs/editor/common/controller/textAreaState
'
;
class
ClipboardEventWrapper
implements
IClipboardEvent
{
private
_event
:
ClipboardEvent
;
constructor
(
event
:
ClipboardEvent
)
{
this
.
_event
=
event
;
}
public
canUseTextData
():
boolean
{
if
(
this
.
_event
.
clipboardData
)
{
return
true
;
}
if
((
<
any
>
window
).
clipboardData
)
{
return
true
;
}
return
false
;
}
public
setTextData
(
text
:
string
):
void
{
if
(
this
.
_event
.
clipboardData
)
{
this
.
_event
.
clipboardData
.
setData
(
'
text/plain
'
,
text
);
this
.
_event
.
preventDefault
();
return
;
}
if
((
<
any
>
window
).
clipboardData
)
{
(
<
any
>
window
).
clipboardData
.
setData
(
'
Text
'
,
text
);
this
.
_event
.
preventDefault
();
return
;
}
throw
new
Error
(
'
ClipboardEventWrapper.setTextData: Cannot use text data!
'
);
}
public
getTextData
():
string
{
if
(
this
.
_event
.
clipboardData
)
{
this
.
_event
.
preventDefault
();
return
this
.
_event
.
clipboardData
.
getData
(
'
text/plain
'
);
}
if
((
<
any
>
window
).
clipboardData
)
{
this
.
_event
.
preventDefault
();
return
(
<
any
>
window
).
clipboardData
.
getData
(
'
Text
'
);
}
throw
new
Error
(
'
ClipboardEventWrapper.getTextData: Cannot use text data!
'
);
}
}
class
KeyboardEventWrapper
implements
IKeyboardEventWrapper
{
public
_actual
:
IKeyboardEvent
;
constructor
(
actual
:
IKeyboardEvent
)
{
this
.
_actual
=
actual
;
}
public
equals
(
keybinding
:
number
):
boolean
{
return
this
.
_actual
.
equals
(
keybinding
);
}
public
preventDefault
():
void
{
this
.
_actual
.
preventDefault
();
}
public
isDefaultPrevented
():
boolean
{
if
(
this
.
_actual
.
browserEvent
)
{
return
this
.
_actual
.
browserEvent
.
defaultPrevented
;
}
return
false
;
}
}
export
class
TextAreaWrapper
extends
Disposable
implements
ITextAreaWrapper
{
private
_textArea
:
HTMLTextAreaElement
;
private
_onKeyDown
=
this
.
_register
(
new
Emitter
<
IKeyboardEventWrapper
>
());
public
onKeyDown
:
Event
<
IKeyboardEventWrapper
>
=
this
.
_onKeyDown
.
event
;
private
_onKeyUp
=
this
.
_register
(
new
Emitter
<
IKeyboardEventWrapper
>
());
public
onKeyUp
:
Event
<
IKeyboardEventWrapper
>
=
this
.
_onKeyUp
.
event
;
private
_onKeyPress
=
this
.
_register
(
new
Emitter
<
IKeyboardEventWrapper
>
());
public
onKeyPress
:
Event
<
IKeyboardEventWrapper
>
=
this
.
_onKeyPress
.
event
;
private
_onCompositionStart
=
this
.
_register
(
new
Emitter
<
ICompositionEvent
>
());
public
onCompositionStart
:
Event
<
ICompositionEvent
>
=
this
.
_onCompositionStart
.
event
;
private
_onCompositionUpdate
=
this
.
_register
(
new
Emitter
<
ICompositionEvent
>
());
public
onCompositionUpdate
:
Event
<
ICompositionEvent
>
=
this
.
_onCompositionUpdate
.
event
;
private
_onCompositionEnd
=
this
.
_register
(
new
Emitter
<
ICompositionEvent
>
());
public
onCompositionEnd
:
Event
<
ICompositionEvent
>
=
this
.
_onCompositionEnd
.
event
;
private
_onInput
=
this
.
_register
(
new
Emitter
<
void
>
());
public
onInput
:
Event
<
void
>
=
this
.
_onInput
.
event
;
private
_onCut
=
this
.
_register
(
new
Emitter
<
IClipboardEvent
>
());
public
onCut
:
Event
<
IClipboardEvent
>
=
this
.
_onCut
.
event
;
private
_onCopy
=
this
.
_register
(
new
Emitter
<
IClipboardEvent
>
());
public
onCopy
:
Event
<
IClipboardEvent
>
=
this
.
_onCopy
.
event
;
private
_onPaste
=
this
.
_register
(
new
Emitter
<
IClipboardEvent
>
());
public
onPaste
:
Event
<
IClipboardEvent
>
=
this
.
_onPaste
.
event
;
constructor
(
textArea
:
HTMLTextAreaElement
)
{
super
();
this
.
_textArea
=
textArea
;
this
.
_register
(
dom
.
addStandardDisposableListener
(
this
.
_textArea
,
'
keydown
'
,
(
e
)
=>
this
.
_onKeyDown
.
fire
(
new
KeyboardEventWrapper
(
e
))));
this
.
_register
(
dom
.
addStandardDisposableListener
(
this
.
_textArea
,
'
keyup
'
,
(
e
)
=>
this
.
_onKeyUp
.
fire
(
new
KeyboardEventWrapper
(
e
))));
this
.
_register
(
dom
.
addStandardDisposableListener
(
this
.
_textArea
,
'
keypress
'
,
(
e
)
=>
this
.
_onKeyPress
.
fire
(
new
KeyboardEventWrapper
(
e
))));
this
.
_register
(
dom
.
addDisposableListener
(
this
.
_textArea
,
'
compositionstart
'
,
(
e
)
=>
this
.
_onCompositionStart
.
fire
(
e
)));
this
.
_register
(
dom
.
addDisposableListener
(
this
.
_textArea
,
'
compositionupdate
'
,
(
e
)
=>
this
.
_onCompositionUpdate
.
fire
(
e
)));
this
.
_register
(
dom
.
addDisposableListener
(
this
.
_textArea
,
'
compositionend
'
,
(
e
)
=>
this
.
_onCompositionEnd
.
fire
(
e
)));
this
.
_register
(
dom
.
addDisposableListener
(
this
.
_textArea
,
'
input
'
,
(
e
)
=>
this
.
_onInput
.
fire
()));
this
.
_register
(
dom
.
addDisposableListener
(
this
.
_textArea
,
'
cut
'
,
(
e
:
ClipboardEvent
)
=>
this
.
_onCut
.
fire
(
new
ClipboardEventWrapper
(
e
))));
this
.
_register
(
dom
.
addDisposableListener
(
this
.
_textArea
,
'
copy
'
,
(
e
:
ClipboardEvent
)
=>
this
.
_onCopy
.
fire
(
new
ClipboardEventWrapper
(
e
))));
this
.
_register
(
dom
.
addDisposableListener
(
this
.
_textArea
,
'
paste
'
,
(
e
:
ClipboardEvent
)
=>
this
.
_onPaste
.
fire
(
new
ClipboardEventWrapper
(
e
))));
}
public
get
actual
():
HTMLTextAreaElement
{
return
this
.
_textArea
;
}
public
getValue
():
string
{
// console.log('current value: ' + this._textArea.value);
return
this
.
_textArea
.
value
;
}
public
setValue
(
reason
:
string
,
value
:
string
):
void
{
// console.log('reason: ' + reason + ', current value: ' + this._textArea.value + ' => new value: ' + value);
this
.
_textArea
.
value
=
value
;
}
public
getSelectionStart
():
number
{
return
this
.
_textArea
.
selectionStart
;
}
public
getSelectionEnd
():
number
{
return
this
.
_textArea
.
selectionEnd
;
}
public
setSelectionRange
(
selectionStart
:
number
,
selectionEnd
:
number
):
void
{
let
activeElement
=
document
.
activeElement
;
if
(
activeElement
===
this
.
_textArea
)
{
this
.
_textArea
.
setSelectionRange
(
selectionStart
,
selectionEnd
);
}
else
{
this
.
_setSelectionRangeJumpy
(
selectionStart
,
selectionEnd
);
}
}
private
_setSelectionRangeJumpy
(
selectionStart
:
number
,
selectionEnd
:
number
):
void
{
try
{
let
scrollState
=
dom
.
saveParentsScrollTop
(
this
.
_textArea
);
this
.
_textArea
.
focus
();
this
.
_textArea
.
setSelectionRange
(
selectionStart
,
selectionEnd
);
dom
.
restoreParentsScrollTop
(
this
.
_textArea
,
scrollState
);
}
catch
(
e
)
{
// Sometimes IE throws when setting selection (e.g. textarea is off-DOM)
console
.
log
(
'
an error has been thrown!
'
);
}
}
public
isInOverwriteMode
():
boolean
{
// In IE, pressing Insert will bring the typing into overwrite mode
if
(
browser
.
isIE11orEarlier
&&
document
.
queryCommandValue
(
'
OverWrite
'
))
{
return
true
;
}
return
false
;
}
}
src/vs/editor/browser/controller/keyboardHandler.ts
浏览文件 @
fd052288
...
...
@@ -4,184 +4,38 @@
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
Event
,
{
Emitter
}
from
'
vs/base/common/event
'
;
import
{
Disposable
,
IDisposable
,
disposeAll
}
from
'
vs/base/common/lifecycle
'
;
import
{
IDisposable
,
disposeAll
}
from
'
vs/base/common/lifecycle
'
;
import
*
as
browser
from
'
vs/base/browser/browser
'
;
import
*
as
dom
from
'
vs/base/browser/dom
'
;
import
{
IKeyboardEvent
}
from
'
vs/base/browser/keyboardEvent
'
;
import
{
StyleMutator
}
from
'
vs/base/browser/styleMutator
'
;
import
{
GlobalScreenReaderNVDA
}
from
'
vs/editor/common/config/commonEditorConfig
'
;
import
{
TextAreaHandler
}
from
'
vs/editor/common/controller/textAreaHandler
'
;
import
{
IClipboardEvent
,
IKeyboardEventWrapper
,
ITextAreaWrapper
,
TextAreaStrategy
}
from
'
vs/editor/common/controller/textAreaState
'
;
import
{
TextAreaStrategy
}
from
'
vs/editor/common/controller/textAreaState
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
*
as
editorCommon
from
'
vs/editor/common/editorCommon
'
;
import
{
ViewEventHandler
}
from
'
vs/editor/common/viewModel/viewEventHandler
'
;
import
{
IKeyboardHandlerHelper
,
IViewContext
,
IViewController
}
from
'
vs/editor/browser/editorBrowser
'
;
class
ClipboardEventWrapper
implements
IClipboardEvent
{
private
_event
:
ClipboardEvent
;
constructor
(
event
:
ClipboardEvent
)
{
this
.
_event
=
event
;
}
public
canUseTextData
():
boolean
{
if
(
this
.
_event
.
clipboardData
)
{
return
true
;
}
if
((
<
any
>
window
).
clipboardData
)
{
return
true
;
}
return
false
;
}
public
setTextData
(
text
:
string
):
void
{
if
(
this
.
_event
.
clipboardData
)
{
this
.
_event
.
clipboardData
.
setData
(
'
text/plain
'
,
text
);
this
.
_event
.
preventDefault
();
return
;
}
if
((
<
any
>
window
).
clipboardData
)
{
(
<
any
>
window
).
clipboardData
.
setData
(
'
Text
'
,
text
);
this
.
_event
.
preventDefault
();
return
;
}
throw
new
Error
(
'
ClipboardEventWrapper.setTextData: Cannot use text data!
'
);
}
public
getTextData
():
string
{
if
(
this
.
_event
.
clipboardData
)
{
this
.
_event
.
preventDefault
();
return
this
.
_event
.
clipboardData
.
getData
(
'
text/plain
'
);
}
if
((
<
any
>
window
).
clipboardData
)
{
this
.
_event
.
preventDefault
();
return
(
<
any
>
window
).
clipboardData
.
getData
(
'
Text
'
);
}
throw
new
Error
(
'
ClipboardEventWrapper.getTextData: Cannot use text data!
'
);
import
{
IViewContext
,
IViewController
,
IKeyboardHandlerHelper
}
from
'
vs/editor/browser/editorBrowser
'
;
import
{
TextAreaWrapper
}
from
'
vs/editor/browser/controller/input/textAreaWrapper
'
;
function
applyEditorFontInfo
(
target
:
HTMLElement
,
source
:
editorCommon
.
IConfiguration
):
void
{
let
styling
=
source
.
editor
.
stylingInfo
;
if
(
styling
.
fontFamily
&&
styling
.
fontFamily
.
length
>
0
)
{
target
.
style
.
fontFamily
=
styling
.
fontFamily
;
}
else
{
target
.
style
.
fontFamily
=
''
;
}
if
(
styling
.
fontSize
>
0
)
{
target
.
style
.
fontSize
=
styling
.
fontSize
+
'
px
'
;
}
else
{
target
.
style
.
fontSize
=
''
;
}
if
(
styling
.
lineHeight
>
0
)
{
target
.
style
.
lineHeight
=
styling
.
lineHeight
+
'
px
'
;
}
else
{
target
.
style
.
lineHeight
=
''
;
}
}
class
KeyboardEventWrapper
implements
IKeyboardEventWrapper
{
public
_actual
:
IKeyboardEvent
;
constructor
(
actual
:
IKeyboardEvent
)
{
this
.
_actual
=
actual
;
}
public
equals
(
keybinding
:
number
):
boolean
{
return
this
.
_actual
.
equals
(
keybinding
);
}
public
preventDefault
():
void
{
this
.
_actual
.
preventDefault
();
}
public
isDefaultPrevented
():
boolean
{
if
(
this
.
_actual
.
browserEvent
)
{
return
this
.
_actual
.
browserEvent
.
defaultPrevented
;
}
return
false
;
}
}
class
TextAreaWrapper
extends
Disposable
implements
ITextAreaWrapper
{
private
_textArea
:
HTMLTextAreaElement
;
private
_onKeyDown
=
this
.
_register
(
new
Emitter
<
IKeyboardEventWrapper
>
());
public
onKeyDown
:
Event
<
IKeyboardEventWrapper
>
=
this
.
_onKeyDown
.
event
;
private
_onKeyUp
=
this
.
_register
(
new
Emitter
<
IKeyboardEventWrapper
>
());
public
onKeyUp
:
Event
<
IKeyboardEventWrapper
>
=
this
.
_onKeyUp
.
event
;
private
_onKeyPress
=
this
.
_register
(
new
Emitter
<
IKeyboardEventWrapper
>
());
public
onKeyPress
:
Event
<
IKeyboardEventWrapper
>
=
this
.
_onKeyPress
.
event
;
private
_onCompositionStart
=
this
.
_register
(
new
Emitter
<
void
>
());
public
onCompositionStart
:
Event
<
void
>
=
this
.
_onCompositionStart
.
event
;
private
_onCompositionEnd
=
this
.
_register
(
new
Emitter
<
void
>
());
public
onCompositionEnd
:
Event
<
void
>
=
this
.
_onCompositionEnd
.
event
;
private
_onInput
=
this
.
_register
(
new
Emitter
<
void
>
());
public
onInput
:
Event
<
void
>
=
this
.
_onInput
.
event
;
private
_onCut
=
this
.
_register
(
new
Emitter
<
IClipboardEvent
>
());
public
onCut
:
Event
<
IClipboardEvent
>
=
this
.
_onCut
.
event
;
private
_onCopy
=
this
.
_register
(
new
Emitter
<
IClipboardEvent
>
());
public
onCopy
:
Event
<
IClipboardEvent
>
=
this
.
_onCopy
.
event
;
private
_onPaste
=
this
.
_register
(
new
Emitter
<
IClipboardEvent
>
());
public
onPaste
:
Event
<
IClipboardEvent
>
=
this
.
_onPaste
.
event
;
constructor
(
textArea
:
HTMLTextAreaElement
)
{
super
();
this
.
_textArea
=
textArea
;
this
.
_register
(
dom
.
addStandardDisposableListener
(
this
.
_textArea
,
'
keydown
'
,
(
e
)
=>
this
.
_onKeyDown
.
fire
(
new
KeyboardEventWrapper
(
e
))));
this
.
_register
(
dom
.
addStandardDisposableListener
(
this
.
_textArea
,
'
keyup
'
,
(
e
)
=>
this
.
_onKeyUp
.
fire
(
new
KeyboardEventWrapper
(
e
))));
this
.
_register
(
dom
.
addStandardDisposableListener
(
this
.
_textArea
,
'
keypress
'
,
(
e
)
=>
this
.
_onKeyPress
.
fire
(
new
KeyboardEventWrapper
(
e
))));
this
.
_register
(
dom
.
addDisposableListener
(
this
.
_textArea
,
'
compositionstart
'
,
(
e
)
=>
this
.
_onCompositionStart
.
fire
()));
this
.
_register
(
dom
.
addDisposableListener
(
this
.
_textArea
,
'
compositionend
'
,
(
e
)
=>
this
.
_onCompositionEnd
.
fire
()));
this
.
_register
(
dom
.
addDisposableListener
(
this
.
_textArea
,
'
input
'
,
(
e
)
=>
this
.
_onInput
.
fire
()));
this
.
_register
(
dom
.
addDisposableListener
(
this
.
_textArea
,
'
cut
'
,
(
e
:
ClipboardEvent
)
=>
this
.
_onCut
.
fire
(
new
ClipboardEventWrapper
(
e
))));
this
.
_register
(
dom
.
addDisposableListener
(
this
.
_textArea
,
'
copy
'
,
(
e
:
ClipboardEvent
)
=>
this
.
_onCopy
.
fire
(
new
ClipboardEventWrapper
(
e
))));
this
.
_register
(
dom
.
addDisposableListener
(
this
.
_textArea
,
'
paste
'
,
(
e
:
ClipboardEvent
)
=>
this
.
_onPaste
.
fire
(
new
ClipboardEventWrapper
(
e
))));
}
public
get
actual
():
HTMLTextAreaElement
{
return
this
.
_textArea
;
}
public
getValue
():
string
{
// console.log('current value: ' + this._textArea.value);
return
this
.
_textArea
.
value
;
}
public
setValue
(
reason
:
string
,
value
:
string
):
void
{
// console.log('reason: ' + reason + ', current value: ' + this._textArea.value + ' => new value: ' + value);
this
.
_textArea
.
value
=
value
;
}
public
getSelectionStart
():
number
{
return
this
.
_textArea
.
selectionStart
;
}
public
getSelectionEnd
():
number
{
return
this
.
_textArea
.
selectionEnd
;
}
public
setSelectionRange
(
selectionStart
:
number
,
selectionEnd
:
number
):
void
{
// console.log('setSelectionRange: ' + selectionStart + ', ' + selectionEnd);
try
{
let
scrollState
=
dom
.
saveParentsScrollTop
(
this
.
_textArea
);
this
.
_textArea
.
focus
();
this
.
_textArea
.
setSelectionRange
(
selectionStart
,
selectionEnd
);
dom
.
restoreParentsScrollTop
(
this
.
_textArea
,
scrollState
);
}
catch
(
e
)
{
// Sometimes IE throws when setting selection (e.g. textarea is off-DOM)
console
.
log
(
'
an error has been thrown!
'
);
}
}
public
isInOverwriteMode
():
boolean
{
// In IE, pressing Insert will bring the typing into overwrite mode
if
(
browser
.
isIE11orEarlier
&&
document
.
queryCommandValue
(
'
OverWrite
'
))
{
return
true
;
}
return
false
;
}
}
export
class
KeyboardHandler
extends
ViewEventHandler
implements
IDisposable
{
private
context
:
IViewContext
;
...
...
@@ -195,19 +49,22 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
private
contentWidth
:
number
;
private
scrollLeft
:
number
;
private
visibleRange
:
editorCommon
.
VisibleRange
;
constructor
(
context
:
IViewContext
,
viewController
:
IViewController
,
viewHelper
:
IKeyboardHandlerHelper
)
{
super
();
this
.
context
=
context
;
this
.
viewController
=
viewController
;
this
.
textArea
=
new
TextAreaWrapper
(
viewHelper
.
textArea
);
applyEditorFontInfo
(
this
.
textArea
.
actual
,
this
.
context
.
configuration
);
this
.
viewHelper
=
viewHelper
;
this
.
contentLeft
=
0
;
this
.
contentWidth
=
0
;
this
.
scrollLeft
=
0
;
this
.
textAreaHandler
=
new
TextAreaHandler
(
browser
,
this
.
_getStrategy
(),
this
.
textArea
,
this
.
context
.
model
);
this
.
textAreaHandler
=
new
TextAreaHandler
(
browser
,
this
.
_getStrategy
(),
this
.
textArea
,
this
.
context
.
model
,
()
=>
this
.
viewHelper
.
flushAnyAccumulatedEvents
()
);
this
.
_toDispose
=
[];
this
.
_toDispose
.
push
(
this
.
textAreaHandler
.
onKeyDown
((
e
)
=>
this
.
viewController
.
emitKeyDown
(
<
IKeyboardEvent
>
e
.
_actual
)));
...
...
@@ -233,27 +90,47 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
this
.
context
.
privateViewEventBus
.
emit
(
editorCommon
.
ViewEventNames
.
RevealRangeEvent
,
revealPositionEvent
);
// Find range pixel position
let
visibleRange
=
this
.
viewHelper
.
visibleRangeForPositionRelativeToEditor
(
lineNumber
,
column
);
if
(
visibleRange
)
{
StyleMutator
.
setTop
(
this
.
textArea
.
actual
,
visibleRange
.
top
);
StyleMutator
.
setLeft
(
this
.
textArea
.
actual
,
this
.
contentLeft
+
visibleRange
.
left
-
this
.
scrollLeft
);
}
this
.
visibleRange
=
this
.
viewHelper
.
visibleRangeForPositionRelativeToEditor
(
lineNumber
,
column
);
if
(
browser
.
isIE11orEarlier
)
{
StyleMutator
.
setWidth
(
this
.
textArea
.
actual
,
this
.
contentWidth
);
if
(
this
.
visibleRange
)
{
StyleMutator
.
setTop
(
this
.
textArea
.
actual
,
this
.
visibleRange
.
top
);
StyleMutator
.
setLeft
(
this
.
textArea
.
actual
,
this
.
contentLeft
+
this
.
visibleRange
.
left
-
this
.
scrollLeft
);
}
// Show the textarea
StyleMutator
.
setHeight
(
this
.
textArea
.
actual
,
this
.
context
.
configuration
.
editor
.
lineHeight
);
dom
.
addClass
(
this
.
viewHelper
.
viewDomNode
,
'
ime-input
'
);
}));
this
.
_toDispose
.
push
(
this
.
textAreaHandler
.
onCompositionUpdate
((
e
)
=>
{
if
(
browser
.
isEdgeOrIE
||
browser
.
isFirefox
)
{
// Due to isEdgeOrIE (where the textarea was not cleared initially)
// we cannot assume the text consists only of the composited text
StyleMutator
.
setWidth
(
this
.
textArea
.
actual
,
0
);
}
else
{
// adjust width by its size
let
canvasElem
=
<
HTMLCanvasElement
>
document
.
createElement
(
'
canvas
'
);
let
context
=
canvasElem
.
getContext
(
'
2d
'
);
let
cs
=
dom
.
getComputedStyle
(
this
.
textArea
.
actual
);
if
(
browser
.
isFirefox
)
{
// computedStyle.font is empty in Firefox...
context
.
font
=
`
${
cs
.
fontStyle
}
${
cs
.
fontVariant
}
${
cs
.
fontWeight
}
${
cs
.
fontStretch
}
${
cs
.
fontSize
}
/
${
cs
.
lineHeight
}
'
${
cs
.
fontFamily
}
'`
;
}
else
{
context
.
font
=
cs
.
font
;
}
let
metrics
=
context
.
measureText
(
e
.
data
);
StyleMutator
.
setWidth
(
this
.
textArea
.
actual
,
metrics
.
width
);
}
}));
this
.
_toDispose
.
push
(
this
.
textAreaHandler
.
onCompositionEnd
((
e
)
=>
{
this
.
textArea
.
actual
.
style
.
height
=
''
;
this
.
textArea
.
actual
.
style
.
width
=
''
;
StyleMutator
.
setLeft
(
this
.
textArea
.
actual
,
0
);
StyleMutator
.
setTop
(
this
.
textArea
.
actual
,
0
);
dom
.
removeClass
(
this
.
viewHelper
.
viewDomNode
,
'
ime-input
'
);
this
.
visibleRange
=
null
;
}));
this
.
_toDispose
.
push
(
GlobalScreenReaderNVDA
.
onChange
((
value
)
=>
{
this
.
textAreaHandler
.
setStrategy
(
this
.
_getStrategy
());
...
...
@@ -286,8 +163,7 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
public
onConfigurationChanged
(
e
:
editorCommon
.
IConfigurationChangedEvent
):
boolean
{
// Give textarea same font size & line height as editor, for the IME case (when the textarea is visible)
StyleMutator
.
setFontSize
(
this
.
textArea
.
actual
,
this
.
context
.
configuration
.
editor
.
fontSize
);
StyleMutator
.
setLineHeight
(
this
.
textArea
.
actual
,
this
.
context
.
configuration
.
editor
.
lineHeight
);
applyEditorFontInfo
(
this
.
textArea
.
actual
,
this
.
context
.
configuration
);
if
(
e
.
experimentalScreenReader
)
{
this
.
textAreaHandler
.
setStrategy
(
this
.
_getStrategy
());
}
...
...
@@ -296,6 +172,10 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
public
onScrollChanged
(
e
:
editorCommon
.
IScrollEvent
):
boolean
{
this
.
scrollLeft
=
e
.
scrollLeft
;
if
(
this
.
visibleRange
)
{
StyleMutator
.
setTop
(
this
.
textArea
.
actual
,
this
.
visibleRange
.
top
);
StyleMutator
.
setLeft
(
this
.
textArea
.
actual
,
this
.
contentLeft
+
this
.
visibleRange
.
left
-
this
.
scrollLeft
);
}
return
false
;
}
...
...
@@ -309,11 +189,6 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
return
false
;
}
public
onCursorPositionChanged
(
e
:
editorCommon
.
IViewCursorPositionChangedEvent
):
boolean
{
this
.
textAreaHandler
.
setCursorPosition
(
e
.
position
);
return
false
;
}
public
onLayoutChanged
(
layoutInfo
:
editorCommon
.
IEditorLayoutInfo
):
boolean
{
this
.
contentLeft
=
layoutInfo
.
contentLeft
;
this
.
contentWidth
=
layoutInfo
.
contentWidth
;
...
...
src/vs/editor/browser/editorBrowser.ts
浏览文件 @
fd052288
...
...
@@ -42,6 +42,7 @@ export interface IKeyboardHandlerHelper {
viewDomNode
:
HTMLElement
;
textArea
:
HTMLTextAreaElement
;
visibleRangeForPositionRelativeToEditor
(
lineNumber
:
number
,
column
:
number
):
editorCommon
.
VisibleRange
;
flushAnyAccumulatedEvents
():
void
;
}
export
interface
IPointerHandlerHelper
{
...
...
src/vs/editor/browser/view/viewImpl.ts
浏览文件 @
fd052288
...
...
@@ -396,6 +396,9 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
return
null
;
}
return
visibleRanges
[
0
];
},
flushAnyAccumulatedEvents
:
()
=>
{
this
.
_flushAnyAccumulatedEvents
();
}
};
}
...
...
src/vs/editor/common/controller/textAreaHandler.ts
浏览文件 @
fd052288
...
...
@@ -8,10 +8,9 @@ import {RunOnceScheduler} from 'vs/base/common/async';
import
Event
,
{
Emitter
}
from
'
vs/base/common/event
'
;
import
{
CommonKeybindings
}
from
'
vs/base/common/keyCodes
'
;
import
{
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
IClipboardEvent
,
IKeyboardEventWrapper
,
ISimpleModel
,
ITextAreaWrapper
,
ITypeData
,
TextAreaState
,
TextAreaStrategy
,
createTextAreaState
}
from
'
vs/editor/common/controller/textAreaState
'
;
import
{
Position
}
from
'
vs/editor/common/core/position
'
;
import
{
IClipboardEvent
,
ICompositionEvent
,
IKeyboardEventWrapper
,
ISimpleModel
,
ITextAreaWrapper
,
ITypeData
,
TextAreaState
,
TextAreaStrategy
,
createTextAreaState
}
from
'
vs/editor/common/controller/textAreaState
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
EndOfLinePreference
,
IEditor
Position
,
IEditor
Range
}
from
'
vs/editor/common/editorCommon
'
;
import
{
EndOfLinePreference
,
IEditorRange
}
from
'
vs/editor/common/editorCommon
'
;
enum
ReadFromTextArea
{
Type
,
...
...
@@ -21,7 +20,7 @@ enum ReadFromTextArea {
export
interface
IBrowser
{
isIPad
:
boolean
;
isChrome
:
boolean
;
is
IE11orEarlier
:
boolean
;
is
EdgeOrIE
:
boolean
;
isFirefox
:
boolean
;
enableEmptySelectionClipboard
:
boolean
;
}
...
...
@@ -56,12 +55,16 @@ export class TextAreaHandler extends Disposable {
private
_onCompositionStart
=
this
.
_register
(
new
Emitter
<
ICompositionStartData
>
());
public
onCompositionStart
:
Event
<
ICompositionStartData
>
=
this
.
_onCompositionStart
.
event
;
private
_onCompositionEnd
=
this
.
_register
(
new
Emitter
<
void
>
());
public
onCompositionEnd
:
Event
<
void
>
=
this
.
_onCompositionEnd
.
event
;
private
_onCompositionUpdate
=
this
.
_register
(
new
Emitter
<
ICompositionEvent
>
());
public
onCompositionUpdate
:
Event
<
ICompositionEvent
>
=
this
.
_onCompositionUpdate
.
event
;
private
_onCompositionEnd
=
this
.
_register
(
new
Emitter
<
ICompositionEvent
>
());
public
onCompositionEnd
:
Event
<
ICompositionEvent
>
=
this
.
_onCompositionEnd
.
event
;
private
Browser
:
IBrowser
;
private
textArea
:
ITextAreaWrapper
;
private
model
:
ISimpleModel
;
private
flushAnyAccumulatedEvents
:()
=>
void
;
private
selection
:
IEditorRange
;
private
selections
:
IEditorRange
[];
...
...
@@ -70,7 +73,6 @@ export class TextAreaHandler extends Disposable {
private
asyncTriggerCut
:
RunOnceScheduler
;
private
lastCompositionEndTime
:
number
;
private
cursorPosition
:
IEditorPosition
;
private
textAreaState
:
TextAreaState
;
private
textareaIsShownAtCursor
:
boolean
;
...
...
@@ -80,14 +82,14 @@ export class TextAreaHandler extends Disposable {
private
_nextCommand
:
ReadFromTextArea
;
constructor
(
Browser
:
IBrowser
,
strategy
:
TextAreaStrategy
,
textArea
:
ITextAreaWrapper
,
model
:
ISimpleModel
)
{
constructor
(
Browser
:
IBrowser
,
strategy
:
TextAreaStrategy
,
textArea
:
ITextAreaWrapper
,
model
:
ISimpleModel
,
flushAnyAccumulatedEvents
:()
=>
void
)
{
super
();
this
.
Browser
=
Browser
;
this
.
textArea
=
textArea
;
this
.
model
=
model
;
this
.
flushAnyAccumulatedEvents
=
flushAnyAccumulatedEvents
;
this
.
selection
=
new
Range
(
1
,
1
,
1
,
1
);
this
.
selections
=
[
new
Range
(
1
,
1
,
1
,
1
)];
this
.
cursorPosition
=
new
Position
(
1
,
1
);
this
.
_nextCommand
=
ReadFromTextArea
.
Type
;
this
.
asyncTriggerCut
=
new
RunOnceScheduler
(()
=>
this
.
_onCut
.
fire
(),
0
);
...
...
@@ -106,8 +108,8 @@ export class TextAreaHandler extends Disposable {
this
.
textareaIsShownAtCursor
=
false
;
this
.
_register
(
this
.
textArea
.
onCompositionStart
(()
=>
{
let
timeSinceLastCompositionEnd
=
(
new
Date
().
getTime
())
-
this
.
lastCompositionEndTime
;
this
.
_register
(
this
.
textArea
.
onCompositionStart
((
e
)
=>
{
if
(
this
.
textareaIsShownAtCursor
)
{
return
;
}
...
...
@@ -115,32 +117,26 @@ export class TextAreaHandler extends Disposable {
this
.
textareaIsShownAtCursor
=
true
;
// In IE we cannot set .value when handling 'compositionstart' because the entire composition will get canceled.
let
shouldEmptyTextArea
=
(
timeSinceLastCompositionEnd
>=
100
)
;
let
shouldEmptyTextArea
=
true
;
if
(
shouldEmptyTextArea
)
{
if
(
!
this
.
Browser
.
is
IE11orEarlier
)
{
if
(
!
this
.
Browser
.
is
EdgeOrIE
)
{
this
.
setTextAreaState
(
'
compositionstart
'
,
this
.
textAreaState
.
toEmpty
());
}
}
let
showAtLineNumber
:
number
;
let
showAtColumn
:
number
;
// In IE we cannot set .value when handling 'compositionstart' because the entire composition will get canceled.
if
(
this
.
Browser
.
isIE11orEarlier
)
{
// Ensure selection start is in viewport
showAtLineNumber
=
this
.
selection
.
startLineNumber
;
showAtColumn
=
(
this
.
selection
.
startColumn
-
this
.
textAreaState
.
getSelectionStart
());
}
else
{
showAtLineNumber
=
this
.
cursorPosition
.
lineNumber
;
showAtColumn
=
this
.
cursorPosition
.
column
;
}
this
.
_onCompositionStart
.
fire
({
showAtLineNumber
:
showA
tLineNumber
,
showAtColumn
:
showA
tColumn
showAtLineNumber
:
this
.
selection
.
star
tLineNumber
,
showAtColumn
:
this
.
selection
.
star
tColumn
});
}));
this
.
_register
(
this
.
textArea
.
onCompositionUpdate
((
e
)
=>
{
this
.
textAreaState
=
this
.
textAreaState
.
fromText
(
e
.
data
);
let
typeInput
=
this
.
textAreaState
.
updateComposition
();
this
.
_onType
.
fire
(
typeInput
);
this
.
_onCompositionUpdate
.
fire
(
e
);
}));
let
readFromTextArea
=
()
=>
{
this
.
textAreaState
=
this
.
textAreaState
.
fromTextArea
(
this
.
textArea
);
let
typeInput
=
this
.
textAreaState
.
deduceInput
();
...
...
@@ -155,9 +151,15 @@ export class TextAreaHandler extends Disposable {
}
};
this
.
_register
(
this
.
textArea
.
onCompositionEnd
(()
=>
{
// console.log('onCompositionEnd: ' + this.textArea.getValue());
// readFromTextArea();
this
.
_register
(
this
.
textArea
.
onCompositionEnd
((
e
)
=>
{
// console.log('onCompositionEnd: ' + e.data);
this
.
textAreaState
=
this
.
textAreaState
.
fromText
(
e
.
data
);
let
typeInput
=
this
.
textAreaState
.
updateComposition
();
this
.
_onType
.
fire
(
typeInput
);
// Due to isEdgeOrIE (where the textarea was not cleared initially)
// we cannot assume the text at the end consists only of the composited text
this
.
textAreaState
=
this
.
textAreaState
.
fromTextArea
(
this
.
textArea
);
this
.
lastCompositionEndTime
=
(
new
Date
()).
getTime
();
if
(
!
this
.
textareaIsShownAtCursor
)
{
...
...
@@ -181,11 +183,15 @@ export class TextAreaHandler extends Disposable {
// --- Clipboard operations
this
.
_register
(
this
.
textArea
.
onCut
((
e
)
=>
{
// Ensure we have the latest selection => ask all pending events to be sent
this
.
flushAnyAccumulatedEvents
();
this
.
_ensureClipboardGetsEditorSelection
(
e
);
this
.
asyncTriggerCut
.
schedule
();
}));
this
.
_register
(
this
.
textArea
.
onCopy
((
e
)
=>
{
// Ensure we have the latest selection => ask all pending events to be sent
this
.
flushAnyAccumulatedEvents
();
this
.
_ensureClipboardGetsEditorSelection
(
e
);
}));
...
...
@@ -232,10 +238,6 @@ export class TextAreaHandler extends Disposable {
this
.
_writePlaceholderAndSelectTextArea
(
'
selection changed
'
);
}
public
setCursorPosition
(
primary
:
IEditorPosition
):
void
{
this
.
cursorPosition
=
primary
;
}
// --- end event handlers
private
setTextAreaState
(
reason
:
string
,
textAreaState
:
TextAreaState
):
void
{
...
...
src/vs/editor/common/controller/textAreaState.ts
浏览文件 @
fd052288
...
...
@@ -15,6 +15,11 @@ export interface IClipboardEvent {
getTextData
():
string
;
}
export
interface
ICompositionEvent
{
data
:
string
;
locale
:
string
;
}
export
interface
IKeyboardEventWrapper
{
_actual
:
any
;
equals
(
keybinding
:
number
):
boolean
;
...
...
@@ -26,8 +31,9 @@ export interface ITextAreaWrapper {
onKeyDown
:
Event
<
IKeyboardEventWrapper
>
;
onKeyUp
:
Event
<
IKeyboardEventWrapper
>
;
onKeyPress
:
Event
<
IKeyboardEventWrapper
>
;
onCompositionStart
:
Event
<
void
>
;
onCompositionEnd
:
Event
<
void
>
;
onCompositionStart
:
Event
<
ICompositionEvent
>
;
onCompositionUpdate
:
Event
<
ICompositionEvent
>
;
onCompositionEnd
:
Event
<
ICompositionEvent
>
;
onInput
:
Event
<
void
>
;
onCut
:
Event
<
IClipboardEvent
>
;
onCopy
:
Event
<
IClipboardEvent
>
;
...
...
@@ -105,6 +111,21 @@ export abstract class TextAreaState {
public
abstract
fromText
(
text
:
string
):
TextAreaState
;
public
updateComposition
():
ITypeData
{
if
(
!
this
.
previousState
)
{
// This is the EMPTY state
return
{
text
:
''
,
replaceCharCnt
:
0
};
}
return
{
text
:
this
.
value
,
replaceCharCnt
:
this
.
previousState
.
selectionEnd
-
this
.
previousState
.
selectionStart
};
}
public
abstract
resetSelection
():
TextAreaState
;
public
getSelectionStart
():
number
{
...
...
@@ -378,7 +399,7 @@ export class NVDAPagedTextAreaState extends TextAreaState {
let
posttext
=
model
.
getValueInRange
(
posttextRange
,
EndOfLinePreference
.
LF
);
let
text
:
string
=
null
;
if
(
selectionStartPage
<
=
selectionEndPage
)
{
if
(
selectionStartPage
===
selectionEndPage
||
selectionStartPage
+
1
==
=
selectionEndPage
)
{
// take full selection
text
=
model
.
getValueInRange
(
selection
,
EndOfLinePreference
.
LF
);
}
else
{
...
...
@@ -391,6 +412,19 @@ export class NVDAPagedTextAreaState extends TextAreaState {
);
}
// Chromium handles very poorly text even of a few thousand chars
// Cut text to avoid stalling the entire UI
const
LIMIT_CHARS
=
500
;
if
(
pretext
.
length
>
LIMIT_CHARS
)
{
pretext
=
pretext
.
substring
(
pretext
.
length
-
LIMIT_CHARS
,
pretext
.
length
);
}
if
(
posttext
.
length
>
LIMIT_CHARS
)
{
posttext
=
posttext
.
substring
(
0
,
LIMIT_CHARS
);
}
if
(
text
.
length
>
2
*
LIMIT_CHARS
)
{
text
=
text
.
substring
(
0
,
LIMIT_CHARS
)
+
String
.
fromCharCode
(
8230
)
+
text
.
substring
(
text
.
length
-
LIMIT_CHARS
,
text
.
length
);
}
return
new
NVDAPagedTextAreaState
(
this
,
pretext
+
text
+
posttext
,
pretext
.
length
,
pretext
.
length
+
text
.
length
,
false
);
}
...
...
src/vs/editor/test/browser/controller/imeTester.html
0 → 100644
浏览文件 @
fd052288
<!DOCTYPE html>
<html>
<head>
<meta
http-equiv=
"X-UA-Compatible"
content=
"IE=edge"
/>
<meta
http-equiv=
"Content-Type"
content=
"text/html;charset=utf-8"
/>
<style>
.container
{
border-top
:
1px
solid
#ccc
;
padding-top
:
5px
;
clear
:
both
;
margin-top
:
30px
;
}
.container
.title
{
margin-bottom
:
10px
;
}
.container
button
{
float
:
left
;
}
.container
textarea
{
float
:
left
;
width
:
200px
;
height
:
100px
;
margin-left
:
50px
;
}
.container
.output
{
float
:
left
;
background
:
lightblue
;
margin
:
0
;
margin-left
:
50px
;
}
.container
.check
{
float
:
left
;
background
:
grey
;
margin
:
0
;
margin-left
:
50px
;
}
.container
.check.good
{
background
:
lightgreen
;
}
</style>
</head>
<body>
<h3>
Detailed setup steps at https://github.com/Microsoft/vscode/wiki/IME-Test
</h3>
<script
src=
"../../../../loader.js"
></script>
<script>
require
.
config
({
baseUrl
:
'
../../../../../../out
'
});
require
([
'
vs/editor/test/browser/controller/imeTester
'
],
function
(
imeTester
)
{
// console.log('loaded', imeTester);
// imeTester.createTest();
});
</script>
</body>
</html>
\ No newline at end of file
src/vs/editor/test/browser/controller/imeTester.ts
0 → 100644
浏览文件 @
fd052288
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
{
TextAreaHandler
}
from
'
vs/editor/common/controller/textAreaHandler
'
;
import
*
as
browser
from
'
vs/base/browser/browser
'
;
import
{
TextAreaStrategy
,
ISimpleModel
}
from
'
vs/editor/common/controller/textAreaState
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
*
as
editorCommon
from
'
vs/editor/common/editorCommon
'
;
import
{
TextAreaWrapper
}
from
'
vs/editor/browser/controller/input/textAreaWrapper
'
;
import
{
Position
}
from
'
vs/editor/common/core/position
'
;
// To run this test, open imeTester.html
class
SingleLineTestModel
implements
ISimpleModel
{
private
_line
:
string
;
private
_eol
:
string
;
constructor
(
line
:
string
)
{
this
.
_line
=
line
;
this
.
_eol
=
'
\n
'
;
}
setText
(
text
:
string
)
{
this
.
_line
=
text
;
}
getLineMaxColumn
(
lineNumber
:
number
):
number
{
return
this
.
_line
.
length
+
1
;
}
getEOL
():
string
{
return
this
.
_eol
;
}
getValueInRange
(
range
:
editorCommon
.
IRange
,
eol
:
editorCommon
.
EndOfLinePreference
):
string
{
return
this
.
_line
.
substring
(
range
.
startColumn
-
1
,
range
.
endColumn
-
1
);
}
getModelLineContent
(
lineNumber
:
number
):
string
{
return
this
.
_line
;
}
getLineCount
():
number
{
return
1
;
}
convertViewPositionToModelPosition
(
viewLineNumber
:
number
,
viewColumn
:
number
):
Position
{
return
new
Position
(
viewLineNumber
,
viewColumn
);
}
}
class
TestView
{
private
_model
:
SingleLineTestModel
;
constructor
(
model
:
SingleLineTestModel
)
{
this
.
_model
=
model
;
}
public
paint
(
output
:
HTMLElement
)
{
let
r
=
''
;
for
(
let
i
=
1
;
i
<=
this
.
_model
.
getLineCount
();
i
++
)
{
let
content
=
this
.
_model
.
getModelLineContent
(
i
);
r
+=
content
+
'
<br/>
'
;
}
output
.
innerHTML
=
r
;
}
}
function
doCreateTest
(
strategy
:
TextAreaStrategy
,
description
:
string
,
inputStr
:
string
,
expectedStr
:
string
):
HTMLElement
{
let
container
=
document
.
createElement
(
'
div
'
);
container
.
className
=
'
container
'
;
let
title
=
document
.
createElement
(
'
div
'
);
title
.
className
=
'
title
'
;
title
.
innerHTML
=
TextAreaStrategy
[
strategy
]
+
'
strategy:
'
+
description
+
'
. Type <strong>
'
+
inputStr
+
'
</strong>
'
;
container
.
appendChild
(
title
);
let
startBtn
=
document
.
createElement
(
'
button
'
);
startBtn
.
innerHTML
=
'
Start
'
;
container
.
appendChild
(
startBtn
);
let
input
=
document
.
createElement
(
'
textarea
'
);
input
.
setAttribute
(
'
rows
'
,
'
10
'
);
input
.
setAttribute
(
'
cols
'
,
'
40
'
);
container
.
appendChild
(
input
);
let
textAreaWrapper
=
new
TextAreaWrapper
(
input
);
let
model
=
new
SingleLineTestModel
(
'
some text
'
);
let
handler
=
new
TextAreaHandler
(
browser
,
strategy
,
textAreaWrapper
,
model
,
()
=>
{});
input
.
onfocus
=
()
=>
{
handler
.
setHasFocus
(
true
);
};
input
.
onblur
=
()
=>
{
handler
.
setHasFocus
(
false
);
};
let
output
=
document
.
createElement
(
'
pre
'
);
output
.
className
=
'
output
'
;
container
.
appendChild
(
output
);
let
check
=
document
.
createElement
(
'
pre
'
);
check
.
className
=
'
check
'
;
container
.
appendChild
(
check
);
let
br
=
document
.
createElement
(
'
br
'
);
br
.
style
.
clear
=
'
both
'
;
container
.
appendChild
(
br
);
let
view
=
new
TestView
(
model
);
let
cursorOffset
:
number
;
let
cursorLength
:
number
;
let
updatePosition
=
(
off
:
number
,
len
:
number
)
=>
{
cursorOffset
=
off
;
cursorLength
=
len
;
handler
.
setCursorSelections
(
new
Range
(
1
,
1
+
cursorOffset
,
1
,
1
+
cursorOffset
+
cursorLength
),
[]);
handler
.
writePlaceholderAndSelectTextAreaSync
();
};
let
updateModelAndPosition
=
(
text
:
string
,
off
:
number
,
len
:
number
)
=>
{
model
.
setText
(
text
);
updatePosition
(
off
,
len
);
view
.
paint
(
output
);
let
expected
=
'
some
'
+
expectedStr
+
'
text
'
;
if
(
text
===
expected
)
{
check
.
innerHTML
=
'
[GOOD]
'
;
check
.
className
=
'
check good
'
;
}
else
{
check
.
innerHTML
=
'
[BAD]
'
;
check
.
className
=
'
check bad
'
;
}
check
.
innerHTML
+=
expected
;
};
handler
.
onType
((
e
)
=>
{
console
.
log
(
'
type text:
'
+
e
.
text
+
'
, replaceCharCnt:
'
+
e
.
replaceCharCnt
);
let
text
=
model
.
getModelLineContent
(
1
);
let
preText
=
text
.
substring
(
0
,
cursorOffset
-
e
.
replaceCharCnt
);
let
postText
=
text
.
substring
(
cursorOffset
+
cursorLength
);
let
midText
=
e
.
text
;
updateModelAndPosition
(
preText
+
midText
+
postText
,
(
preText
+
midText
).
length
,
0
);
});
view
.
paint
(
output
);
startBtn
.
onclick
=
function
()
{
updateModelAndPosition
(
'
some text
'
,
5
,
0
);
input
.
focus
();
};
return
container
;
}
const
TESTS
=
[
{
description
:
'
Japanese IME 1
'
,
in
:
'
sennsei [Enter]
'
,
out
:
'
せんせい
'
},
{
description
:
'
Japanese IME 2
'
,
in
:
'
konnichiha [Enter]
'
,
out
:
'
こんいちは
'
},
{
description
:
'
Japanese IME 3
'
,
in
:
'
mikann [Enter]
'
,
out
:
'
みかん
'
},
{
description
:
'
Korean IME 1
'
,
in
:
'
gksrmf [Space]
'
,
out
:
'
한글
'
},
{
description
:
'
Chinese IME 1
'
,
in
:
'
.,
'
,
out
:
'
。,
'
},
{
description
:
'
Chinese IME 2
'
,
in
:
'
ni [Space] hao [Space]
'
,
out
:
'
你好
'
},
{
description
:
'
Chinese IME 3
'
,
in
:
'
hazni [Space]
'
,
out
:
'
哈祝你
'
},
];
TESTS
.
forEach
((
t
)
=>
{
document
.
body
.
appendChild
(
doCreateTest
(
TextAreaStrategy
.
NVDA
,
t
.
description
,
t
.
in
,
t
.
out
));
document
.
body
.
appendChild
(
doCreateTest
(
TextAreaStrategy
.
IENarrator
,
t
.
description
,
t
.
in
,
t
.
out
));
});
src/vs/editor/test/common/mocks/mockTextAreaWrapper.ts
浏览文件 @
fd052288
...
...
@@ -6,7 +6,7 @@
import
Event
,
{
Emitter
}
from
'
vs/base/common/event
'
;
import
{
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
IClipboardEvent
,
IKeyboardEventWrapper
,
ITextAreaWrapper
}
from
'
vs/editor/common/controller/textAreaState
'
;
import
{
IClipboardEvent
,
I
CompositionEvent
,
I
KeyboardEventWrapper
,
ITextAreaWrapper
}
from
'
vs/editor/common/controller/textAreaState
'
;
export
class
MockTextAreaWrapper
extends
Disposable
implements
ITextAreaWrapper
{
...
...
@@ -19,11 +19,14 @@ export class MockTextAreaWrapper extends Disposable implements ITextAreaWrapper
private
_onKeyPress
=
this
.
_register
(
new
Emitter
<
IKeyboardEventWrapper
>
());
public
onKeyPress
:
Event
<
IKeyboardEventWrapper
>
=
this
.
_onKeyPress
.
event
;
private
_onCompositionStart
=
this
.
_register
(
new
Emitter
<
void
>
());
public
onCompositionStart
:
Event
<
void
>
=
this
.
_onCompositionStart
.
event
;
private
_onCompositionStart
=
this
.
_register
(
new
Emitter
<
ICompositionEvent
>
());
public
onCompositionStart
:
Event
<
ICompositionEvent
>
=
this
.
_onCompositionStart
.
event
;
private
_onCompositionEnd
=
this
.
_register
(
new
Emitter
<
void
>
());
public
onCompositionEnd
:
Event
<
void
>
=
this
.
_onCompositionEnd
.
event
;
private
_onCompositionUpdate
=
this
.
_register
(
new
Emitter
<
ICompositionEvent
>
());
public
onCompositionUpdate
:
Event
<
ICompositionEvent
>
=
this
.
_onCompositionUpdate
.
event
;
private
_onCompositionEnd
=
this
.
_register
(
new
Emitter
<
ICompositionEvent
>
());
public
onCompositionEnd
:
Event
<
ICompositionEvent
>
=
this
.
_onCompositionEnd
.
event
;
private
_onInput
=
this
.
_register
(
new
Emitter
<
void
>
());
public
onInput
:
Event
<
void
>
=
this
.
_onInput
.
event
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录