-
-
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. пункте