Home/Blog

Fixing the Enter key in an Obsidian AI plugin so that Japanese input stops sending by mistake

Seita Morooka

  • Obsidian
  • Claude
  • TypeScript
  • OSS
  • IME

Every day I use Claudian, a community plugin by Yishen Tu (MIT license) that lets you chat with Claude inside the note-taking app Obsidian.

The plugin has a UI where the AI asks you a question in multiple-choice form. You pick A, B or C, or you answer freely in an “Other” field. But in that “Other” field, when you type in Japanese, the Enter you press to confirm a conversion sends the answer itself. Japanese is typed through an input method (IME): you type the sounds, then press Enter to confirm the converted characters. The moment I confirmed the first few words of a sentence, those few half-written characters flew off as my answer. It was a small irritation every time I used it.

With a closed product, that would be the end of it: “so that is how it works”. But with a tool whose source is public, you can open it up and fix it. This post is the record of that, from diagnosis to fix to verification.

Getting the symptom right: “Enter sends it” was three problems

First I read the implementation of the UI in question (InlineAskUserQuestion.ts) and took the symptom apart. The complaint I had felt as one thing, “Enter sends by mistake”, was in fact three independent problems on top of each other.

// Before the fix: key handling while the input is focused (summary)
if (e.key === 'Tab' || e.key === 'Enter') {
  e.preventDefault();
  this.isInputFocused = false;
  activeElement?.blur();
  this.switchTab(this.activeTabIndex + 1); // unconditionally "confirm the answer → next question"
}
  1. Enter always meant “confirm”: the code looked at no modifier key and no setting. Enter always confirmed the answer and moved to the next question
  2. You could not type a line break at all: the field was a single-line <input type="text">, so even with different Enter behavior, a multi-line answer was physically impossible
  3. Enter during IME conversion was not told apart: key events carry a flag, isComposing, that says “a conversion is in progress right now”, and the code did not look at it. The Enter that confirms a conversion and the Enter that sends were treated as the same

What is interesting is that the main chat input of this plugin already has a setting, “require Cmd/Ctrl+Enter to send”, and it handles the IME correctly. So the author understands the problem. Only the multiple-choice UI had been left behind by that design.

The plan for the fix: do not invent new behavior

I think the worst thing you can do in a modification is add private rules of your own. The plan this time was a single point: “tie the multiple-choice UI to the existing setting of the main chat”.

  • If “require Cmd/Ctrl+Enter to send” is ON: Enter is a line break, and Cmd/Ctrl+Enter confirms the answer
  • If it is OFF: Enter confirms as before (Shift+Enter is a line break)
  • Enter during IME conversion is always ignored, whatever the setting

For the implementation, I replaced the field with a <textarea> that grows in height automatically, and changed the key check like this.

if (e.key === 'Enter') {
  // Enter during IME conversion confirms the conversion; it does not send
  if (e.isComposing) return;

  const hasCommitModifier = Platform.isMacOS
    ? e.metaKey && !e.ctrlKey && !e.altKey
    : e.ctrlKey && !e.metaKey && !e.altKey;

  // With the setting ON, Enter without a modifier passes through as a line break
  if (this.config.requireModifierToCommit ? !hasCommitModifier : e.shiftKey) return;
}
// Past this point: confirm the answer and go to the next question

One exception: secret input asked in password form cannot be a <textarea> (masking does not work there), so I left it as the original single-line input. Not changing everything uniformly is a design decision too.

Verification: add tests without breaking tests

The plugin had 61 existing unit tests. Verifying a modification means both “break none of the existing ones” and “turn the new behavior itself into tests”.

  • “With the setting ON, plain Enter does not confirm the answer”
  • “Cmd+Enter confirms it”
  • “Enter during IME conversion does not confirm, whatever the setting”

I added six tests like these and confirmed that all 67 pass. The behavior of the Japanese IME is the very subject of this change, so it is worth fixing it in tests as insurance against regressions.

I also stepped into one trap. I put a style fix into styles.css at the root of the repository, and it vanished when I built. It turned out that this file is build output, generated by concatenating the CSS modules under src/style/. If you edit build output directly, the next build overwrites it. Telling source from build output is one of the first things to check when you touch someone else’s repository.

Summary: a tool is something you can fix, not only use

In line count, this change is not large. But the daily irritation of “my answer flies off every time I press Enter” is gone, and I can now write long answers in Japanese in the normal way. The more working with an AI becomes part of every day, the more this kind of friction in input adds up.

  • Take the symptom apart (the “sending by mistake” was three independent problems)
  • Bring the fix in line with the existing design (do not invent private rules)
  • Fix the verification in tests (61 existing, 6 new)

This modification has sequels: the big rebuild, where I remade the whole tab UI, and running a fork, on how to keep modifications like these alive.

At oobe I take on changes that close “the last small gap” in off-the-shelf tools, and I set up AI-assisted work environments that fit how a business works. If small complaints about a tool you use have been piling up, write to me through the contact form.

All posts

Write with whatever is decided so far

What you want to build, your budget, your timing. Only the parts you already know are enough.

Contact