Skip to content

Commit 816ff6b

Browse files
authored
Merge pull request #6 from siropkin/develop
v1.1.0 Enhance keyboard layout detection, refine default language setting, and update Gradle to 8.9
2 parents 5b5f202 + 8e2ef95 commit 816ff6b

File tree

9 files changed

+205
-144
lines changed

9 files changed

+205
-144
lines changed

CHANGELOG.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@
44

55
## [1.1.0] - 2024-07-19
66
### Changed
7-
- Add "Use Keyboard Layout" setting to determine the language based on the keyboard layout
8-
- Update Gradle to 8.9
7+
- Improved keyboard layout detection across different operating systems, ensuring more accurate language tracking.
8+
- Transitioned the "Default Language" setting from a ComboBox component to an Input component, allowing for custom default language input and enhancing flexibility beyond pre-filled options.
9+
- Added "Detect Keyboard Layout" button to the settings page, enabling users to manually detect their keyboard layout and update the default language accordingly.
10+
11+
### For Contributors and Developers
12+
- Updated Gradle to version 8.9 to align with the latest development practices and ensure compatibility.
13+
914

1015
## [1.0.5] - 2023-12-07
1116
### Changed

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*IntelliJ plugin for tracking keyboard language*
88

99
[![Rating](https://img.shields.io/jetbrains/plugin/r/stars/22072?style=flat-square)](https://plugins.jetbrains.com/plugin/22072-kursor)
10-
[![Downloads](https://img.shields.io/jetbrains/plugin/d/22072-kursor.svg?style=flat-square)](https://plugins.jetbrains.com/embeddable/install/22072)
10+
[![Downloads](https://img.shields.io/jetbrains/plugin/d/22072-kursor.svg?style=flat-square)](https://plugins.jetbrains.com/plugin/22072-kursor)
1111
[![Version](https://img.shields.io/jetbrains/plugin/v/22072-kursor.svg?style=flat-square)](https://plugins.jetbrains.com/plugin/22072-kursor)
1212

1313
![Kursor Demo](./screenshots/demo.png)
@@ -35,7 +35,6 @@ Alternatively, you can install it directly inside your IDE:
3535
![Settings Screenshot](./screenshots/settings.png)
3636

3737
- **Default Language:** The default language for your IDE.
38-
- **Use Keyboard Layout:** Determines the language based on the keyboard layout.
3938
- **Change Color on Non-Default Language:** Changes the cursor color if the language is not the default.
4039
- **Show Text Indicator:** Displays a language indicator on the cursor. If disabled, only the cursor color will be changed.
4140
- **Show Default Language:** Shows the default language on the cursor when enabled.
@@ -46,6 +45,17 @@ Alternatively, you can install it directly inside your IDE:
4645
- **Vertical Position:** Vertical position of the language indicator (top, middle, or bottom).
4746
- **Horizontal Offset:** Horizontal offset of the language indicator.
4847

48+
## Feedback and Suggestions
49+
50+
I value your feedback and suggestions to improve Kursor. If you have any ideas, issues, or feature requests, please share them with me on GitHub. Your input helps me make Kursor better for everyone.
51+
52+
To post your feedback or suggestions, visit our GitHub Issues page:
53+
54+
[https://github.com/siropkin/kursor/issues](https://github.com/siropkin/kursor/issues)
55+
56+
Thank you for supporting Kursor and helping me enhance your coding experience.
57+
58+
4959
## Support
5060

5161
[![Buy Me A Coffee](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/ivan.seredkin)

screenshots/settings.png

874 Bytes
Loading
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package com.github.siropkin.kursor
2+
3+
import java.awt.im.InputContext
4+
import java.io.BufferedReader
5+
import java.io.IOException
6+
7+
class KeyboardLayout(private val country: String, private val language: String) {
8+
override fun toString(): String = country.lowercase().ifEmpty { language.lowercase() }
9+
}
10+
11+
class KeyboardLayoutInfo {
12+
private val unknownCountry = "unk"
13+
private val unknownLanguage = ""
14+
15+
private val os: String = System.getProperty("os.name").lowercase()
16+
private var linuxDistribution: String = System.getenv("DESKTOP_SESSION")?.lowercase() ?: ""
17+
private var linuxDesktopGroup: String = System.getenv("XDG_SESSION_TYPE")?.lowercase() ?: ""
18+
private var linuxNonUbuntuKeyboardCountries: List<String> = emptyList()
19+
20+
fun getLayout(): KeyboardLayout {
21+
return when {
22+
os.startsWith("linux") -> getLinuxKeyboardLayout()
23+
os.startsWith("win") -> getWindowsKeyboardLayout()
24+
os.startsWith("mac") -> getMacKeyboardLayout()
25+
else -> KeyboardLayout(unknownCountry, unknownLanguage)
26+
}
27+
}
28+
29+
private fun getLinuxKeyboardLayout(): KeyboardLayout {
30+
// InputContext.getInstance().locale is not working on Linux: it always returns "en_US"
31+
// This is not the ideal solution because it involves executing a shell command to know the current keyboard layout
32+
// which might affect the performance. And we have different commands for different Linux distributions.
33+
// But it is the only solution I found that works on Linux.
34+
// For Linux we know only keyboard country and do not know keyboard language
35+
if (linuxDistribution == "ubuntu") {
36+
// output example: [('xkb', 'us'), ('xkb', 'ru'), ('xkb', 'ca+eng')]
37+
val split = executeNativeCommand(arrayOf("gsettings", "get", "org.gnome.desktop.input-sources", "mru-sources"))
38+
.substringAfter("('xkb', '")
39+
.substringBefore("')")
40+
.split("+")
41+
val country = split[0]
42+
val language = if (split.size > 1) split[1] else unknownLanguage
43+
return KeyboardLayout(country, language)
44+
}
45+
46+
if (linuxNonUbuntuKeyboardCountries.isEmpty()) {
47+
// output example: rules: evdev
48+
//model: pc105
49+
//layout: us
50+
//options: grp:win_space_toggle,terminate:ctrl_alt_bksp
51+
// FIXME: This command does not work on linuxDesktopGroup = "wayland", see: https://github.com/siropkin/kursor/issues/3
52+
linuxNonUbuntuKeyboardCountries = if (linuxDesktopGroup == "wayland") {
53+
executeNativeCommand(arrayOf("setxkbmap", "-query"))
54+
.substringAfter("layout:")
55+
.substringBefore("\n")
56+
.trim()
57+
.split(",")
58+
} else {
59+
executeNativeCommand(arrayOf("setxkbmap", "-query"))
60+
.substringAfter("layout:")
61+
.substringBefore("\n")
62+
.trim()
63+
.split(",")
64+
}
65+
}
66+
67+
// output example: Keyboard Control:
68+
// auto repeat: on key click percent: 0 LED mask: 00000000
69+
// XKB indicators:
70+
// 00: Caps Lock: off 01: Num Lock: off 02: Scroll Lock: off
71+
// 03: Compose: off 04: Kana: off 05: Sleep: off
72+
// 06: Suspend: off 07: Mute: off 08: Misc: off
73+
// 09: Mail: off 10: Charging: off 11: Shift Lock: off
74+
// 12: Group 2: off 13: Mouse Keys: off
75+
// auto repeat delay: 500 repeat rate: 33
76+
// auto repeating keys: 00ffffffdffffbbf
77+
// fadfffefffedffff
78+
// 9fffffffffffffff
79+
// fff7ffffffffffff
80+
// bell percent: 50 bell pitch: 400 bell duration: 100
81+
//Pointer Control:
82+
// acceleration: 2/1 threshold: 4
83+
//Screen Saver:
84+
// prefer blanking: yes allow exposures: yes
85+
// timeout: 0 cycle: 0
86+
//Colors:
87+
// default colormap: 0x20 BlackPixel: 0x0 WhitePixel: 0xffffff
88+
//Font Path:
89+
// /usr/share/fonts/X11/misc,/usr/share/fonts/X11/Type1,built-ins
90+
//DPMS (Energy Star):
91+
// Standby: 0 Suspend: 0 Off: 0
92+
// DPMS is Enabled
93+
// Monitor is On
94+
val linuxCurrentKeyboardCountryIndex = executeNativeCommand(arrayOf("xset", "-q"))
95+
.substringAfter("LED mask:")
96+
.substringBefore("\n")
97+
.trim()
98+
.substring(4, 5)
99+
.toInt(16)
100+
101+
// Additional check to avoid out of bounds exception
102+
if (linuxCurrentKeyboardCountryIndex >= linuxNonUbuntuKeyboardCountries.size) {
103+
return KeyboardLayout(unknownCountry, unknownLanguage)
104+
}
105+
106+
// This is a bad solution because it returns 0 if it's a default layout and 1 in other cases,
107+
// and if user has more than two layouts, we do not know which one is really on
108+
if (linuxNonUbuntuKeyboardCountries.size > 2 && linuxCurrentKeyboardCountryIndex > 0) {
109+
KeyboardLayout(unknownCountry, unknownLanguage)
110+
}
111+
112+
val country = linuxNonUbuntuKeyboardCountries[linuxCurrentKeyboardCountryIndex]
113+
return KeyboardLayout(country, unknownLanguage)
114+
}
115+
116+
private fun getMacKeyboardLayout(): KeyboardLayout {
117+
val locale = InputContext.getInstance().locale
118+
return KeyboardLayout(locale.country, locale.language)
119+
}
120+
121+
private fun getWindowsKeyboardLayout(): KeyboardLayout {
122+
val locale = InputContext.getInstance().locale
123+
return KeyboardLayout(locale.country, locale.language)
124+
}
125+
126+
private fun executeNativeCommand(command: Array<String>): String {
127+
return try {
128+
val process = Runtime.getRuntime().exec(command)
129+
process.waitFor()
130+
process.inputStream.bufferedReader().use(BufferedReader::readText)
131+
} catch (e: IOException) {
132+
e.printStackTrace()
133+
""
134+
}
135+
}
136+
}
137+

0 commit comments

Comments
 (0)