-
-
Save Onefabis/d8d27f8c02d03071f1d987c76686cbd8 to your computer and use it in GitHub Desktop.
''' | |
1. Open src.c in lang shift lib and add this function right next to the 'lang_activate' function | |
######################################## | |
void lang_toggle(int externalLang) { | |
if (lang_current == lang_should_be && timer_read() - lang_timer >= 200) { | |
if (externalLang == 0){ | |
layer_off(2); | |
} else if (externalLang == 1){ | |
layer_on(2); | |
} | |
lang_current = externalLang; | |
lang_should_be = externalLang; | |
uint8_t response[RAW_EPSIZE]; | |
memset(response, 0, RAW_EPSIZE); | |
response[0] = lang_current; | |
raw_hid_send(response, RAW_EPSIZE); | |
} | |
} | |
######################################## | |
2. After that enable RAW_ENABLE in rules.mk in your keyboard | |
3. Then add this code in your keymap.c fils | |
######################################## | |
#ifdef RAW_ENABLE | |
void raw_hid_receive(uint8_t *data, uint8_t length) { | |
if(data[0] == 0) { | |
lang_toggle(1); | |
} else if(data[0] == 1) { | |
lang_toggle(0); | |
}; | |
}; | |
#endif | |
######################################## | |
4. Create the 'keyboard.txt' file near to the 'currentLayer.exe' the it should look like this | |
vendor_id = 0x0000 | |
product_id = 0x0000 | |
usage_page = 0xFF60 | |
usage = 0x61 | |
copy and paste vendor_id and product_id from your qmk config.h file | |
##################################################################### | |
####### IF YOU WISH TO COMPILE EXE FILS BY YOURSELF ############## | |
##################################################################### | |
1. Save the code below as 'currentLayer.py' | |
2. Install next libraries: | |
pip install hid | |
pip install wxPython | |
3. Get 'hidapi.dll' from 'hidapi-win.zip' archive here https://github.com/libusb/hidapi/releases and put it near to 'C:\Windows\System32\' | |
4. Install pip install git+https://github.com/pyinstaller/pyinstaller, delete the old one if already installed | |
5. Put the icon.gif attached in comments and place it near to the 'currentLayer.py' and don't forget to change its extension to .ico | |
6. In command line change the path to where in placed and run the code | |
pyinstaller -F --add-data "hidapi.dll;." --icon=icon.ico --onefile --windowed currentLayer.py | |
7. Get 'currentLayer.exe' in dist subfolder | |
8. Don't forget to always put 'keyboard.txt' near to the .exe with the text described above | |
''' | |
import ctypes | |
import hid | |
import time | |
import wx.adv | |
import wx | |
import threading | |
import queue | |
from base64 import b64decode | |
from zlib import decompress | |
from io import BytesIO | |
imgIconData = b'eJxjYGAEQgUFBhDJsEKAgUGMgYFBA4iBQgwODBBxEGgQYBgFo2AU4AHzXTgtFrryxtMCg8zGZ/cCN+45C915/9MSL3DjnYPT3zS2G4axhcNCV654fHq2JSv/vz3Jgyi8HagWrxuAcUGq/QcKdP9/25pCFD4IVDvc7KcqHgL2rwmTBIcjCK8Fsinlk2o/cnyDzKCUP9TsB4XfAag5a6DhSQl/NP6Hlv30jv8FblxxA1r+uHCa0Mt+XO0Q+rQ/uLG2P2AA0v4CpgVaYHcOS3x2j4JRMNLAfxzgAwMD/wMGBvYDDAzMlGCQGSCzcNkDAOK2rRo=' | |
image_data = decompress(b64decode(imgIconData)) | |
stream = BytesIO(bytearray(image_data)) | |
TRAY_TOOLTIP = 'Language changer' | |
keyboard_file = 'keyboard.txt' | |
try: | |
input = raw_input | |
except NameError: | |
pass | |
def create_menu_item(menu, label, func): | |
item = wx.MenuItem(menu, -1, label) | |
menu.Bind(wx.EVT_MENU, func, id=item.GetId()) | |
menu.Append(item) | |
return item | |
class TaskBarIcon(wx.adv.TaskBarIcon): | |
def __init__(self, frame): | |
self.frame = frame | |
super(TaskBarIcon, self).__init__() | |
self.trayIcon = wx.Image(stream, wx.BITMAP_TYPE_ANY) | |
self.trayImage = wx.Bitmap(self.trayIcon) | |
self.set_icon(self.trayImage, 0) | |
self.Bind(wx.adv.EVT_TASKBAR_LEFT_DOWN, self.on_left_down) | |
self.pauseStatus = 0 | |
self.speed_queue = queue.Queue() | |
self.blink_thread = MonitorLang(2) | |
self.blink_thread.start() | |
def CreatePopupMenu(self): | |
self.menu = wx.Menu() | |
self.pauseMenuItem = create_menu_item(self.menu, 'Toggle monitoring', self.toggle) | |
self.menu.AppendSeparator() | |
create_menu_item(self.menu, 'Exit', self.on_exit) | |
return self.menu | |
def set_icon(self, path, status): | |
if status == 0: | |
icon = wx.Icon(path) | |
self.SetIcon(icon, TRAY_TOOLTIP + ' running') | |
else: | |
icon = wx.Icon(path) | |
self.SetIcon(icon, TRAY_TOOLTIP + ' paused') | |
def on_left_down(self, event): | |
pass | |
def toggle(self, event): | |
if self.pauseStatus == 1: | |
print('Resume') | |
self.set_icon(self.trayImage, 0) | |
self.pauseStatus = 0 | |
self.blink_thread.set_mode(2) | |
else: | |
self.set_icon(self.trayImage, 1) | |
print('Paused') | |
self.blink_thread.set_mode(1) | |
self.pauseStatus = 1 | |
def on_exit(self, event): | |
self.blink_thread.set_mode(0) | |
wx.CallAfter(self.Destroy) | |
self.frame.Close() | |
class MonitorLang (threading.Thread): | |
def __init__(self, mode=2): | |
reader = open(keyboard_file, 'r') | |
self.debounce_timer = 0 | |
self.debounce_counter = 1 | |
self.loop_run_timer = 0 | |
self.vendor_id = 0 | |
self.product_id = 0 | |
self.usage_page = 0 | |
self.usage = 0 | |
try: | |
for i in reader.readlines(): | |
if 'vendor_id' in i: | |
self.vendor_id = int(i.split('=')[-1], 16) | |
if 'product_id' in i: | |
self.product_id = int(i.split('=')[-1], 16) | |
if 'usage_page' in i: | |
self.usage_page = int(i.split('=')[-1], 16) | |
if 'usage' in i: | |
self.usage = int(i.split('=')[-1], 16) | |
finally: | |
reader.close() | |
self._speed_cache = 0 | |
self.mode = mode | |
self.lock = threading.RLock() | |
super(MonitorLang, self).__init__() | |
def getCurrentSystemLayer(self): | |
user32 = ctypes.WinDLL('user32', use_last_error=True) | |
handle = user32.GetForegroundWindow() | |
threadid = user32.GetWindowThreadProcessId(handle, 0) | |
layout_id = user32.GetKeyboardLayout(threadid) | |
language_id = layout_id & (2 ** 16 - 1) | |
return language_id | |
def get_raw_hid_interface(self): | |
device_interfaces = hid.enumerate(self.vendor_id, self.product_id) | |
raw_hid_interfaces = [i for i in device_interfaces if i['usage_page'] == self.usage_page and i['usage'] == self.usage] | |
if len(raw_hid_interfaces) == 0: | |
return None | |
interface = hid.Device(path=raw_hid_interfaces[0]['path']) | |
return interface | |
def send_raw_packet(self, data): | |
interface = self.get_raw_hid_interface() | |
if interface is None: | |
print("No device found") | |
request_data = [0x00] * 33 # First byte is Report ID | |
request_data[1:len(data) + 1] = data | |
request_packet = bytes(request_data) | |
if interface: | |
try: | |
interface.write(request_packet) | |
finally: | |
interface.close() | |
def set_mode(self, mode): # you can use a proper setter if you want | |
with self.lock: | |
self.mode = mode | |
def run(self): | |
self.layerCached = -1 | |
self.layerStored = None | |
while True: | |
with self.lock: | |
if self.mode == 0: | |
print("Mode is 0, exiting...") | |
break | |
if self.mode == 2: | |
activeLayers = self.getCurrentSystemLayer() | |
if self.layerCached != activeLayers: | |
interface = self.get_raw_hid_interface() | |
if activeLayers == 1033: | |
self.send_raw_packet([1]) | |
if activeLayers == 1049: | |
self.send_raw_packet([0]) | |
self.layerCached = activeLayers | |
try: | |
response_packet = interface.read(32, timeout=400) | |
if response_packet: | |
if response_packet[0] == 0: | |
self.send_raw_packet([1]) | |
if response_packet[0] == 1: | |
self.send_raw_packet([0]) | |
finally: | |
interface.close() | |
time.sleep(0.2) | |
class App(wx.App): | |
def OnInit(self): | |
frame=wx.Frame(None) | |
self.SetTopWindow(frame) | |
TaskBarIcon(frame) | |
return True | |
def main(): | |
app = App(False) | |
app.MainLoop() | |
if __name__ == '__main__': | |
main() |
Onefabis
commented
Sep 15, 2021
You can get compilled exe here https://drive.google.com/file/d/123Y1UGvCvPMtX6jasfuX78aRhe_r-I2K/view?usp=sharing
fix step 6;
pyinstaller -F --add-data "hidapi.dll;." --icon=icon.ico --onefile --windowed currentLayer.py
Дубликат архива с exe файлами https://disk.yandex.ru/d/qq8v_D7hZLtYXw
- Откройте src.c в библиотеке lang shift и добавьте новую функцию сразу после 'lang_activate' функции
########################################
void lang_toggle(int externalLang) {
if (lang_current == lang_should_be && timer_read() - lang_timer >= 200) {
if (externalLang == 0){
layer_off(2);
} else if (externalLang == 1){
layer_on(2);
}
lang_current = externalLang;
lang_should_be = externalLang;
uint8_t response[RAW_EPSIZE];
memset(response, 0, RAW_EPSIZE);
response[0] = lang_current;
raw_hid_send(response, RAW_EPSIZE);
}
}
########################################
-
Также включите параметр RAW_ENABLE в rules.mk в вашей клавиатуре
-
Затем добавьте следующий код в keymap.c файл
########################################
#ifdef RAW_ENABLE
void raw_hid_receive(uint8_t *data, uint8_t length) {
if(data[0] == 0) {
lang_toggle(1); # здесь можно переключить на русскую раскладку
} else if(data[0] == 1) {
lang_toggle(0); # здесь можно переключить на английскую раскладку
};
};
#endif
########################################
- Создайте файл 'keyboard.txt' рядом с 'currentLayer.exe', содержимое должно быть таким:
vendor_id = 0x0000
product_id = 0x0000
usage_page = 0xFF60
usage = 0x61
значения для vendor_id и product_id из qmk config.h вашей клавиатуры
#####################################################################
######## ЕСЛИ РЕШИЛИ СКОМПИЛИРОВАТЬ САМИ EXE ##############
#####################################################################
- Сохраните код выше как 'currentLayer.py'
- Установите следующие библиотеки:
pip install hid
pip install wxPython - Скачайте 'hidapi.dll' из 'hidapi-win.zip' архива из https://github.com/libusb/hidapi/releases и положите в папку 'C:\Windows\System32'
- Установите pip install git+https://github.com/pyinstaller/pyinstaller, удалите старый pyinstaller, если такой уже установлен
- Скачайте icon.gif прикрепленные в комментариях выше и поместите рядом с 'currentLayer.py' и не забудьте заменить расширение на .ico
- В командной строке замените рабочий путь (cd) на тот в котором размещается python файл и запустите следующий код:
pyinstaller -F --add-data "hidapi.dll;." --icon=icon.ico --onefile --windowed currentLayer.py - Возьмите 'currentLayer.exe' в dist подпапке
- Не забудьте всегда держать 'keyboard.txt' рядом с .exe с текстом, указанным в инструкции выше в 4. пункте