Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/clukeyboard.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/AndroidManifest.xml29
-rw-r--r--app/src/main/java/com/clusterrr/hardwarekeyboard/KeyMapping.kt12
-rw-r--r--app/src/main/java/com/clusterrr/hardwarekeyboard/Keyboard.kt385
-rw-r--r--app/src/main/java/com/clusterrr/hardwarekeyboard/RusMapping.kt469
-rw-r--r--app/src/main/java/com/clusterrr/hardwarekeyboard/ScanCodes.kt196
-rw-r--r--app/src/main/res/drawable-v24/ic_launcher_foreground.xml34
-rw-r--r--app/src/main/res/drawable/ic_launcher_background.xml170
-rw-r--r--app/src/main/res/layout/keyboard_layout.xml48
-rw-r--r--app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml5
-rw-r--r--app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml5
-rw-r--r--app/src/main/res/mipmap-hdpi/ic_launcher.pngbin0 -> 2963 bytes
-rw-r--r--app/src/main/res/mipmap-hdpi/ic_launcher_round.pngbin0 -> 4905 bytes
-rw-r--r--app/src/main/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2060 bytes
-rw-r--r--app/src/main/res/mipmap-mdpi/ic_launcher_round.pngbin0 -> 2783 bytes
-rw-r--r--app/src/main/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4490 bytes
-rw-r--r--app/src/main/res/mipmap-xhdpi/ic_launcher_round.pngbin0 -> 6895 bytes
-rw-r--r--app/src/main/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 6387 bytes
-rw-r--r--app/src/main/res/mipmap-xxhdpi/ic_launcher_round.pngbin0 -> 10413 bytes
-rw-r--r--app/src/main/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 9128 bytes
-rw-r--r--app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.pngbin0 -> 15132 bytes
-rw-r--r--app/src/main/res/values/colors.xml9
-rw-r--r--app/src/main/res/values/strings.xml3
-rw-r--r--app/src/main/res/values/styles.xml10
-rw-r--r--app/src/main/res/xml/method.xml5
24 files changed, 1380 insertions, 0 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..22ec5f7
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.clusterrr.hardwarekeyboard">
+
+ <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:resizeableActivity="true"
+ android:theme="@style/AppTheme">
+
+ <service
+ android:name=".Keyboard"
+ android:enabled="true"
+ android:label="@string/app_name"
+ android:exported="true"
+ android:permission="android.permission.BIND_INPUT_METHOD">
+ <intent-filter>
+ <action android:name="android.view.InputMethod" />
+ </intent-filter>
+ <meta-data android:name="android.view.im"
+ android:resource="@xml/method" />
+ </service>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/app/src/main/java/com/clusterrr/hardwarekeyboard/KeyMapping.kt b/app/src/main/java/com/clusterrr/hardwarekeyboard/KeyMapping.kt
new file mode 100644
index 0000000..2007d84
--- /dev/null
+++ b/app/src/main/java/com/clusterrr/hardwarekeyboard/KeyMapping.kt
@@ -0,0 +1,12 @@
+package com.clusterrr.hardwarekeyboard
+
+open class KeyMapping {
+ var ReplaceKeyCode: Int = 0
+ var ReplaceScanCode: Int = 0
+ var AlternateKeyCode: Int = 0
+ var AlternateScanCode: Int = 0
+ var AlternateFix: Boolean = false
+ var Char: String? = null
+ var ShiftChar: String? = null
+ var IgnoreCapsLock: Boolean = false
+}
diff --git a/app/src/main/java/com/clusterrr/hardwarekeyboard/Keyboard.kt b/app/src/main/java/com/clusterrr/hardwarekeyboard/Keyboard.kt
new file mode 100644
index 0000000..2314440
--- /dev/null
+++ b/app/src/main/java/com/clusterrr/hardwarekeyboard/Keyboard.kt
@@ -0,0 +1,385 @@
+package com.clusterrr.hardwarekeyboard
+
+import android.inputmethodservice.InputMethodService
+import android.util.Log
+import android.view.KeyEvent
+import android.view.View
+import android.widget.CompoundButton
+import android.widget.Switch
+import android.widget.TextView
+import android.widget.Toast
+import java.util.ArrayList
+import android.provider.Settings
+import java.lang.Exception
+
+class Keyboard : InputMethodService(), View.OnClickListener, CompoundButton.OnCheckedChangeListener {
+ private val FN_KEY = ScanCodes.SCANCODE_SHOW_KEYBOARD
+ private val LANGUAGE_KEYS = arrayOf(
+ intArrayOf(ScanCodes.SCANCODE_LANGUAGE),
+ intArrayOf(ScanCodes.SCANCODE_SHIFT_LEFT, ScanCodes.SCANCODE_CTRL_LEFT)
+ )
+ private val FN_FIX_KEYS = arrayOf(
+ intArrayOf(ScanCodes.SCANCODE_SHOW_KEYBOARD, ScanCodes.SCANCODE_SPACE)
+ )
+ private val SHOW_HIDE_KEYS = arrayOf(intArrayOf(ScanCodes.SCANCODE_SHOW_KEYBOARD, ScanCodes.SCANCODE_TAB))
+ private val BRIGHTNESS_DOWN_KEYS = arrayOf(intArrayOf(ScanCodes.SCANCODE_SHOW_KEYBOARD, ScanCodes.SCANCODE_J))
+ private val BRIGHTNESS_UP_KEYS = arrayOf(intArrayOf(ScanCodes.SCANCODE_SHOW_KEYBOARD, ScanCodes.SCANCODE_K))
+ private val SCANCODE_ONLY_APPS = arrayOf("com.microsoft.rdc.android")
+
+ private var altLanguage = false
+ private var fnLock = false
+ private val keysPressed = ArrayList<Int>()
+ private var capsLock = false
+
+ internal var textViewLanguage: TextView? = null
+ internal var switchCapsLock: Switch? = null
+ internal var switchFnLock: Switch? = null
+
+ override fun onEvaluateFullscreenMode(): Boolean {
+ return false
+ }
+
+ override fun onCreateInputView(): View {
+ val inputView = layoutInflater.inflate(R.layout.keyboard_layout, null)
+ textViewLanguage = inputView.findViewById(R.id.textViewLanguage)
+ switchCapsLock = inputView.findViewById(R.id.switchCapsLock)
+ switchFnLock = inputView.findViewById(R.id.switchFnLock)
+ textViewLanguage!!.setOnClickListener(this)
+ switchCapsLock!!.setOnCheckedChangeListener(this)
+ switchFnLock!!.setOnCheckedChangeListener(this)
+ updateLangage()
+ updateFnFixSwitch()
+ updateCapsLockSwitch()
+ return inputView
+ }
+
+ private fun updateLangage(): String {
+ var languageName: String? = null
+ if (!altLanguage)
+ languageName = "EN"
+ else
+ languageName = "RU"
+ if (textViewLanguage != null)
+ textViewLanguage!!.text = languageName
+ return languageName
+ }
+
+ fun toggleLanguage() {
+ altLanguage = !altLanguage
+ val languageName = updateLangage()
+ Toast.makeText(this, languageName, Toast.LENGTH_SHORT).show()
+ }
+
+ private fun updateFnFixSwitch() {
+ if (switchFnLock == null)
+ return
+ if (switchFnLock!!.isChecked != fnLock) {
+ switchFnLock!!.setOnCheckedChangeListener(null)
+ switchFnLock!!.isChecked = fnLock
+ switchFnLock!!.setOnCheckedChangeListener(this)
+ }
+ }
+
+ fun toggleFnLock() {
+ if (!fnLock) {
+ fnLock = true
+ Toast.makeText(this, "FN lock: on", Toast.LENGTH_SHORT).show()
+ } else {
+ fnLock = false
+ Toast.makeText(this, "FN lock: off", Toast.LENGTH_SHORT).show()
+ }
+ updateFnFixSwitch()
+ }
+
+ private fun updateCapsLockSwitch() {
+ if (switchCapsLock == null)
+ return
+ if (switchCapsLock!!.isChecked != capsLock)
+ switchCapsLock!!.isChecked = capsLock
+ }
+
+ private fun shouldUseScanCodes(): Boolean {
+ val packageName = currentInputEditorInfo.packageName
+ return packageName in SCANCODE_ONLY_APPS
+ }
+
+ override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
+ Log.d("keyboard", " down key_code=" + event.keyCode
+ + ", scan_code=" + event.scanCode
+ + ", device_code=" + event.deviceId
+ + ", repeat=" + event.repeatCount
+ + ", shift=" + event.isShiftPressed
+ + ", ctrl=" + event.isCtrlPressed
+ + ", alt=" + event.isAltPressed
+ )
+
+ val scanCode = event.scanCode
+
+ // Hide keyboard on back
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ updateInputViewShown()
+ val current = isInputViewShown
+ if (current) {
+ requestHideSelf(0)
+ return true
+ }
+ }
+
+ if (scanCode <= 0 || event.deviceId <= 0)
+ return false
+
+ // Handle caps lock to show current status
+ if (scanCode == ScanCodes.SCANCODE_CAPS_LOCK) {
+ if (!keysPressed.contains(ScanCodes.SCANCODE_CAPS_LOCK)) {
+ capsLock = !event.isCapsLockOn
+ if (capsLock)
+ Toast.makeText(this, "Сaps Lock: ON", Toast.LENGTH_SHORT).show()
+ else
+ Toast.makeText(this, "Caps Lock: off", Toast.LENGTH_SHORT).show()
+ }
+ } else {
+ capsLock = event.isCapsLockOn
+ }
+ updateCapsLockSwitch()
+
+ // Toggle language
+ if (!shouldUseScanCodes() && checkCombinations(LANGUAGE_KEYS, scanCode)) {
+ keysPressed.add(scanCode) // do not repeat
+ toggleLanguage()
+ return true
+ }
+
+ // Toggle FN fix
+ if (checkCombinations(FN_FIX_KEYS, scanCode)) {
+ keysPressed.add(scanCode) // do not repeat
+ toggleFnLock()
+ return true
+ }
+
+ // Toggle GUI
+ if (checkCombinations(SHOW_HIDE_KEYS, scanCode)) {
+ keysPressed.add(scanCode) // do not repeat
+ toggleVisibility()
+ return true
+ }
+
+ if (checkCombinations(BRIGHTNESS_DOWN_KEYS, scanCode)) {
+ adjustBrightness(-5)
+ return true
+ }
+
+ if (checkCombinations(BRIGHTNESS_UP_KEYS, scanCode)) {
+ adjustBrightness(5)
+ return true
+ }
+
+ if (!keysPressed.contains(scanCode)) {
+ keysPressed.add(scanCode)
+ }
+
+ if (scanCode == FN_KEY) {
+ return true
+ }
+
+ // Get mapping for key
+ val key = mapping.getMapping(scanCode)
+ if (key != null) {
+
+ // Is the FN key hold?
+ if (keysPressed.contains(FN_KEY) xor (fnLock && key.AlternateFix)) {
+ // Does key has some FN-function?
+ if (key.AlternateScanCode != 0 || key.AlternateKeyCode != 0) {
+ sendKeyCode(event, key.AlternateKeyCode, key.AlternateScanCode)
+ return true
+ }
+ }
+
+ // Does the key have an alternative function?
+ if (key.ReplaceKeyCode != 0 || key.ReplaceScanCode != 0) {
+ sendKeyCode(event, key.ReplaceKeyCode, key.ReplaceScanCode)
+ return true
+ }
+
+ // Is it alternative language?
+ if (!shouldUseScanCodes() // Workaround for some apps: send scancode only
+ && altLanguage && !event.isAltPressed && !event.isCtrlPressed) {
+ val shift = event.isShiftPressed xor (event.isCapsLockOn && !key.IgnoreCapsLock)
+ var text: String? = null
+ if (!shift)
+ text = key.Char
+ else
+ text = key.ShiftChar
+ // Send keypresses as text
+ if (text != null) {
+ sendText(text)
+ return true
+ }
+ }
+
+ // Do not alter key function
+ }
+
+ // Workaround for some apps: send scancode only
+ if (shouldUseScanCodes()) {
+ sendScanCode(event)
+ return true
+ }
+
+ // Passthru this key without overrides
+ return false
+ }
+
+ override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
+ Log.d("keyboard", " up key_code=" + event.keyCode
+ + ", scan_code=" + event.scanCode
+ + ", device_code=" + event.deviceId
+ + ", repeat=" + event.repeatCount
+ + ", shift=" + event.isShiftPressed
+ + ", ctrl=" + event.isCtrlPressed
+ + ", alt=" + event.isAltPressed
+ )
+
+ val scanCode = event.scanCode
+
+ if (scanCode <= 0 || event.deviceId <= 0)
+ return false
+
+ if (keysPressed.contains(scanCode))
+ keysPressed.remove(scanCode)
+
+ if (scanCode == FN_KEY) {
+ return true
+ }
+
+ val key = mapping.getMapping(scanCode)
+ if (key != null) {
+
+ if (keysPressed.contains(FN_KEY) || fnLock && key.AlternateFix) {
+ if (key.AlternateScanCode != 0 || key.AlternateKeyCode != 0) {
+ sendKeyCode(event, key.AlternateKeyCode, key.AlternateScanCode)
+ return true
+ }
+ }
+
+ if (key.ReplaceKeyCode != 0 || key.ReplaceScanCode != 0) {
+ sendKeyCode(event, key.ReplaceKeyCode, key.ReplaceScanCode)
+ return true
+ }
+
+ if (shouldUseScanCodes()) {
+ sendScanCode(event)
+ return true
+ }
+
+ if (altLanguage && !event.isAltPressed && !event.isCtrlPressed) {
+ val shift = event.isShiftPressed xor (event.isCapsLockOn && !key.IgnoreCapsLock)
+ var text: String? = null
+ if (!shift)
+ text = key.Char
+ else
+ text = key.ShiftChar
+ if (text != null) {
+ //sendText(text);
+ return true
+ }
+ }
+
+ }
+
+ if (shouldUseScanCodes()) {
+ sendScanCode(event)
+ return true
+ }
+
+ return false
+ }
+
+ private fun checkCombinations(combinations: Array<IntArray>, scanCode: Int): Boolean {
+ for (c in combinations.indices) {
+ val combination = combinations[c]
+ if (combination.size - 1 != keysPressed.size)
+ continue
+ var matched = true
+ for (k in combination.indices) {
+ if (!(scanCode != combination[k] && keysPressed.contains(combination[k]) || scanCode == combination[k] && !keysPressed.contains(combination[k]))) {
+ matched = false
+ break
+ }
+ }
+ if (matched) {
+ if (keysPressed.contains(scanCode))
+ keysPressed.add(scanCode)
+ return true
+ }
+ }
+ return false
+ }
+
+ private fun sendKeyCode(sourceEvent: KeyEvent, keyCode: Int, scanCode: Int) {
+ var keyCode = keyCode
+ val ic = currentInputConnection
+
+ if (shouldUseScanCodes() && scanCode != 0)
+ keyCode = 0
+ val event = KeyEvent(sourceEvent.downTime, sourceEvent.eventTime, sourceEvent.action,
+ keyCode, sourceEvent.repeatCount, sourceEvent.metaState,
+ sourceEvent.deviceId, scanCode,
+ 0,
+ sourceEvent.source)
+ ic.sendKeyEvent(event)
+ }
+
+ private fun sendScanCode(sourceEvent: KeyEvent) {
+ val ic = currentInputConnection
+ val event = KeyEvent(sourceEvent.downTime, sourceEvent.eventTime, sourceEvent.action,
+ 0, sourceEvent.repeatCount, sourceEvent.metaState,
+ sourceEvent.deviceId, sourceEvent.scanCode,
+ 0,
+ sourceEvent.source)
+ ic.sendKeyEvent(event)
+ }
+
+ private fun sendText(text: String) {
+ val ic = currentInputConnection
+ ic.commitText(text, 1)
+ }
+
+ override fun onClick(v: View) {
+ when (v.id) {
+ R.id.textViewLanguage -> toggleLanguage()
+ }
+ }
+
+ override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
+ when (buttonView.id) {
+ R.id.switchCapsLock -> updateCapsLockSwitch()
+ R.id.switchFnLock -> toggleFnLock()
+ }
+ }
+
+ fun toggleVisibility() {
+ updateInputViewShown()
+ val current = isInputViewShown
+ if (!current)
+ requestShowSelf(0)
+ else
+ requestHideSelf(0)
+ }
+
+ private fun adjustBrightness(delta: Int) {
+ try {
+ var brightness = Settings.System.getInt(getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS, 0)
+ brightness += delta
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS, brightness);
+ }
+ catch (ex: Exception) {
+ ex.printStackTrace()
+ }
+ }
+
+ companion object {
+ private val mapping = RusMapping()
+ }
+}
diff --git a/app/src/main/java/com/clusterrr/hardwarekeyboard/RusMapping.kt b/app/src/main/java/com/clusterrr/hardwarekeyboard/RusMapping.kt
new file mode 100644
index 0000000..7038bbc
--- /dev/null
+++ b/app/src/main/java/com/clusterrr/hardwarekeyboard/RusMapping.kt
@@ -0,0 +1,469 @@
+package com.clusterrr.hardwarekeyboard
+
+import android.view.KeyEvent
+
+import java.util.HashMap
+
+class RusMapping {
+ internal var mapping: HashMap<Int, KeyMapping> = object : HashMap<Int, KeyMapping>() {
+ init {
+ put(ScanCodes.SCANCODE_GRAVE,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_ESCAPE
+ AlternateScanCode = ScanCodes.SCANCODE_ESCAPE
+ AlternateFix = true
+ Char = "ё"
+ ShiftChar = "Ё"
+ }
+ })
+ put(ScanCodes.SCANCODE_1,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_F1
+ AlternateScanCode = ScanCodes.SCANCODE_F1
+ AlternateFix = true
+ }
+ })
+ put(ScanCodes.SCANCODE_2,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_F2
+ AlternateScanCode = ScanCodes.SCANCODE_F2
+ AlternateFix = true
+ ShiftChar = "\""
+ IgnoreCapsLock = true
+ }
+ })
+ put(ScanCodes.SCANCODE_3,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_F3
+ AlternateScanCode = ScanCodes.SCANCODE_F3
+ AlternateFix = true
+ ShiftChar = "№"
+ IgnoreCapsLock = true
+ }
+ })
+ put(ScanCodes.SCANCODE_4,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_F4
+ AlternateScanCode = ScanCodes.SCANCODE_F4
+ AlternateFix = true
+ ShiftChar = ";"
+ IgnoreCapsLock = true
+ }
+ })
+ put(ScanCodes.SCANCODE_5,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_F5
+ AlternateScanCode = ScanCodes.SCANCODE_F5
+ AlternateFix = true
+ }
+ })
+ put(ScanCodes.SCANCODE_6,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_F6
+ AlternateScanCode = ScanCodes.SCANCODE_F6
+ AlternateFix = true
+ ShiftChar = ":"
+ IgnoreCapsLock = true
+ }
+ })
+ put(ScanCodes.SCANCODE_7,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_F7
+ AlternateScanCode = ScanCodes.SCANCODE_F7
+ AlternateFix = true
+ ShiftChar = "?"
+ IgnoreCapsLock = true
+ }
+ })
+ put(ScanCodes.SCANCODE_8,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_F8
+ AlternateScanCode = ScanCodes.SCANCODE_F8
+ AlternateFix = true
+ }
+ })
+ put(ScanCodes.SCANCODE_9,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_F9
+ AlternateScanCode = ScanCodes.SCANCODE_F9
+ AlternateFix = true
+ }
+ })
+ put(ScanCodes.SCANCODE_0,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_F10
+ AlternateScanCode = ScanCodes.SCANCODE_F10
+ AlternateFix = true
+ }
+ })
+ put(ScanCodes.SCANCODE_MINUS,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_F11
+ AlternateScanCode = ScanCodes.SCANCODE_F11
+ AlternateFix = true
+ }
+ })
+ put(ScanCodes.SCANCODE_EQUALS,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_F12
+ AlternateScanCode = ScanCodes.SCANCODE_F12
+ AlternateFix = true
+ }
+ })
+ put(ScanCodes.SCANCODE_Q,
+ object : KeyMapping() {
+ init {
+ Char = "й"
+ ShiftChar = "Й"
+ AlternateKeyCode = KeyEvent.KEYCODE_BACK
+ }
+ })
+ put(ScanCodes.SCANCODE_W,
+ object : KeyMapping() {
+ init {
+ Char = "ц"
+ ShiftChar = "Ц"
+ }
+ })
+ put(ScanCodes.SCANCODE_E,
+ object : KeyMapping() {
+ init {
+ Char = "у"
+ ShiftChar = "У"
+ }
+ })
+ put(ScanCodes.SCANCODE_R,
+ object : KeyMapping() {
+ init {
+ Char = "к"
+ ShiftChar = "К"
+ }
+ })
+ put(ScanCodes.SCANCODE_T,
+ object : KeyMapping() {
+ init {
+ Char = "е"
+ ShiftChar = "Е"
+ }
+ })
+ put(ScanCodes.SCANCODE_Y,
+ object : KeyMapping() {
+ init {
+ Char = "н"
+ ShiftChar = "Н"
+ }
+ })
+ put(ScanCodes.SCANCODE_U,
+ object : KeyMapping() {
+ init {
+ Char = "г"
+ ShiftChar = "Г"
+ }
+ })
+ put(ScanCodes.SCANCODE_I,
+ object : KeyMapping() {
+ init {
+ Char = "ш"
+ ShiftChar = "Ш"
+ }
+ })
+ put(ScanCodes.SCANCODE_O,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_NUMPAD_SUBTRACT
+ AlternateScanCode = ScanCodes.SCANCODE_NUMPAD_SUBTRACT
+ AlternateFix = false
+ Char = "щ"
+ ShiftChar = "Щ"
+ }
+ })
+ put(ScanCodes.SCANCODE_P,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_NUMPAD_ADD
+ AlternateScanCode = ScanCodes.SCANCODE_NUMPAD_ADD
+ AlternateFix = false
+ Char = "з"
+ ShiftChar = "З"
+ }
+ })
+ put(ScanCodes.SCANCODE_LEFT_BRACKET,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_NUMPAD_DIVIDE
+ AlternateScanCode = ScanCodes.SCANCODE_NUMPAD_DIVIDE
+ AlternateFix = false
+ Char = "х"
+ ShiftChar = "Х"
+ }
+ })
+ put(ScanCodes.SCANCODE_RIGHT_BRACKET,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_NUMPAD_MULTIPLY
+ AlternateScanCode = ScanCodes.SCANCODE_NUMPAD_MULTIPLY
+ AlternateFix = false
+ Char = "ъ"
+ ShiftChar = "Ъ"
+ }
+ })
+ put(ScanCodes.SCANCODE_A,
+ object : KeyMapping() {
+ init {
+ Char = "ф"
+ ShiftChar = "Ф"
+ }
+ })
+ put(ScanCodes.SCANCODE_S,
+ object : KeyMapping() {
+ init {
+ Char = "ы"
+ ShiftChar = "Ы"
+ }
+ })
+ put(ScanCodes.SCANCODE_D,
+ object : KeyMapping() {
+ init {
+ Char = "в"
+ ShiftChar = "В"
+ }
+ })
+ put(ScanCodes.SCANCODE_F,
+ object : KeyMapping() {
+ init {
+ Char = "а"
+ ShiftChar = "А"
+ }
+ })
+ put(ScanCodes.SCANCODE_G,
+ object : KeyMapping() {
+ init {
+ Char = "п"
+ ShiftChar = "П"
+ }
+ })
+ put(ScanCodes.SCANCODE_H,
+ object : KeyMapping() {
+ init {
+ Char = "р"
+ ShiftChar = "Р"
+ }
+ })
+ put(ScanCodes.SCANCODE_J,
+ object : KeyMapping() {
+ init {
+ Char = "о"
+ ShiftChar = "О"
+ }
+ })
+ put(ScanCodes.SCANCODE_K,
+ object : KeyMapping() {
+ init {
+ Char = "л"
+ ShiftChar = "Л"
+ }
+ })
+ put(ScanCodes.SCANCODE_L,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_VOLUME_MUTE
+ //AlternateScanCode = ScanCodes.SCANCODE_VOLUME_MUTE;
+ AlternateFix = false
+ Char = "д"
+ ShiftChar = "Д"
+ }
+ })
+ put(ScanCodes.SCANCODE_SEMICOLON,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_VOLUME_DOWN
+ //AlternateScanCode = ScanCodes.SCANCODE_VOLUME_DOWN;
+ AlternateFix = false
+ Char = "ж"
+ ShiftChar = "Ж"
+ }
+ })
+ put(ScanCodes.SCANCODE_APOSTROPHE,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_VOLUME_UP
+ //AlternateScanCode = ScanCodes.SCANCODE_VOLUME_UP;
+ AlternateFix = false
+ Char = "э"
+ ShiftChar = "Э"
+ }
+ })
+ put(ScanCodes.SCANCODE_Z,
+ object : KeyMapping() {
+ init {
+ Char = "я"
+ ShiftChar = "Я"
+ }
+ })
+ put(ScanCodes.SCANCODE_X,
+ object : KeyMapping() {
+ init {
+ Char = "ч"
+ ShiftChar = "Ч"
+ }
+ })
+ put(ScanCodes.SCANCODE_C,
+ object : KeyMapping() {
+ init {
+ Char = "с"
+ ShiftChar = "С"
+ }
+ })
+ put(ScanCodes.SCANCODE_V,
+ object : KeyMapping() {
+ init {
+ Char = "м"
+ ShiftChar = "М"
+ }
+ })
+ put(ScanCodes.SCANCODE_B,
+ object : KeyMapping() {
+ init {
+ Char = "и"
+ ShiftChar = "И"
+ }
+ })
+ put(ScanCodes.SCANCODE_N,
+ object : KeyMapping() {
+ init {
+ Char = "т"
+ ShiftChar = "Т"
+ }
+ })
+ put(ScanCodes.SCANCODE_M,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_MEDIA_REWIND
+ //AlternateScanCode = ScanCodes.SCANCODE_MEDIA_REWIND;
+ AlternateFix = false
+ Char = "ь"
+ ShiftChar = "Ь"
+ }
+ })
+ put(ScanCodes.SCANCODE_COMMA,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_MEDIA_FAST_FORWARD
+ //AlternateScanCode = ScanCodes.SCANCODE_MEDIA_FAST_FORWARD;
+ AlternateFix = false
+ Char = "б"
+ ShiftChar = "Б"
+ }
+ })
+ put(ScanCodes.SCANCODE_PERIOD,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS
+ //AlternateScanCode = ScanCodes.SCANCODE_MEDIA_PREVIOUS;
+ AlternateFix = false
+ Char = "ю"
+ ShiftChar = "Ю"
+ }
+ })
+ put(ScanCodes.SCANCODE_BACKSLASH,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_INSERT
+ ShiftChar = "/"
+ IgnoreCapsLock = true
+ }
+ })
+ put(ScanCodes.SCANCODE_BACKSLASH_LEFT,
+ object : KeyMapping() {
+ init {
+ ShiftChar = "/"
+ IgnoreCapsLock = true
+ }
+ })
+ put(ScanCodes.SCANCODE_SLASH,
+ object : KeyMapping() {
+ init {
+ Char = "."
+ ShiftChar = ","
+ IgnoreCapsLock = true
+ AlternateKeyCode = KeyEvent.KEYCODE_MEDIA_NEXT
+ //AlternateScanCode = ScanCodes.SCANCODE_MEDIA_NEXT;
+ AlternateFix = false
+ }
+ })
+ put(ScanCodes.SCANCODE_SHIFT_RIGHT,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
+ //AlternateScanCode = ScanCodes.SCANCODE_MEDIA_PLAY_PAUSE;
+ AlternateFix = false
+ }
+ })
+ put(ScanCodes.SCANCODE_DPAD_LEFT,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_MOVE_HOME
+ AlternateScanCode = ScanCodes.SCANCODE_MOVE_HOME
+ AlternateFix = false
+ }
+ })
+ put(ScanCodes.SCANCODE_DPAD_RIGHT,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_MOVE_END
+ AlternateScanCode = ScanCodes.SCANCODE_MOVE_END
+ AlternateFix = false
+ }
+ })
+ put(ScanCodes.SCANCODE_DPAD_UP,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_PAGE_UP
+ AlternateScanCode = ScanCodes.SCANCODE_PAGE_UP
+ AlternateFix = false
+ }
+ })
+ put(ScanCodes.SCANCODE_DPAD_DOWN,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_PAGE_DOWN
+ AlternateScanCode = ScanCodes.SCANCODE_PAGE_DOWN
+ AlternateFix = false
+ }
+ })
+ put(ScanCodes.SCANCODE_DEL,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_FORWARD_DEL
+ AlternateScanCode = ScanCodes.SCANCODE_FORWARD_DEL
+ AlternateFix = false
+ }
+ })
+ put(ScanCodes.SCANCODE_ALT_RIGHT,
+ object : KeyMapping() {
+ init {
+ AlternateKeyCode = KeyEvent.KEYCODE_MENU
+ AlternateScanCode = ScanCodes.SCANCODE_MENU
+ AlternateFix = false
+ }
+ })
+ }
+ }
+
+ fun getMapping(scanCode: Int): KeyMapping? {
+ return if (mapping.containsKey(scanCode)) mapping[scanCode] else null
+ }
+}
diff --git a/app/src/main/java/com/clusterrr/hardwarekeyboard/ScanCodes.kt b/app/src/main/java/com/clusterrr/hardwarekeyboard/ScanCodes.kt
new file mode 100644
index 0000000..f6f8e65
--- /dev/null
+++ b/app/src/main/java/com/clusterrr/hardwarekeyboard/ScanCodes.kt
@@ -0,0 +1,196 @@
+package com.clusterrr.hardwarekeyboard
+
+object ScanCodes {
+ val SCANCODE_VOLUME_MUTE = 113
+ val SCANCODE_VOLUME_DOWN = 114
+ val SCANCODE_VOLUME_UP = 115
+ val SCANCODE_MEDIA_NEXT = 163
+ val SCANCODE_MEDIA_PLAY_PAUSE = 164
+ val SCANCODE_MEDIA_PREVIOUS = 165
+ val SCANCODE_SEARCH = 217
+ val SCANCODE_DPAD_LEFT = 105
+ val SCANCODE_DPAD_RIGHT = 106
+ val SCANCODE_DPAD_UP = 103
+ val SCANCODE_DPAD_DOWN = 108
+
+ val SCANCODE_ESCAPE = 1
+ val SCANCODE_F1 = 59
+ val SCANCODE_F2 = 60
+ val SCANCODE_F3 = 61
+ val SCANCODE_F4 = 62
+ val SCANCODE_F5 = 63
+ val SCANCODE_F6 = 64
+ val SCANCODE_F7 = 65
+ val SCANCODE_F8 = 66
+ val SCANCODE_F9 = 67
+ val SCANCODE_F10 = 68
+ val SCANCODE_F11 = 87
+ val SCANCODE_F12 = 88
+ val SCANCODE_FORWARD_DEL = 111
+
+ val SCANCODE_GRAVE = 41
+ val SCANCODE_1 = 2
+ val SCANCODE_2 = 3
+ val SCANCODE_3 = 4
+ val SCANCODE_4 = 5
+ val SCANCODE_5 = 6
+ val SCANCODE_6 = 7
+ val SCANCODE_7 = 8
+ val SCANCODE_8 = 9
+ val SCANCODE_9 = 10
+ val SCANCODE_0 = 11
+ val SCANCODE_DEL = 14
+
+ val SCANCODE_TAB = 15
+ val SCANCODE_Q = 16
+ val SCANCODE_W = 17
+ val SCANCODE_E = 18
+ val SCANCODE_R = 19
+ val SCANCODE_T = 20
+ val SCANCODE_Y = 21
+ val SCANCODE_U = 22
+ val SCANCODE_I = 23
+ val SCANCODE_O = 24
+ val SCANCODE_P = 25
+ val SCANCODE_BACKSLASH = 43
+ val SCANCODE_BACKSLASH_LEFT = 86
+
+ val SCANCODE_CAPS_LOCK = 58
+ val SCANCODE_A = 30
+ val SCANCODE_S = 31
+ val SCANCODE_D = 32
+ val SCANCODE_F = 33
+ val SCANCODE_G = 34
+ val SCANCODE_H = 35
+ val SCANCODE_J = 36
+ val SCANCODE_K = 37
+ val SCANCODE_L = 38
+ val SCANCODE_ENTER = 28
+
+ val SCANCODE_SHIFT_LEFT = 42
+ val SCANCODE_Z = 44
+ val SCANCODE_X = 45
+ val SCANCODE_C = 46
+ val SCANCODE_V = 47
+ val SCANCODE_B = 48
+ val SCANCODE_N = 49
+ val SCANCODE_M = 50
+ val SCANCODE_COMMA = 51
+ val SCANCODE_PERIOD = 52
+ val SCANCODE_SEMICOLON = 39
+ val SCANCODE_APOSTROPHE = 40
+ val SCANCODE_SHIFT_RIGHT = 54
+
+ val SCANCODE_CTRL_LEFT = 29
+ val SCANCODE_SHOW_KEYBOARD = 706
+ val SCANCODE_ALT_LEFT = 56
+ val SCANCODE_SPACE = 57
+ val SCANCODE_LANGUAGE = 122
+ val SCANCODE_ALT_RIGHT = 100
+ val SCANCODE_MINUS = 12
+ val SCANCODE_EQUALS = 13
+ val SCANCODE_LEFT_BRACKET = 26
+ val SCANCODE_RIGHT_BRACKET = 27
+ val SCANCODE_SLASH = 53
+
+ val SCANCODE_PAGE_UP = 104
+ val SCANCODE_PAGE_DOWN = 109
+ val SCANCODE_MOVE_HOME = 102
+ val SCANCODE_MOVE_END = 107
+
+ /**
+ * Key code constant: System Request / Print Screen key.
+ */
+ val SCANCODE_SYSRQ = 84
+ /**
+ * Scan code constant: Scroll Lock key.
+ */
+ val SCANCODE_SCROLL_LOCK = 70
+ /**
+ * Key code constant: Break / Pause key.
+ */
+ val SCANCODE_BREAK = 119
+ /**
+ * Scan code constant: Num Lock key.
+ * This key alters the behavior of other keys on the numeric keypad.
+ */
+ val SCANCODE_NUM_LOCK = 69
+ /**
+ * Scan code constant: Numeric keypad '0' key.
+ */
+ val SCANCODE_NUMPAD_0 = 82
+ /**
+ * Scan code constant: Numeric keypad '1' key.
+ */
+ val SCANCODE_NUMPAD_1 = 79
+ /**
+ * Scan code constant: Numeric keypad '2' key.
+ */
+ val SCANCODE_NUMPAD_2 = 80
+ /**
+ * Scan code constant: Numeric keypad '3' key.
+ */
+ val SCANCODE_NUMPAD_3 = 81
+ /**
+ * Scan code constant: Numeric keypad '4' key.
+ */
+ val SCANCODE_NUMPAD_4 = 75
+ /**
+ * Scan code constant: Numeric keypad '5' key.
+ */
+ val SCANCODE_NUMPAD_5 = 76
+ /**
+ * Scan code constant: Numeric keypad '6' key.
+ */
+ val SCANCODE_NUMPAD_6 = 77
+ /**
+ * Scan code constant: Numeric keypad '7' key.
+ */
+ val SCANCODE_NUMPAD_7 = 71
+ /**
+ * Scan code constant: Numeric keypad '8' key.
+ */
+ val SCANCODE_NUMPAD_8 = 72
+ /**
+ * Scan code constant: Numeric keypad '9' key.
+ */
+ val SCANCODE_NUMPAD_9 = 73
+ /**
+ * Scan code constant: Numeric keypad '/' key (for division).
+ */
+ val SCANCODE_NUMPAD_DIVIDE = 98
+ /**
+ * Scan code constant: Numeric keypad '*' key (for multiplication).
+ */
+ val SCANCODE_NUMPAD_MULTIPLY = 55
+ /**
+ * Scan code constant: Numeric keypad '-' key (for subtraction).
+ */
+ val SCANCODE_NUMPAD_SUBTRACT = 74
+ /**
+ * Scan code constant: Numeric keypad '+' key (for addition).
+ */
+ val SCANCODE_NUMPAD_ADD = 78
+ /**
+ * Scan code constant: Numeric keypad '.' key (for decimals or digit grouping).
+ */
+ val SCANCODE_NUMPAD_DOT = 83
+ /**
+ * Scan code constant: Numeric keypad ',' key (for decimals or digit grouping).
+ */
+ val SCANCODE_NUMPAD_COMMA = 159
+ /**
+ * Scan code constant: Numeric keypad Enter key.
+ */
+ val SCANCODE_NUMPAD_ENTER = 96
+
+ /**
+ * Scan code constant: Menu key.
+ */
+ val SCANCODE_MENU = 127
+ /**
+ * Scan code constant: Calculator special function key.
+ * Used to launch a calculator application.
+ */
+ val SCANCODE_CALCULATOR = 140
+} \ No newline at end of file
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..971add5
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:fillType="evenOdd"
+ android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
+ android:strokeWidth="1"
+ android:strokeColor="#00000000">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:endX="78.5885"
+ android:endY="90.9159"
+ android:startX="48.7653"
+ android:startY="61.0927"
+ android:type="linear">
+ <item
+ android:color="#44000000"
+ android:offset="0.0" />
+ <item
+ android:color="#00000000"
+ android:offset="1.0" />
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path
+ android:fillColor="#FFFFFF"
+ android:fillType="nonZero"
+ android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
+ android:strokeWidth="1"
+ android:strokeColor="#00000000" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..eed7a42
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:fillColor="#008577"
+ android:pathData="M0,0h108v108h-108z" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M9,0L9,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,0L19,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,0L29,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,0L39,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,0L49,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,0L59,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,0L69,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,0L79,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M89,0L89,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M99,0L99,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,9L108,9"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,19L108,19"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,29L108,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,39L108,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,49L108,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,59L108,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,69L108,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,79L108,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,89L108,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,99L108,99"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,29L89,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,39L89,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,49L89,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,59L89,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,69L89,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,79L89,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,19L29,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,19L39,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,19L49,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,19L59,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,19L69,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,19L79,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/app/src/main/res/layout/keyboard_layout.xml b/app/src/main/res/layout/keyboard_layout.xml
new file mode 100644
index 0000000..8a11266
--- /dev/null
+++ b/app/src/main/res/layout/keyboard_layout.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="24dp">
+
+ <Switch
+ android:id="@+id/switchCapsLock"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
+ android:checked="true"
+ android:switchPadding="5dp"
+ android:text="Caps Lock"
+ android:textColor="@color/colorText"
+ android:focusable="false"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <Switch
+ android:id="@+id/switchFnLock"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="32dp"
+ android:switchPadding="5dp"
+ android:text="FN Lock"
+ android:textColor="@color/colorText"
+ android:focusable="false"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/switchCapsLock"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/textViewLanguage"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginEnd="8dp"
+ android:background="@color/colorLanguageBackground"
+ android:textColor="@color/colorLanguageText"
+ android:gravity="center"
+ android:text="EN"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..a26f6fb
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon> \ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..a26f6fb
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon> \ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..898f3ed
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dffca36
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..64ba76f
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dae5e08
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..e5ed465
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..14ed0af
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b0907ca
--- /dev/null
+++ b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..d8ae031
--- /dev/null
+++ b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..2c18de9
--- /dev/null
+++ b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..beed3cd
--- /dev/null
+++ b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..0145c7c
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="colorText">#408040</color>
+ <color name="colorLanguageText">#B0B0B0</color>
+ <color name="colorLanguageBackground">#0000FF</color>
+ <color name="colorPrimary">#008577</color>
+ <color name="colorPrimaryDark">#00574B</color>
+ <color name="colorAccent">#D81B60</color>
+</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..c5a811b
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">Hardware Keyboard</string>
+</resources>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..7532894
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,10 @@
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="Theme.AppCompat.DayNight">
+ <item name="android:colorPrimary">@color/colorPrimary</item>
+ <item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="android:colorAccent">@color/colorAccent</item>
+ </style>
+
+</resources>
diff --git a/app/src/main/res/xml/method.xml b/app/src/main/res/xml/method.xml
new file mode 100644
index 0000000..55e7ab2
--- /dev/null
+++ b/app/src/main/res/xml/method.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<input-method xmlns:android="http://schemas.android.com/apk/res/android"
+ android:settingsActivity="com.clusterrr.hardwarekeyboard.MainActivity"
+ android:icon="@drawable/ic_launcher_foreground">
+</input-method> \ No newline at end of file