@qnroa/qtype 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +84 -0
- package/CHANGELOG.zh.md +66 -0
- package/dist/core/typing/engine/TypingInput.js +147 -30
- package/dist/core/typing/engine/settings.js +1 -0
- package/dist/view/assets/index-4lY5IlHh.js +224 -0
- package/dist/view/assets/index-B7iVy4Gn.js +3 -0
- package/dist/view/assets/{index-Cj70GP_V.js → index-BKlIGFJx.js} +1 -1
- package/dist/view/assets/index-CRg6M5y-.css +1 -0
- package/dist/view/index.html +2 -2
- package/package.json +1 -1
- package/dist/view/assets/index-B_3g67jY.js +0 -3
- package/dist/view/assets/index-CeFBpbIw.js +0 -194
- package/dist/view/assets/index-VPadwWzO.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -13,6 +13,90 @@ can land in any minor bump (`0.x.0`).
|
|
|
13
13
|
|
|
14
14
|
## [Unreleased]
|
|
15
15
|
|
|
16
|
+
## [0.2.5] — 2026-09-14
|
|
17
|
+
|
|
18
|
+
Second pass on card-lifecycle correctness plus a code-typing quality-
|
|
19
|
+
of-life feature. The completion pill no longer overlaps card content,
|
|
20
|
+
navigating between done and not-done cards no longer poisons the
|
|
21
|
+
fresh card with a "already done" paint, and code cards can skip
|
|
22
|
+
leading indentation the way typing.io does.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
- **Auto-skip indent** (Typing rules → Auto-skip indent). Every line's
|
|
26
|
+
leading spaces / tabs are pre-hit for the user — the cursor jumps to
|
|
27
|
+
the first real character on each line, so code cards no longer force
|
|
28
|
+
you to type ten spaces before every statement. On by default; toggle
|
|
29
|
+
in Settings or via the HUD ⋮ menu. Same behaviour typing.io ships as
|
|
30
|
+
its default and defended publicly against "just make me type it"
|
|
31
|
+
arguments in early user feedback. Blank lines (pure-whitespace lines)
|
|
32
|
+
are not skipped — the user still hits Enter for them.
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
- **Completion pill overlapping card content.** The "press Enter to
|
|
36
|
+
continue" hint used to sit under the HUD as an absolute-positioned
|
|
37
|
+
pill; on code / article cards where the prompt sits right below the
|
|
38
|
+
HUD, it landed on top of the first line of content. The hint now
|
|
39
|
+
lives in a fixed-height notification strip between the stage and the
|
|
40
|
+
keyboard — same pattern Anki / Duolingo use — so it never overlays
|
|
41
|
+
content and layout doesn't shift when it appears or leaves.
|
|
42
|
+
- **Wrong card shown as "already done" after rewind then advance.**
|
|
43
|
+
Sequence: finish card 1 → auto-advance to card 2 → rewind to card 1
|
|
44
|
+
(correctly rendered as done) → advance back to card 2, which was
|
|
45
|
+
now painted green even though the user had never typed it. Root
|
|
46
|
+
cause: the route's `useEffect` for `markAllHit()` ran after `cardId`
|
|
47
|
+
changed but before the state machine's `CARD_ENTER` effect settled
|
|
48
|
+
the new `kind`, so a stale `completed` from the previous card
|
|
49
|
+
painted the fresh engine. The effect now cross-checks the
|
|
50
|
+
authoritative `cardDone` (from `useDoneState`) before calling
|
|
51
|
+
`markAllHit()`.
|
|
52
|
+
- **Auto-advance timer not scheduling after `manual → auto` mid-pass.**
|
|
53
|
+
If the user switched advance mode from manual to auto while sitting
|
|
54
|
+
in a `passed{awaitingAdvance}` state, the 700ms timer that fires
|
|
55
|
+
`STAMP_TIMEOUT` never scheduled — the effect that owns it had no
|
|
56
|
+
`advanceMode` dep and its `prev !== 'passed'` gate blocked re-entry.
|
|
57
|
+
The gate is now `stampTimerRef.current === null` (idempotent), and
|
|
58
|
+
`advanceMode` is a proper dep.
|
|
59
|
+
|
|
60
|
+
## [0.2.4] — 2026-09-08
|
|
61
|
+
|
|
62
|
+
Bug-fix + refactor pass around the ignore-punctuation setting and the
|
|
63
|
+
plumbing that surfaces settings in the command palette and HUD menu.
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
- **Ignore-punctuation used to eat operators.** `+`, `-`, `*`, `/`,
|
|
67
|
+
`=`, `<`, `>`, `(`, `)` and other code / math symbols were treated
|
|
68
|
+
as punctuation, so turning the setting on rewrote whole code
|
|
69
|
+
passages into runs of blanks. The punctuation set is now the same
|
|
70
|
+
9 ASCII marks keybr / ptype / Monkeytype recognise
|
|
71
|
+
(`. , ! ? ; : ' " -` — sentence and clause marks only) plus the
|
|
72
|
+
corresponding CJK sentence marks, smart quotes, and Chinese book /
|
|
73
|
+
corner-bracket pairs. Operators and brackets pass through
|
|
74
|
+
unchanged.
|
|
75
|
+
- **Arena stale-render after toggling ignore-punctuation.** Switching
|
|
76
|
+
the setting mid-card left the arena rendered against the previous
|
|
77
|
+
engine's target for a tick, so punctuation slots appeared to
|
|
78
|
+
linger until the next event. The arena is now keyed on
|
|
79
|
+
`${card.id}::${engine.target}`, forcing a full remount whenever
|
|
80
|
+
the engine's effective target changes — no stale
|
|
81
|
+
`useSyncExternalStore` subscription, no leftover DOM.
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
- **HUD ⋮ menu is now registry-driven.** Every settings entry that
|
|
85
|
+
opts in via `hud: { icon, order? }` shows up as a quick toggle
|
|
86
|
+
during typing. `hint`, `ignoreCase`, `ignorePunctuation`,
|
|
87
|
+
`allowBackspace`, `showKeyboard`, `showHands` land in the menu by
|
|
88
|
+
default; `showPhonetic`, `showGloss`, `autoSpeak` show up on word
|
|
89
|
+
/ sentence cards. Adding a new HUD toggle is now one registry
|
|
90
|
+
line.
|
|
91
|
+
- **Command palette lists every setting.** The palette walks the
|
|
92
|
+
settings registry and emits a `setting.<id>` command per entry —
|
|
93
|
+
bool settings toggle inline; enum / number / action settings open
|
|
94
|
+
the settings dialog scrolled to the row. No more manually adding
|
|
95
|
+
palette entries for each new setting.
|
|
96
|
+
- **`useHint()` extracted.** Three call sites were inlining the
|
|
97
|
+
same `usePersistedState<HintMode>('settings', 'hint', ...)` block;
|
|
98
|
+
they all use the shared hook now.
|
|
99
|
+
|
|
16
100
|
## [0.2.3] — 2026-09-07
|
|
17
101
|
|
|
18
102
|
Fixes long-standing bugs around Chinese IME input on the typing arena
|
package/CHANGELOG.zh.md
CHANGED
|
@@ -12,6 +12,72 @@ English: [CHANGELOG.md](https://www.npmjs.com/package/@qnroa/qtype?activeTab=cod
|
|
|
12
12
|
|
|
13
13
|
## [Unreleased]
|
|
14
14
|
|
|
15
|
+
## [0.2.5] — 2026-09-14
|
|
16
|
+
|
|
17
|
+
围绕卡片生命周期的正确性又做了一轮修复,并加入一个代码打字的
|
|
18
|
+
体验改进。完成提示条不再压卡片内容;在"已完成"和"未打"卡片
|
|
19
|
+
之间来回切,新卡不再被误标为"已完成";代码卡按 typing.io 的做法
|
|
20
|
+
自动跳过缩进。
|
|
21
|
+
|
|
22
|
+
### 新增
|
|
23
|
+
- **自动跳过缩进**(打字规则 → 自动跳过缩进)。每行开头的空格 / Tab
|
|
24
|
+
由系统自动填入,光标直接落在第一个真字符上 —— 代码卡不再逼你
|
|
25
|
+
每句前先敲十个空格。默认开启,可在设置或 HUD ⋮ 菜单里切换。
|
|
26
|
+
typing.io 默认就是这个行为,作者曾公开对"就让用户自己打空格吧"
|
|
27
|
+
这种意见做过反驳。纯空白行(只有空格 + 换行)不自动跳过,用户
|
|
28
|
+
仍需手动敲回车。
|
|
29
|
+
|
|
30
|
+
### 修复
|
|
31
|
+
- **完成提示条压卡片内容。** "按 Enter 继续"提示原来是挂在 HUD
|
|
32
|
+
下方的绝对定位气泡,在代码 / 文章类卡片(内容紧贴 HUD 下方)
|
|
33
|
+
时会盖住第一行内容。现在提示条改成打字区和键盘之间的**固定
|
|
34
|
+
高度通知条**,和 Anki / Duolingo 一样 —— 不遮内容,布局也不会
|
|
35
|
+
在提示出现 / 消失时跳动。
|
|
36
|
+
- **回退再前进后新卡被误显示为"已完成"。** 场景:打完卡片 1 →
|
|
37
|
+
自动到卡片 2 → 退回卡片 1(正确显示为完成)→ 再前进到卡片 2,
|
|
38
|
+
卡片 2 被涂满绿色,尽管从没打过。根因:route 里的
|
|
39
|
+
`markAllHit()` useEffect 在 `cardId` 变化后先跑,状态机
|
|
40
|
+
`CARD_ENTER` effect 后跑,`kind` 仍是旧的 `completed`,把新引擎
|
|
41
|
+
也涂绿了。现在这个 effect 会**同时校验** `useDoneState` 里真实
|
|
42
|
+
的 `cardDone`,不再单信任 stale `kind`。
|
|
43
|
+
- **`manual → auto` 中途切换后自动前进 timer 不触发。** 用户在
|
|
44
|
+
`passed{awaitingAdvance}` 里把前进模式从 manual 切到 auto,原本
|
|
45
|
+
700ms 定时器不启动 —— effect 的 deps 里没有 `advanceMode`,而且
|
|
46
|
+
`prev !== 'passed'` 的守卫挡住了二次进入。改成幂等守卫
|
|
47
|
+
(`stampTimerRef.current === null`)并把 `advanceMode` 加入 deps。
|
|
48
|
+
|
|
49
|
+
## [0.2.4] — 2026-09-08
|
|
50
|
+
|
|
51
|
+
围绕"忽略标点"设置和"命令面板 / HUD 菜单如何呈现设置"两件事,
|
|
52
|
+
做了一轮修复和小重构。
|
|
53
|
+
|
|
54
|
+
### 修复
|
|
55
|
+
- **忽略标点误伤运算符。** 之前 `+ - * / = < > ( )` 等代码 / 数学
|
|
56
|
+
符号都被当成标点,一开设置就把整段代码替换成空格。改成和
|
|
57
|
+
keybr / ptype / Monkeytype 一致的 9 个 ASCII 句读
|
|
58
|
+
(`. , ! ? ; : ' " -`),加上对应的中文句号 / 逗号 / 冒号 / 分号 /
|
|
59
|
+
问号 / 感叹号 / 顿号 + 中文引号 / 书名号 / 角括号。运算符和括号
|
|
60
|
+
一律不动。
|
|
61
|
+
- **切换忽略标点后 arena 一瞬间残留旧渲染。** 卡片打字中途切设置,
|
|
62
|
+
引擎重建了但 arena 的 fiber 被复用,`useSyncExternalStore`
|
|
63
|
+
订阅还挂在旧 engine 上,标点位置视觉错乱,得刷新才好。arena
|
|
64
|
+
的 React key 改成 `${card.id}::${engine.target}`,engine 目标
|
|
65
|
+
一变就整棵重挂,零残留。
|
|
66
|
+
|
|
67
|
+
### 变更
|
|
68
|
+
- **HUD ⋮ 菜单改为注册表驱动。** 设置条目里加 `hud: { icon, order? }`
|
|
69
|
+
就自动出现在打字时的快捷菜单。默认加入的:显示提示、忽略大小写、
|
|
70
|
+
忽略标点、允许退格、显示键盘、显示手位;word / sentence 卡片
|
|
71
|
+
额外多显示音标 / 释义 / 自动朗读。加一个 HUD 快捷开关现在只需
|
|
72
|
+
改注册表一行。
|
|
73
|
+
- **命令面板列出所有设置。** 面板遍历设置注册表,给每个条目生成一条
|
|
74
|
+
`setting.<id>` 命令。bool 类型直接就地翻转;枚举 / 数字 / action
|
|
75
|
+
打开设置对话框并高亮那一行。新增设置不再需要单独往命令面板加
|
|
76
|
+
条目。
|
|
77
|
+
- **抽出 `useHint()` hook。** 之前 3 个地方内联同样的
|
|
78
|
+
`usePersistedState<HintMode>('settings', 'hint', ...)`,现在统一用
|
|
79
|
+
这个 hook。
|
|
80
|
+
|
|
15
81
|
## [0.2.3] — 2026-09-07
|
|
16
82
|
|
|
17
83
|
修复打字界面在中文输入法下的一系列老问题,并把"忽略标点"的行为
|
|
@@ -26,6 +26,10 @@ export class TypingInput {
|
|
|
26
26
|
#target;
|
|
27
27
|
#targetCodepoints;
|
|
28
28
|
#length;
|
|
29
|
+
/** Per-slot flag: this slot is a leading-indent whitespace that the
|
|
30
|
+
* engine will auto-hit under `autoSkipIndent`. Computed once at
|
|
31
|
+
* construction from the target's line structure. */
|
|
32
|
+
#skipMask;
|
|
29
33
|
settings;
|
|
30
34
|
#chars;
|
|
31
35
|
#position;
|
|
@@ -53,8 +57,17 @@ export class TypingInput {
|
|
|
53
57
|
? this.#targetCodepoints.map((cp) => String.fromCodePoint(cp)).join('')
|
|
54
58
|
: text;
|
|
55
59
|
this.#length = this.#targetCodepoints.length;
|
|
60
|
+
this.#skipMask = this.settings.autoSkipIndent
|
|
61
|
+
? buildIndentSkipMask(this.#targetCodepoints)
|
|
62
|
+
: new Array(this.#length).fill(false);
|
|
56
63
|
this.#chars = this.#buildInitialChars();
|
|
57
64
|
this.#position = 0;
|
|
65
|
+
// If the target starts with indent whitespace, auto-advance past
|
|
66
|
+
// it before the user's first keystroke so the initial cursor is
|
|
67
|
+
// on the first "real" character. Subsequent lines are handled in
|
|
68
|
+
// `onKeyDown` after a newline hit lands the cursor on the next
|
|
69
|
+
// line's leading whitespace.
|
|
70
|
+
this.#autoAdvanceSkipped(0);
|
|
58
71
|
}
|
|
59
72
|
#buildInitialChars() {
|
|
60
73
|
const chars = new Array(this.#length);
|
|
@@ -103,6 +116,12 @@ export class TypingInput {
|
|
|
103
116
|
this.#chars = next;
|
|
104
117
|
if (isHit || !this.settings.stopOnError) {
|
|
105
118
|
this.#position++;
|
|
119
|
+
// After advancing, if the new position is an auto-skip indent
|
|
120
|
+
// whitespace (typical case: user just hit newline, cursor sits
|
|
121
|
+
// on the next line's leading spaces / tabs), fast-forward
|
|
122
|
+
// through those slots so the user's next keystroke lands on
|
|
123
|
+
// real code.
|
|
124
|
+
this.#autoAdvanceSkipped(timestamp);
|
|
106
125
|
}
|
|
107
126
|
this.#notify();
|
|
108
127
|
if (recovered)
|
|
@@ -122,7 +141,13 @@ export class TypingInput {
|
|
|
122
141
|
// Signal that the user is trying to rewind past start.
|
|
123
142
|
return Feedback.Restart;
|
|
124
143
|
}
|
|
125
|
-
|
|
144
|
+
// Skip back over any auto-hit indent whitespace so the user
|
|
145
|
+
// doesn't "rewind" into invisible-to-them spaces. Land on the
|
|
146
|
+
// most recent user-touched slot.
|
|
147
|
+
let target = this.#position - 1;
|
|
148
|
+
while (target > 0 && this.#skipMask[target])
|
|
149
|
+
target--;
|
|
150
|
+
this.#position = target;
|
|
126
151
|
const next = this.#chars.slice();
|
|
127
152
|
const prev = next[this.#position];
|
|
128
153
|
// Clear Hit/Miss (this slot is now pending again) but remember it
|
|
@@ -143,8 +168,35 @@ export class TypingInput {
|
|
|
143
168
|
reset() {
|
|
144
169
|
this.#chars = this.#buildInitialChars();
|
|
145
170
|
this.#position = 0;
|
|
171
|
+
this.#autoAdvanceSkipped(0);
|
|
146
172
|
this.#notify();
|
|
147
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Walk `#position` past every consecutive auto-skip indent slot,
|
|
176
|
+
* marking each as an auto-hit so the arena renders them green.
|
|
177
|
+
* `timestamp` is stamped onto the skipped chars for consistency
|
|
178
|
+
* with real hits; downstream stats ignore auto-hit timestamps for
|
|
179
|
+
* WPM computation since they weren't user keystrokes.
|
|
180
|
+
*/
|
|
181
|
+
#autoAdvanceSkipped(timestamp) {
|
|
182
|
+
if (!this.settings.autoSkipIndent)
|
|
183
|
+
return;
|
|
184
|
+
while (this.#position < this.#length &&
|
|
185
|
+
this.#skipMask[this.#position]) {
|
|
186
|
+
const idx = this.#position;
|
|
187
|
+
const expected = this.#targetCodepoints[idx];
|
|
188
|
+
const next = this.#chars.slice();
|
|
189
|
+
const prev = next[idx];
|
|
190
|
+
next[idx] = {
|
|
191
|
+
target: expected,
|
|
192
|
+
typed: expected,
|
|
193
|
+
attrs: (prev.attrs & ~(CharAttr.Miss | CharAttr.Cursor)) | CharAttr.Hit,
|
|
194
|
+
timestamp,
|
|
195
|
+
};
|
|
196
|
+
this.#chars = next;
|
|
197
|
+
this.#position++;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
148
200
|
/**
|
|
149
201
|
* Mark every character as Hit — used by the route's `completed`
|
|
150
202
|
* state (a card the user finished earlier) so downstream renderers
|
|
@@ -216,35 +268,100 @@ function sameLetter(a, b) {
|
|
|
216
268
|
return false;
|
|
217
269
|
}
|
|
218
270
|
/**
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
* (
|
|
271
|
+
* Sentence / clause punctuation, per keybr + ptype + Monkeytype
|
|
272
|
+
* conventions. Explicitly excludes math operators (`+ - * / = < >`),
|
|
273
|
+
* brackets (`( ) [ ] { }`), and code-symbol characters (`_ | \ @ # $
|
|
274
|
+
* % & ^ ~ \``) — those show up in real prose and code and should be
|
|
275
|
+
* typed as-is, not silently rewritten to space.
|
|
276
|
+
*
|
|
277
|
+
* Uses an inline set of codepoints instead of `\p{P}` — the Unicode
|
|
278
|
+
* punctuation category also matches math / brackets / dashes we want
|
|
279
|
+
* to leave alone, which is exactly why every mainstream typing app
|
|
280
|
+
* hard-codes its own list.
|
|
281
|
+
*/
|
|
282
|
+
/**
|
|
283
|
+
* Mark every codepoint that is leading whitespace on its line — a run
|
|
284
|
+
* of ASCII space (0x20) or tab (0x09) at line-start, up to (but not
|
|
285
|
+
* including) the first non-whitespace character on that line. Blank
|
|
286
|
+
* lines (nothing but whitespace between two newlines) are not
|
|
287
|
+
* flagged — the user still hits Enter for them, and there is no
|
|
288
|
+
* "indent" to skip.
|
|
222
289
|
*/
|
|
290
|
+
function buildIndentSkipMask(cps) {
|
|
291
|
+
const mask = new Array(cps.length).fill(false);
|
|
292
|
+
let atLineStart = true;
|
|
293
|
+
for (let i = 0; i < cps.length; i++) {
|
|
294
|
+
const cp = cps[i];
|
|
295
|
+
if (cp === 0x0a) {
|
|
296
|
+
atLineStart = true;
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
if (atLineStart && (cp === 0x20 || cp === 0x09)) {
|
|
300
|
+
mask[i] = true;
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
atLineStart = false;
|
|
304
|
+
}
|
|
305
|
+
// Blank lines: a run of whitespace immediately followed by a
|
|
306
|
+
// newline is not "indentation" — un-flag it so the user still has
|
|
307
|
+
// to hit Enter (or space, if the line is really pure spaces) to
|
|
308
|
+
// pass. Walk each flagged run and check whether it ends at a
|
|
309
|
+
// newline before any non-whitespace.
|
|
310
|
+
for (let i = 0; i < mask.length; i++) {
|
|
311
|
+
if (!mask[i])
|
|
312
|
+
continue;
|
|
313
|
+
let j = i;
|
|
314
|
+
while (j < mask.length && mask[j])
|
|
315
|
+
j++;
|
|
316
|
+
// j is the first non-mask index after the run. If cps[j] is a
|
|
317
|
+
// newline or end-of-input, this run isn't indent — clear it.
|
|
318
|
+
if (j >= cps.length || cps[j] === 0x0a) {
|
|
319
|
+
for (let k = i; k < j; k++)
|
|
320
|
+
mask[k] = false;
|
|
321
|
+
}
|
|
322
|
+
i = j - 1;
|
|
323
|
+
}
|
|
324
|
+
return mask;
|
|
325
|
+
}
|
|
223
326
|
function isPunctuation(cp) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
327
|
+
switch (cp) {
|
|
328
|
+
// ASCII sentence / clause marks. . , ! ? ; : ' "
|
|
329
|
+
case 0x2e:
|
|
330
|
+
case 0x2c:
|
|
331
|
+
case 0x21:
|
|
332
|
+
case 0x3f:
|
|
333
|
+
case 0x3b:
|
|
334
|
+
case 0x3a:
|
|
335
|
+
case 0x27:
|
|
336
|
+
case 0x22:
|
|
337
|
+
// CJK sentence marks: 。 、
|
|
338
|
+
case 0x3001:
|
|
339
|
+
case 0x3002:
|
|
340
|
+
// Fullwidth forms: ! ? , : ; ' "
|
|
341
|
+
case 0xff01:
|
|
342
|
+
case 0xff1f:
|
|
343
|
+
case 0xff0c:
|
|
344
|
+
case 0xff1a:
|
|
345
|
+
case 0xff1b:
|
|
346
|
+
case 0xff07:
|
|
347
|
+
case 0xff02:
|
|
348
|
+
// Smart quotes: " " ' '
|
|
349
|
+
case 0x201c:
|
|
350
|
+
case 0x201d:
|
|
351
|
+
case 0x2018:
|
|
352
|
+
case 0x2019:
|
|
353
|
+
// Book title marks: 《 》 〈 〉
|
|
354
|
+
case 0x300a:
|
|
355
|
+
case 0x300b:
|
|
356
|
+
case 0x3008:
|
|
357
|
+
case 0x3009:
|
|
358
|
+
// CJK corner brackets: 「 」 『 』
|
|
359
|
+
case 0x300c:
|
|
360
|
+
case 0x300d:
|
|
361
|
+
case 0x300e:
|
|
362
|
+
case 0x300f:
|
|
363
|
+
return true;
|
|
364
|
+
default:
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
250
367
|
}
|