An IntelliJ IDEA plugin that fixes text typed in the wrong keyboard layout (RU ↔ EN) with a single shortcut.
The project targets IntelliJ IDEA 2022.2.1 (IC-222.3739.54) and declares since-build = 222
with no upper bound, so it also loads in later IDEs.
- With a selection — converts the selected fragment.
- Without a selection — converts the word under the caret (a caret touching either edge of a word counts as being on it).
- Two-way conversion — the direction is derived from the text itself, so pressing the shortcut again converts the fragment back.
- Case and punctuation — the character mapping is built from physical keys including their Shift
states:
;↔ж,,↔б,?↔,,`↔ё,@↔",#↔№, and so on. - Multiple carets — every caret is handled in a single command.
- Ctrl+Z — the edit is wrapped in a
WriteCommandAction, so undo reverts it in one step.
| OS | Keystroke |
|---|---|
| Windows / Linux | Ctrl+Shift+R |
| macOS | Cmd+Shift+R |
The action is also available under Edit → Fix Keyboard Layout (RU/EN).
Heads-up: in the default keymap
Ctrl+Shift+Ris already bound to Replace in Files (andCmd+Shift+Ron macOS to Run…). The IDE will show a dialog to pick between the conflicting actions. To avoid it, rebind the shortcut under Settings → Keymap → Plugins → Keyboard Magic, or editkeyboard-shortcutinsrc/main/resources/META-INF/plugin.xml— for example toctrl alt shift R.
- JDK 17 — IDEA 2022.2 runs on Java 17. Any JDK 17 works, including the JetBrains Runtime
bundled with the IDE (
<IDEA install dir>/jbr). - Everything else (Gradle 8.5, Kotlin 1.9.25, gradle-intellij-plugin 1.17.4, the IntelliJ IDEA 2022.2.1 SDK) is fetched by Gradle.
If java is not on PATH, set JAVA_HOME before building:
$env:JAVA_HOME = "C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2022.2.1\jbr"# All tests: unit tests for the mapper and the word finder, plus integration tests that run the
# action in a real IDE editor (caret, selection, multiple carets, Ctrl+Z)
.\gradlew.bat test
# Build the plugin; the ZIP lands in build\distributions\
.\gradlew.bat buildPlugin
# Launch IDEA 2022.2.1 in a sandbox with the plugin installed
.\gradlew.bat runIde
# Check the plugin against the declared IDE version range
.\gradlew.bat verifyPlugin-
.\gradlew.bat runIde— a separate IDEA instance opens with the plugin; your real settings are untouched. -
Create any file and type
ghbdtn, vbh!in it. -
Put the caret on
ghbdtnand pressCtrl+Shift+R→ it becomesпривет. -
Press it again → back to
ghbdtn. -
Select the whole line and press
Ctrl+Shift+R→привет? мир!(the comma is
бin the Russian layout, while,comes from?— that is exactly how a per-character mapping built from physical keys is supposed to behave) -
Press
Ctrl+Z— the edit is reverted in one step.
.\gradlew.bat buildPluginThen in IDEA: Settings → Plugins → ⚙ → Install Plugin from Disk…, pick
build\distributions\keyboard-magic-1.0.0.zip, and restart the IDE.
src/main/kotlin/com/github/keyboardmagic/
├── LayoutService.kt # EN↔RU mapping and direction detection
├── WordFinder.kt # the word under the caret
└── LayoutConverterAction.kt # action, WriteCommandAction, multiple carets
src/main/resources/META-INF/plugin.xml
src/test/kotlin/com/github/keyboardmagic/
├── LayoutServiceTest.kt # mapping, direction detection, word finder (unit)
└── LayoutConverterActionTest.kt # the action in a real editor (BasePlatformTestCase)
LayoutService.KEY_ROWS holds rows of physical keys: the EN characters on the left and what the
same keys produce in the RU layout on the right. Every key contributes two pairs (unshifted and
shifted), which makes the tables a bijection and guarantees that converting twice returns the
original text — covered by the every mapped character round trips test.
The direction is picked in detectLayout: Cyrillic and Latin letters are counted and the majority
wins; a fragment without letters falls back to EN → RU.
A word is a run of letters, digits and underscores — punctuation is deliberately excluded, otherwise
end; would be converted together with its ;. For fragments where punctuation matters (,jkm →
боль), select the text explicitly.
Everything is driven from gradle.properties:
| Property | Value | Meaning |
|---|---|---|
platformType / platformVersion |
IC / 2022.2.1 |
which SDK to download |
platformLocalPath |
empty | path to an installed IDE instead of downloading |
pluginSinceBuild |
222 |
minimum IDE build |
pluginUntilBuild |
empty | no upper bound |
platformLocalPath only works when the installation directory is writable: gradle-intellij-plugin
drops an Ivy descriptor next to the IDE, which fails under C:\Program Files with "Could not write
to file". That is why the SDK is downloaded by default.
The code is compiled with apiVersion = 1.6 because IDEA 2022.2 ships the Kotlin 1.6 standard
library (lib/3rd-party-rt.jar) — the compiler then rejects any API the IDE could not run. To build
against a newer IDE, change platformVersion/pluginSinceBuild and raise
apiVersion/languageVersion in build.gradle.kts to the Kotlin version that platform ships.