DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

64511982lin-hash /

64511982lin-hash/dsh-swap-enter

Verified

Swap Enter and Shift+Enter in the DeepSeek Harness composer (Enter = newline, Shift+Enter = send).

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@059e59fd

dsh-swap-enter

Swaps Enter and Shift+Enter in the DeepSeek Harness chat composer.

  • Enter → inserts a newline
  • Shift+Enter → sends the message

Some chats (Feishu, Slack, Telegram) put the line break on the bare key and the send action on the modifier. DSH ships the other way around. This plugin flips it.

English | 中文

Install

From the plugin market (dsh-market, or any storefront built on the awesome-dsh-plugin index):

dsh plugin --profile <profile> add github:64511982lin-hash/dsh-swap-enter

Or point plugin_manager at a local checkout:

plugin_manager install_bundle { target: "<absolute path to this directory>" }

No build step, no runtime dependencies — the bundle is plain ES modules. The host half is a no-op; everything happens in the browser bundle.

After installing, reload the Web UI. There is nothing to configure.

What is left alone

Swapping two keys must not break the other things Enter does:

Situation Behavior
Suggestion or slash-command menu is open Untouched — Enter still picks the highlighted entry
IME composition in progress (Chinese, Japanese, Korean) Untouched — the composing keystroke never reaches the plugin
Ctrl/Cmd/Alt + Enter Untouched — the complementary shortcut keeps working
Composer is read-only Untouched
Focus is anywhere outside the composer Untouched
Plugin disposed (profile switched, HMR) Untouched — the shipped behavior returns

Holding Shift+Enter sends once, not once per repeat tick, because the auto-repeat flag is forwarded to the submit path.

Why this is a plugin and not a setting

There is no keybinding option to toggle. The client ui-conversation plugin's config schema has exactly one field — busyEnter (queue or steer) — and the fixed.send / fixed.newline entries visible in the keyboard-command registry are display records only: they describe the bindings to the settings UI and do not route the keypress.

The real behavior lives in two different code paths in the shipped composer:

  1. Shift+Enter is not handled in JavaScript at all. The composer's KEY_ENTER command returns false for shift+Enter and lets the browser's default action insert the line break.
  2. Bare Enter calls handlers.submit() from inside that command.

So a swap has to reproduce each path rather than flip a flag, and it cannot rely on one mechanism for both.

How it works

client.js installs a keydown listener on document in the capture phase, which runs before Lexical's listener on the editor root element. When a bare Enter arrives from inside [data-composer-input], it cancels the original event with preventDefault() + stopImmediatePropagation() and then replays the opposite path:

  • Shift+Enter (send) — dispatches a synthetic keydown with shiftKey: false, which re-runs the composer's own submit path, including its busy/steering rules.
  • Enter (newline) — dispatches a cancellable InputEvent('beforeinput', { inputType: 'insertLineBreak' }). Lexical's beforeinput handler inserts the break and cancels the event. A synthetic keydown with shiftKey: true would not work here: untrusted events have no default action, so the break would never be inserted.

Keys the plugin synthesized are tagged in a WeakSet so no listener instance — including a second one from a hot reload — can intercept them again.

Compatibility

  • Declared for dsh >=0.2.0-rc.1 <0.3.0-0.
  • Developed and verified against DSH 0.2.2-rc.1 (desktop build).
  • Web UI only (dsh.client.platform: "web").

The mechanism depends on the composer being a Lexical editor with the data-composer-input attribute and a beforeinput bridge — both true for the 0.2.x line. A future composer rewrite could change that.

Tests

node test/swap-enter.test.cjs

Eight cases run against the real client.js in a stub DOM that reproduces both composer paths:

PASS  Enter -> line break
PASS  Shift+Enter -> send
PASS  Ctrl+Enter untouched
PASS  menu open -> untouched
PASS  read-only -> untouched
PASS  IME composing -> untouched
PASS  outside composer -> untouched
PASS  after dispose -> shipped behavior

License

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit 059e59fdd34c

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout