From 72c45be7c4b525b217cb782a7a983b05637c9ae1 Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Sat, 5 Oct 2024 19:28:16 +0900 Subject: [PATCH] inline input support --- src/KeyHandler.ts | 26 +++++++++++++++++++++++--- src/frame.ts | 18 +++++++++++++++--- src/index.html | 15 +++++++++++---- src/renderer.ts | 12 +++++++++++- 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/KeyHandler.ts b/src/KeyHandler.ts index 57d47d71..cbebf16f 100644 --- a/src/KeyHandler.ts +++ b/src/KeyHandler.ts @@ -5,10 +5,13 @@ import { isChrome } from "./utils/utils"; export class KeyHandler extends EventEmitter<"input", (s: string) => void> { private currentMode : NvimMode; + private isComposing : boolean; + private lastCursorPosition : { x: number, y: number }; constructor(private elem: HTMLElement, settings: GlobalSettings) { super(); const ignoreKeys = settings.ignoreKeys; this.elem.addEventListener("keydown", (evt) => { + this.moveTo(this.lastCursorPosition.x, this.lastCursorPosition.y, "cursor"); // This is a workaround for osx where pressing non-alphanumeric // characters like "@" requires pressing , which results // in the browser sending an event, which we want to @@ -87,7 +90,11 @@ export class KeyHandler extends EventEmitter<"input", (s: string) => void> { // Firefox. /* istanbul ignore next */ if (isChrome()) { + this.elem.addEventListener("compositionstart", (e: CompositionEvent) => { + this.isComposing = true; + }); this.elem.addEventListener("compositionend", (e: CompositionEvent) => { + this.isComposing = false; acceptInput(e); }); } @@ -97,9 +104,22 @@ export class KeyHandler extends EventEmitter<"input", (s: string) => void> { this.elem.focus(); } - moveTo(x: number, y: number) { - this.elem.style.left = `${x}px`; - this.elem.style.top = `${y}px`; + moveTo(x: number, y: number, eventSource: string) { + if (eventSource === "cursor") { + this.lastCursorPosition = { x, y }; + } + if (!this.isComposing) { + this.elem.style.left = `${x}px`; + this.elem.style.top = `${y}px`; + } + } + + resizeHeight(height: number) { + this.elem.style.height = `${height}px`; + } + + changeColor(foregroundColor: string) { + this.elem.style.color = foregroundColor; } setMode(s: NvimMode) { diff --git a/src/frame.ts b/src/frame.ts index f74ea0f6..449b97ae 100644 --- a/src/frame.ts +++ b/src/frame.ts @@ -1,6 +1,6 @@ import { KeyHandler } from "./KeyHandler"; import { getGlobalConf, confReady, getConfForUrl, NvimMode } from "./utils/configuration"; -import { getGridId, getLogicalSize, computeGridDimensionsFor, getGridCoordinates, events as rendererEvents } from "./renderer"; +import { getGridId, getLogicalSize, computeGridDimensionsFor, getGridCoordinates, getInitialState, events as rendererEvents } from "./renderer"; import { getPageProxy } from "./page"; import { neovim } from "./Neovim"; import { toFileName } from "./utils/utils"; @@ -65,7 +65,7 @@ export const isReady = browser resizeReqId = id; // We need to put the keyHandler at the origin in order to avoid // issues when it slips out of the viewport - keyHandler.moveTo(0, 0); + keyHandler.moveTo(0, 0, 'mouse'); // It's tempting to try to optimize this by only calling // ui_try_resize when nCols is different from cols and nRows is // different from rows but we can't because redraw notifications @@ -144,8 +144,20 @@ export const isReady = browser delete canvas.oncontextmenu; mouseEnabled = false; }); + const state = getInitialState(); + keyHandler.resizeHeight(state.height); + rendererEvents.on("resize", ([grid, width, height]: any) => { + keyHandler.resizeHeight(height); + }); + keyHandler.changeColor(state.foregroundColor); + rendererEvents.on("colorChange", ({ background, foreground }: any) => { + keyHandler.changeColor(foreground); + }); + rendererEvents.on("moveCursor", (e: any) => { + keyHandler.moveTo(e.x, e.y, 'cursor'); + }); window.addEventListener("mousemove", (evt: MouseEvent) => { - keyHandler.moveTo(evt.clientX, evt.clientY); + keyHandler.moveTo(evt.clientX, evt.clientY, 'mouse'); }); function onMouse(evt: MouseEvent, action: string) { if (!mouseEnabled) { diff --git a/src/index.html b/src/index.html index e36f6b1d..17420036 100644 --- a/src/index.html +++ b/src/index.html @@ -9,15 +9,22 @@ padding: 0px; overflow: hidden; } - #keyhandler { - height: 1px; - opacity: 0.01; + #firevim_container { + width: 100%; + height: 100%; + position: relative; overflow: hidden; + } + #keyhandler { + width: 100%; + background-color: transparent; outline: none; border: none; + resize: none; position: absolute; margin: 0px; padding: 0px; + z-index: 1; } #canvas { position: absolute; @@ -29,5 +36,5 @@ - + diff --git a/src/renderer.ts b/src/renderer.ts index 90f80d06..efcca0c9 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -6,7 +6,7 @@ type ResizeEvent = {grid: number, width: number, height: number}; type FrameResizeEvent = {width: number, height: number} type ModeChangeEvent = NvimMode; type ResizeEventHandler = (e: ResizeEvent | FrameResizeEvent | ModeChangeEvent) => void; -type EventKind = "colorChange" | "resize" | "frameResize" | "modeChange" | "mouseOn" | "mouseOff"; +type EventKind = "colorChange" | "resize" | "frameResize" | "modeChange" | "mouseOn" | "mouseOff" | "moveCursor"; export const events = new EventEmitter(); let glyphCache : any = {}; @@ -320,6 +320,14 @@ export function getGridCoordinates (x: number, y: number) { return [Math.floor(x * window.devicePixelRatio / cellWidth), Math.floor(y * window.devicePixelRatio / cellHeight)]; } +export function getInitialState() { + const [_, charHeight] = getGlyphInfo(globalState); + return { + foregroundColor: globalState.highlights[0].foreground, + height: charHeight, + } +} + function newHighlight (bg: string, fg: string): HighlightInfo { return { background: bg, @@ -873,6 +881,7 @@ function paintCommandlineWindow(state: State) { } } ctx.fillRect(x + cursorX, y, 1, charHeight); + events.emit("moveCursor", { x: x + cursorX, y: y }); } function paint (_: DOMHighResTimeStamp) { @@ -1063,6 +1072,7 @@ function paint (_: DOMHighResTimeStamp) { : info.blinkoff - (relativeNow - info.blinkon); setTimeout(scheduleFrame, nextPaint); } + events.emit("moveCursor", { x: cursor.x * charWidth, y: cursor.y * charHeight }); } }