Skip to content

Commit 2730bf7

Browse files
authored
caret blink (#42)
1 parent 9ba56c9 commit 2730bf7

5 files changed

Lines changed: 69 additions & 3 deletions

File tree

src/api.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export type SystemEvent = {
4141
data: {
4242
auxUp: string
4343
preedit: string
44+
caret: number
4445
}
4546
} | {
4647
type: 'CANDIDATES'

src/candidates.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,54 @@ function cancelLongPress() {
3232
}
3333
}
3434

35-
export function setPreedit(auxUp: string, preedit: string) {
35+
const textEncoder = new TextEncoder()
36+
const textDecoder = new TextDecoder()
37+
let timer: number | null = null
38+
let show = false
39+
40+
export function setPreedit(auxUp: string, preedit: string, caret: number) {
41+
if (timer) {
42+
clearInterval(timer)
43+
timer = null
44+
}
3645
const container = getCandidateBar().querySelector('.fcitx-keyboard-candidates-container')!
3746
let element = container.querySelector('.fcitx-keyboard-preedit')
3847
if (auxUp || preedit) {
3948
if (!element) {
4049
element = div('fcitx-keyboard-preedit')
4150
container.prepend(element)
4251
}
43-
element.innerHTML = auxUp + preedit
52+
element.innerHTML = ''
53+
if (auxUp) {
54+
const auxUpElement = div('fcitx-keyboard-aux-up')
55+
auxUpElement.innerHTML = auxUp
56+
element.appendChild(auxUpElement)
57+
}
58+
if (preedit) {
59+
const preCaretElement = div('fcitx-keyboard-pre-caret')
60+
if (caret >= 0) {
61+
const preeditBytes = textEncoder.encode(preedit)
62+
const preCaret = textDecoder.decode(preeditBytes.subarray(0, caret))
63+
const postCaret = textDecoder.decode(preeditBytes.subarray(caret, preeditBytes.length))
64+
preCaretElement.innerHTML = preCaret
65+
const caretElement = div('fcitx-keyboard-caret')
66+
element.append(preCaretElement, caretElement)
67+
show = true
68+
timer = window.setInterval(() => {
69+
show = !show
70+
caretElement.style.opacity = show ? '1' : '0'
71+
}, 500)
72+
if (postCaret) {
73+
const postCaretElement = div('fcitx-keyboard-post-caret')
74+
postCaretElement.innerHTML = postCaret
75+
element.appendChild(postCaretElement)
76+
}
77+
}
78+
else {
79+
preCaretElement.innerHTML = preedit
80+
element.appendChild(preCaretElement)
81+
}
82+
}
4483
}
4584
else {
4685
element?.remove()

src/keyboard.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export function onMessage(message: string) {
117117
removeCandidatesFromStack()
118118
break
119119
case 'PREEDIT':
120-
setPreedit(event.data.auxUp, event.data.preedit)
120+
setPreedit(event.data.auxUp, event.data.preedit, event.data.caret)
121121
break
122122
case 'CANDIDATES':
123123
setCandidates(event.data.candidates, event.data.highlighted, event.data.scrollState, event.data.scrollStart, event.data.scrollEnd)

src/preset.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,15 @@
143143
.fcitx-keyboard-preedit {
144144
height: 32cqh;
145145
font-size: 24cqh;
146+
line-height: 24cqh;
147+
display: flex;
148+
align-items: center;
149+
}
150+
151+
.fcitx-keyboard-caret {
152+
width: 1px;
153+
height: 24cqh;
154+
background-color: black;
146155
}
147156

148157
.fcitx-keyboard-candidates-container {

tests/test-candidates.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ test('Preedit', async ({ page }) => {
139139
await sendSystemEvent(page, { type: 'PREEDIT', data: {
140140
auxUp: 'Quick Phrase: ',
141141
preedit: 'vah',
142+
caret: -1,
142143
} })
143144
const preedit = page.locator('.fcitx-keyboard-preedit')
144145
await expect(preedit).toHaveText('Quick Phrase: vah')
@@ -157,6 +158,22 @@ test('Preedit', async ({ page }) => {
157158
expect(newBox, 'No layout shift').toEqual(box)
158159
})
159160

161+
test('Caret blink', async ({ page }) => {
162+
await init(page)
163+
164+
await sendSystemEvent(page, { type: 'PREEDIT', data: {
165+
auxUp: '',
166+
preedit: '🐦‍🔥she',
167+
caret: 13,
168+
} })
169+
await expect(page.locator('.fcitx-keyboard-pre-caret')).toHaveText('🐦‍🔥sh')
170+
await expect(page.locator('.fcitx-keyboard-post-caret')).toHaveText('e')
171+
const caret = page.locator('.fcitx-keyboard-caret')
172+
await expect(caret).toHaveCSS('opacity', '1')
173+
await expect(caret).toHaveCSS('opacity', '0')
174+
await expect(caret).toHaveCSS('opacity', '1')
175+
})
176+
160177
test('Horizontal scroll', async ({ page }) => {
161178
await init(page)
162179

0 commit comments

Comments
 (0)