11import type { Key , Layout } from '../src/layout'
2- import type { VirtualKeyboardClient , VirtualKeyboardEvent } from './api'
2+ import type { InputMethod , VirtualKeyboardClient , VirtualKeyboardEvent } from './api'
33import ArrowLeft from 'bundle-text:../svg/arrow-left.svg'
44import ArrowRight from 'bundle-text:../svg/arrow-right.svg'
55import CheckMark from 'bundle-text:../svg/checkmark.svg'
66import Enter from 'bundle-text:../svg/enter.svg'
77import Search from 'bundle-text:../svg/search.svg'
88import Send from 'bundle-text:../svg/send.svg'
9+ import { showContextmenu } from './contextmenu'
910import { setDisplayMode } from './display'
1011import { renderRow } from './key'
1112import { getContainer , getKey , press , release } from './util'
@@ -19,9 +20,12 @@ let shiftReleased = true
1920let keyPressedWithShiftPressed = false
2021let enterKeyType = ''
2122let spaceKeyLabel = ''
23+ let inputMethods_ : InputMethod [ ] = [ ]
2224let pendingTouch : Touch | null = null
2325const touches : { [ key : number ] : Touch } = { }
2426let startX = 0
27+ let startY = 0
28+ let longPressId : number | null = null
2529let lastX = 0
2630// We assume only one key can slide at a time, and another touch suspends it.
2731let slidingKey : Key | null = null
@@ -30,6 +34,22 @@ let completedSteps = 0
3034const slideStep = 10
3135
3236const DOUBLE_TAP_INTERVAL = 300 // Same with f5a.
37+ const LONG_PRESS_THRESHOLD = 500
38+ const DRAG_THRESHOLD = 10
39+
40+ function dragged ( touch : Touch ) {
41+ const { clientX, clientY } = touch
42+ const dX = clientX - startX
43+ const dY = clientY - startY
44+ return dX * dX + dY * dY > DRAG_THRESHOLD
45+ }
46+
47+ function cancelLongPress ( ) {
48+ if ( longPressId ) {
49+ clearTimeout ( longPressId )
50+ longPressId = null
51+ }
52+ }
3353
3454export function setLayout ( layout : Layout ) {
3555 layout_ = layout
@@ -143,9 +163,11 @@ function touchUp(touch: Touch) {
143163export function onTouchStart ( event : TouchEvent ) {
144164 const touch = event . changedTouches [ 0 ]
145165 startX = touch . clientX
166+ startY = touch . clientY
146167 lastX = startX
147168 resetSlide ( )
148- const key = getKey ( getContainer ( touch ) )
169+ let container = getContainer ( touch )
170+ const key = getKey ( container )
149171 if ( key ) {
150172 slidingKey = key
151173 if ( pendingTouch ) {
@@ -158,15 +180,30 @@ export function onTouchStart(event: TouchEvent) {
158180 else {
159181 pendingTouch = touch
160182 }
183+ if ( key . type === 'globe' ) {
184+ longPressId = window . setTimeout ( ( ) => {
185+ longPressId = null
186+ pendingTouch = null
187+ showContextmenu ( container ! , inputMethods_ . map ( inputMethod => ( {
188+ text : inputMethod . displayName ,
189+ callback ( ) { sendEvent ( { type : 'SET_INPUT_METHOD' , data : inputMethod . name } ) } ,
190+ } ) ) )
191+ } , LONG_PRESS_THRESHOLD )
192+ }
161193 }
162194 // Must recalculate container as layer may have been changed.
163- const container = getContainer ( touch )
195+ container = getContainer ( touch )
164196 container && press ( container )
165197 touches [ touch . identifier ] = touch
166198}
167199
168200export function onTouchMove ( event : TouchEvent ) {
169201 const touch = event . changedTouches [ 0 ]
202+ // If same touch of startX/Y, great.
203+ // If comparing with a more recent touch, we don't care if it's cancelled or not.
204+ if ( dragged ( touch ) ) {
205+ cancelLongPress ( )
206+ }
170207 const { clientX } = touch
171208 if ( [ 'space' , 'backspace' ] . includes ( slidingKey ?. type ?? '' ) ) {
172209 if ( ( clientX - lastX ) * ( clientX - startX ) < 0 ) { // turn around
@@ -194,6 +231,7 @@ export function onTouchMove(event: TouchEvent) {
194231}
195232
196233export function onTouchEnd ( event : TouchEvent ) {
234+ cancelLongPress ( )
197235 if ( slidingKey ) {
198236 if ( slidingKey . type === 'backspace' && slid ) {
199237 sendEvent ( { type : 'BACKSPACE_SLIDE' , data : 'RELEASE' } )
@@ -266,3 +304,13 @@ export function setSpaceKeyLabel(label: string) {
266304 space . innerHTML = spaceKeyLabel
267305 }
268306}
307+
308+ export function setInputMethods ( inputMethods : InputMethod [ ] , currentInputMethod : string ) {
309+ inputMethods_ = inputMethods
310+ for ( const inputMethod of inputMethods ) {
311+ if ( inputMethod . name === currentInputMethod ) {
312+ setSpaceKeyLabel ( inputMethod . displayName )
313+ break
314+ }
315+ }
316+ }
0 commit comments