@@ -30,6 +30,9 @@ type Press = {
3030 alts : HTMLButtonElement [ ] ;
3131 selectedIndex : number ;
3232 committed : boolean ;
33+ committedChar : string | null ;
34+ upperAtDown : boolean ;
35+ controller : AbortController ;
3336} ;
3437
3538const DEFAULT_LOCALE : Locale = "en" ;
@@ -182,16 +185,14 @@ export class VirtualKeyboard extends HTMLElement {
182185
183186 this . #controller = new AbortController ( ) ;
184187 const { signal } = this . #controller;
185- const swallowFocus = ( e : Event ) : void => e . preventDefault ( ) ;
186188 const swallowFocusUnlessTopbar = ( e : Event ) : void => {
187189 const target = e . target as HTMLElement | null ;
188190 if ( target ?. closest ( ".topbar" ) ) return ;
189191 e . preventDefault ( ) ;
190192 } ;
191193 const host = this . #root. querySelector ( ".vk" ) ;
192- host ?. addEventListener ( "pointerdown" , swallowFocus , { signal } ) ;
193- host ?. addEventListener ( "mousedown" , swallowFocus , { signal } ) ;
194- host ?. addEventListener ( "touchstart" , swallowFocusUnlessTopbar , { passive : false , signal } ) ;
194+ host ?. addEventListener ( "pointerdown" , swallowFocusUnlessTopbar , { signal } ) ;
195+ host ?. addEventListener ( "mousedown" , swallowFocusUnlessTopbar , { signal } ) ;
195196 this . #renderTopbar( ) ;
196197 this . #attachDragScroll( this . #root. querySelector ( ".topbar" ) as HTMLElement ) ;
197198 this . #render( ) ;
@@ -466,7 +467,6 @@ export class VirtualKeyboard extends HTMLElement {
466467 const signal = this . #controller! . signal ;
467468 if ( hasAlts ) {
468469 btn . addEventListener ( "pointerdown" , ( e ) => this . #onPointerDown( e , key , btn ) , { signal } ) ;
469- btn . addEventListener ( "pointermove" , ( e ) => this . #onPointerMove( e ) , { signal } ) ;
470470 btn . addEventListener ( "pointerup" , ( e ) => this . #onPointerUp( e ) , { signal } ) ;
471471 btn . addEventListener ( "pointercancel" , ( ) => this . #cancelPress( ) , { signal } ) ;
472472 } else if ( isRepeatableKey ( key ) ) {
@@ -505,6 +505,22 @@ export class VirtualKeyboard extends HTMLElement {
505505 return ;
506506 }
507507 btn . setPointerCapture ( e . pointerId ) ;
508+
509+ const upperAtDown = this . #state. shift !== "off" && this . #state. layer === "letters" ;
510+ let committedChar : string | null = null ;
511+ if ( key . action . kind === "char" && this . #state. modifiers . size === 0 ) {
512+ committedChar = upperAtDown ? key . action . value . toUpperCase ( ) : key . action . value ;
513+ this . #emit( committedChar ) ;
514+ if ( this . #state. shift === "on" ) {
515+ this . #state. shift = "off" ;
516+ this . #applyShiftState( ) ;
517+ }
518+ }
519+
520+ const controller = new AbortController ( ) ;
521+ btn . addEventListener ( "pointermove" , ( ev ) => this . #onPointerMove( ev ) , {
522+ signal : controller . signal ,
523+ } ) ;
508524 const press : Press = {
509525 key,
510526 button : btn ,
@@ -513,7 +529,10 @@ export class VirtualKeyboard extends HTMLElement {
513529 popover : null ,
514530 alts : [ ] ,
515531 selectedIndex : 0 ,
516- committed : false ,
532+ committed : committedChar !== null ,
533+ committedChar,
534+ upperAtDown,
535+ controller,
517536 } ;
518537 press . timer = window . setTimeout ( ( ) => this . #openPopover( ) , this . #longPressMs) ;
519538 this . #press = press ;
@@ -539,13 +558,23 @@ export class VirtualKeyboard extends HTMLElement {
539558 p . timer = null ;
540559 }
541560 if ( p . popover ) {
542- const alts = p . key . alternates ?? [ ] ;
543- const choice = alts [ p . selectedIndex ] ?? p . key . label ;
544- this . #emitChar( choice ) ;
561+ const chosen = p . key . alternates ?. [ p . selectedIndex ] ;
562+ if ( chosen !== undefined ) {
563+ const alternative = p . upperAtDown ? chosen . toUpperCase ( ) : chosen ;
564+ if ( p . committed ) {
565+ if ( alternative !== p . committedChar ) {
566+ this . #adapter. execute ( { kind : "backspace" } ) ;
567+ this . #emit( alternative ) ;
568+ }
569+ } else {
570+ this . #emitChar( chosen ) ;
571+ }
572+ }
545573 this . #closePopover( ) ;
546574 } else if ( ! p . committed ) {
547575 this . #handle( p . key ) ;
548576 }
577+ p . controller . abort ( ) ;
549578 this . #press = null ;
550579 }
551580
@@ -554,14 +583,15 @@ export class VirtualKeyboard extends HTMLElement {
554583 if ( ! p ) return ;
555584 if ( p . timer !== null ) clearTimeout ( p . timer ) ;
556585 if ( p . popover ) this . #closePopover( ) ;
586+ p . controller . abort ( ) ;
557587 this . #press = null ;
558588 }
559589
560590 #openPopover( ) : void {
561591 const p = this . #press;
562592 if ( ! p || ! p . key . alternates ) return ;
563593 const alts = p . key . alternates ;
564- const upper = this . #state . shift !== "off" && this . #state . layer === "letters" ;
594+ const upper = p . upperAtDown ;
565595
566596 const popover = document . createElement ( "div" ) ;
567597 popover . className = "popover" ;
0 commit comments