Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fcitx5-keyboard-web
44 changes: 42 additions & 2 deletions page/keyboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const hiddenBottom = 'max(calc(-200vw / 3), -50vh)'

export const hasTouch = /Android|iPhone|iPad|iPod/.test(navigator.userAgent)

function updateInput(input: HTMLInputElement | HTMLTextAreaElement, value: string, selectionStart?: number) {
function updateInput(input: HTMLInputElement | HTMLTextAreaElement, value: string, selectionStart: number) {
input.value = value
input.selectionStart = input.selectionEnd = selectionStart ?? value.length
input.dispatchEvent(new Event('change'))
Expand All @@ -24,17 +24,57 @@ function simulate(key: string, code: string) {
const preText = input.value.slice(0, caret)
const postText = input.value.slice(caret)
if (key) {
updateInput(input, preText + key + postText)
const pre = preText + key
updateInput(input, pre + postText, pre.length)
return
}
switch (code) {
case 'ArrowLeft':
if (preText) {
const indices = graphemeIndices(preText)
const selectionStart = indices[indices.length - 1]
updateInput(input, preText + postText, selectionStart)
}
break
case 'ArrowRight':
if (postText) {
const indices = graphemeIndices(postText)
const selectionStart = preText.length + (indices[1] ?? postText.length)
updateInput(input, preText + postText, selectionStart)
}
break
case 'Backspace':
if (preText) {
const indices = graphemeIndices(preText)
const selectionStart = indices[indices.length - 1]
updateInput(input, preText.slice(0, selectionStart) + postText, selectionStart)
}
break
case 'End':
if (postText) {
let end = postText.length
for (const index of graphemeIndices(postText)) {
if (postText[index] === '\n') {
end = index
break
}
}
updateInput(input, preText + postText, preText.length + end)
}
break
case 'Home':
if (preText) {
const indices = graphemeIndices(preText)
let start = 0
for (const index of indices.reverse()) {
if (preText[index] === '\n') {
start = index + 1
break
}
}
updateInput(input, preText + postText, start)
}
break
}
}

Expand Down
74 changes: 74 additions & 0 deletions tests/test-simulate.mobile.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,80 @@
import type { Locator, Page } from '@playwright/test'
import { expect, test } from '@playwright/test'
import { expectKeyboardShown, init, tapKeyboard } from './util'

function openEditor(page: Page) {
return page.locator('.fcitx-keyboard-toolbar-button:nth-child(3)').tap()
}

function getSelection(locator: Locator): Promise<[number, number]> {
return locator.evaluate((el: HTMLTextAreaElement) => [el.selectionStart, el.selectionEnd])
}

test('Printable', async ({ page }) => {
await init(page)
const textarea = page.locator('textarea')
await textarea.tap()
await expectKeyboardShown(page)
await textarea.evaluate((el: HTMLTextAreaElement) => {
el.value = 'ad'
el.selectionStart = el.selectionEnd = 1
})

await tapKeyboard(page, 'b!')
await tapKeyboard(page, 'c;')
await expect(textarea, 'selectionStart is not reset to the end').toHaveValue('abcd')
})

test('ArrowLeft and ArrowRight', async ({ page }) => {
await init(page)

const textarea = page.locator('textarea')
await textarea.tap()
await expectKeyboardShown(page)
await textarea.evaluate((el: HTMLTextAreaElement) => {
el.value = '左🦨右'
el.selectionStart = el.selectionEnd = 3
})
await openEditor(page)

const left = page.locator('.fcitx-keyboard-editor-button-container:nth-child(1)')
const right = page.locator('.fcitx-keyboard-editor-button-container:nth-child(3)')
await left.tap()
expect(await textarea.evaluate((el: HTMLTextAreaElement) => [el.selectionStart, el.selectionEnd])).toEqual([1, 1])

await right.tap()
expect(await getSelection(textarea)).toEqual([3, 3])
await right.tap()
expect(await getSelection(textarea)).toEqual([4, 4])
})

test('Home and End', async ({ page }) => {
await init(page)
const textarea = page.locator('textarea')
await textarea.tap()
await expectKeyboardShown(page)
await textarea.evaluate((el: HTMLTextAreaElement) => {
el.value = 'ab\ncd'
el.selectionStart = el.selectionEnd = 1
})
await openEditor(page)

const home = page.locator('.fcitx-keyboard-editor-button-container:nth-child(10)')
const end = page.locator('.fcitx-keyboard-editor-button-container:nth-child(11)')
await end.tap()
expect(await getSelection(textarea)).toEqual([2, 2])
await home.tap()
expect(await getSelection(textarea)).toEqual([0, 0])

await textarea.evaluate((el: HTMLTextAreaElement) => {
el.selectionStart = el.selectionEnd = 4
})
await end.tap()
expect(await getSelection(textarea)).toEqual([5, 5])
await home.tap()
expect(await getSelection(textarea)).toEqual([3, 3])
})

test('Backspace', async ({ page }) => {
await init(page)

Expand Down
Loading