Skip to content

Commit

Permalink
Merge pull request #6 from siropkin/develop
Browse files Browse the repository at this point in the history
v1.1.0 Enhance keyboard layout detection, refine default language setting, and update Gradle to 8.9
  • Loading branch information
siropkin authored Jul 23, 2024
2 parents 5b5f202 + 8e2ef95 commit 816ff6b
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 144 deletions.
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@

## [1.1.0] - 2024-07-19
### Changed
- Add "Use Keyboard Layout" setting to determine the language based on the keyboard layout
- Update Gradle to 8.9
- Improved keyboard layout detection across different operating systems, ensuring more accurate language tracking.
- 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.
- Added "Detect Keyboard Layout" button to the settings page, enabling users to manually detect their keyboard layout and update the default language accordingly.

### For Contributors and Developers
- Updated Gradle to version 8.9 to align with the latest development practices and ensure compatibility.


## [1.0.5] - 2023-12-07
### Changed
Expand Down
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*IntelliJ plugin for tracking keyboard language*

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

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

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

## Feedback and Suggestions

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.

To post your feedback or suggestions, visit our GitHub Issues page:

[https://github.com/siropkin/kursor/issues](https://github.com/siropkin/kursor/issues)

Thank you for supporting Kursor and helping me enhance your coding experience.


## Support

[![Buy Me A Coffee](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/ivan.seredkin)
Binary file modified screenshots/settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
137 changes: 137 additions & 0 deletions src/main/kotlin/com/github/siropkin/kursor/KeyboardLayoutInfo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package com.github.siropkin.kursor

import java.awt.im.InputContext
import java.io.BufferedReader
import java.io.IOException

class KeyboardLayout(private val country: String, private val language: String) {
override fun toString(): String = country.lowercase().ifEmpty { language.lowercase() }
}

class KeyboardLayoutInfo {
private val unknownCountry = "unk"
private val unknownLanguage = ""

private val os: String = System.getProperty("os.name").lowercase()
private var linuxDistribution: String = System.getenv("DESKTOP_SESSION")?.lowercase() ?: ""
private var linuxDesktopGroup: String = System.getenv("XDG_SESSION_TYPE")?.lowercase() ?: ""
private var linuxNonUbuntuKeyboardCountries: List<String> = emptyList()

fun getLayout(): KeyboardLayout {
return when {
os.startsWith("linux") -> getLinuxKeyboardLayout()
os.startsWith("win") -> getWindowsKeyboardLayout()
os.startsWith("mac") -> getMacKeyboardLayout()
else -> KeyboardLayout(unknownCountry, unknownLanguage)
}
}

private fun getLinuxKeyboardLayout(): KeyboardLayout {
// InputContext.getInstance().locale is not working on Linux: it always returns "en_US"
// This is not the ideal solution because it involves executing a shell command to know the current keyboard layout
// which might affect the performance. And we have different commands for different Linux distributions.
// But it is the only solution I found that works on Linux.
// For Linux we know only keyboard country and do not know keyboard language
if (linuxDistribution == "ubuntu") {
// output example: [('xkb', 'us'), ('xkb', 'ru'), ('xkb', 'ca+eng')]
val split = executeNativeCommand(arrayOf("gsettings", "get", "org.gnome.desktop.input-sources", "mru-sources"))
.substringAfter("('xkb', '")
.substringBefore("')")
.split("+")
val country = split[0]
val language = if (split.size > 1) split[1] else unknownLanguage
return KeyboardLayout(country, language)
}

if (linuxNonUbuntuKeyboardCountries.isEmpty()) {
// output example: rules: evdev
//model: pc105
//layout: us
//options: grp:win_space_toggle,terminate:ctrl_alt_bksp
// FIXME: This command does not work on linuxDesktopGroup = "wayland", see: https://github.com/siropkin/kursor/issues/3
linuxNonUbuntuKeyboardCountries = if (linuxDesktopGroup == "wayland") {
executeNativeCommand(arrayOf("setxkbmap", "-query"))
.substringAfter("layout:")
.substringBefore("\n")
.trim()
.split(",")
} else {
executeNativeCommand(arrayOf("setxkbmap", "-query"))
.substringAfter("layout:")
.substringBefore("\n")
.trim()
.split(",")
}
}

// output example: Keyboard Control:
// auto repeat: on key click percent: 0 LED mask: 00000000
// XKB indicators:
// 00: Caps Lock: off 01: Num Lock: off 02: Scroll Lock: off
// 03: Compose: off 04: Kana: off 05: Sleep: off
// 06: Suspend: off 07: Mute: off 08: Misc: off
// 09: Mail: off 10: Charging: off 11: Shift Lock: off
// 12: Group 2: off 13: Mouse Keys: off
// auto repeat delay: 500 repeat rate: 33
// auto repeating keys: 00ffffffdffffbbf
// fadfffefffedffff
// 9fffffffffffffff
// fff7ffffffffffff
// bell percent: 50 bell pitch: 400 bell duration: 100
//Pointer Control:
// acceleration: 2/1 threshold: 4
//Screen Saver:
// prefer blanking: yes allow exposures: yes
// timeout: 0 cycle: 0
//Colors:
// default colormap: 0x20 BlackPixel: 0x0 WhitePixel: 0xffffff
//Font Path:
// /usr/share/fonts/X11/misc,/usr/share/fonts/X11/Type1,built-ins
//DPMS (Energy Star):
// Standby: 0 Suspend: 0 Off: 0
// DPMS is Enabled
// Monitor is On
val linuxCurrentKeyboardCountryIndex = executeNativeCommand(arrayOf("xset", "-q"))
.substringAfter("LED mask:")
.substringBefore("\n")
.trim()
.substring(4, 5)
.toInt(16)

// Additional check to avoid out of bounds exception
if (linuxCurrentKeyboardCountryIndex >= linuxNonUbuntuKeyboardCountries.size) {
return KeyboardLayout(unknownCountry, unknownLanguage)
}

// This is a bad solution because it returns 0 if it's a default layout and 1 in other cases,
// and if user has more than two layouts, we do not know which one is really on
if (linuxNonUbuntuKeyboardCountries.size > 2 && linuxCurrentKeyboardCountryIndex > 0) {
KeyboardLayout(unknownCountry, unknownLanguage)
}

val country = linuxNonUbuntuKeyboardCountries[linuxCurrentKeyboardCountryIndex]
return KeyboardLayout(country, unknownLanguage)
}

private fun getMacKeyboardLayout(): KeyboardLayout {
val locale = InputContext.getInstance().locale
return KeyboardLayout(locale.country, locale.language)
}

private fun getWindowsKeyboardLayout(): KeyboardLayout {
val locale = InputContext.getInstance().locale
return KeyboardLayout(locale.country, locale.language)
}

private fun executeNativeCommand(command: Array<String>): String {
return try {
val process = Runtime.getRuntime().exec(command)
process.waitFor()
process.inputStream.bufferedReader().use(BufferedReader::readText)
} catch (e: IOException) {
e.printStackTrace()
""
}
}
}

Loading

0 comments on commit 816ff6b

Please sign in to comment.