diff --git a/CHANGELOG.md b/CHANGELOG.md index c91a574..a585fb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +# LOGITacker v0.2.2-beta + +**For updates from older LOGITacker versions the command `erase_flash` has to be ran once, to re-initialize +the flash data storage for the changed data structures. Not doing so likely causes errors during LOGITacker +operation** + +- fix: malformed keyboard reports when USB injection is used, because Logitech checksum was injected +- added Danish keyboard layout `da` +- added python companion script to program, which creates a script with Danish unicode character on LOGITacker +(programming using USB HID interface) + # LOGITacker v0.2.1-beta **For updates from older LOGITacker versions the command `erase_flash` has to be ran once, to re-initialize diff --git a/apr-dongle/blank/config/sdk_config.h b/apr-dongle/blank/config/sdk_config.h index 43c3f30..f7b54c0 100644 --- a/apr-dongle/blank/config/sdk_config.h +++ b/apr-dongle/blank/config/sdk_config.h @@ -1975,7 +1975,7 @@ // Note: This value is not editable in Configuration Wizard. // Serial number that is defined the same way like in @ref APP_USBD_STRINGS_MANUFACTURER. #ifndef APP_USBD_STRING_SERIAL -#define APP_USBD_STRING_SERIAL APP_USBD_STRING_DESC("v0.2.1-beta") +#define APP_USBD_STRING_SERIAL APP_USBD_STRING_DESC("v0.2.2-beta") #endif // diff --git a/logitacker/logitacker.h b/logitacker/logitacker.h index a49317b..e2ad42a 100644 --- a/logitacker/logitacker.h +++ b/logitacker/logitacker.h @@ -14,7 +14,7 @@ extern "C" { #include "logitacker_keyboard_map.h" #include "logitacker_processor_covert_channel.h" -#define VERSION_STRING "v0.2.1-beta" +#define VERSION_STRING "v0.2.2-beta" //#define PAIRING_REQ_MARKER_BYTE 0xee // byte used as device ID in pairing requests #define ACTIVE_ENUM_INNER_LOOP_MAX 20 //how many CAPS presses / key releases get send diff --git a/logitacker/logitacker_cli.c b/logitacker/logitacker_cli.c index c1c33df..8a7d2cc 100644 --- a/logitacker/logitacker_cli.c +++ b/logitacker/logitacker_cli.c @@ -665,7 +665,7 @@ static void cmd_options_inject_lang(nrf_cli_t const *p_cli, size_t argc, char ** return; } else { - nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "need language layout name as first argument (f.e. us, de)\r\n"); + nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "need language layout name as first argument (f.e. us, de, da)\r\n"); return; diff --git a/logitacker/logitacker_keyboard_map.c b/logitacker/logitacker_keyboard_map.c index dd875e4..4dbdfa3 100644 --- a/logitacker/logitacker_keyboard_map.c +++ b/logitacker/logitacker_keyboard_map.c @@ -223,13 +223,18 @@ uint32_t logitacker_keyboard_map_wc_to_hid_reports(hid_keyboard_report_t **p_out default: return NRF_ERROR_INVALID_PARAM; } - } else if (in_layout == LANGUAGE_LAYOUT_DE) { switch (in_rune) { LAYOUT_DE(LAYOUT_SWITCH_CASE) default: return NRF_ERROR_INVALID_PARAM; } + } else if (in_layout == LANGUAGE_LAYOUT_DA) { + switch (in_rune) { + LAYOUT_DA(LAYOUT_SWITCH_CASE) + default: + return NRF_ERROR_INVALID_PARAM; + } } else { return NRF_ERROR_INVALID_PARAM; } @@ -307,6 +312,7 @@ logitacker_keyboard_map_lang_t logitacker_keyboard_map_lang_from_str(char * lang if (strcmp(lang_str, "de") == 0 || strcmp(lang_str, "DE") == 0 ) return LANGUAGE_LAYOUT_DE; if (strcmp(lang_str, "us") == 0 || strcmp(lang_str, "US") == 0 ) return LANGUAGE_LAYOUT_US; + if (strcmp(lang_str, "da") == 0 || strcmp(lang_str, "DA") == 0 ) return LANGUAGE_LAYOUT_DA; lab_default: NRF_LOG_WARNING("unknown language layout '%s' ... using 'us' as default", nrf_log_push(lang_str)); diff --git a/logitacker/logitacker_keyboard_map.h b/logitacker/logitacker_keyboard_map.h index 719feda..a801cd1 100644 --- a/logitacker/logitacker_keyboard_map.h +++ b/logitacker/logitacker_keyboard_map.h @@ -388,6 +388,11 @@ DEF_REPORT_SEQUENCE_NAMED(GRAVE_FOLLOWED_BY_SPACE, DEF_REPORT(HID_MOD_KE // German '`' as deadkey DEF_REPORT_SEQUENCE_NAMED(SHIFT_AND_EQUAL_FOLLOWED_BY_SPACE, DEF_REPORT(HID_MOD_KEY_LEFT_SHIFT, HID_KEY_EQUAL), DEF_REPORT(HID_MOD_KEY_NONE, HID_KEY_NONE), DEF_REPORT(HID_MOD_KEY_NONE, HID_KEY_SPACE)); +// for DA +DEF_REPORT_SEQUENCE_NAMED(US_RALT_AND_4, DEF_REPORT(HID_MOD_KEY_RIGHT_ALT, HID_KEY_4)); +DEF_REPORT_SEQUENCE_NAMED(US_RALT_AND_EQUAL, DEF_REPORT(HID_MOD_KEY_RIGHT_ALT, HID_KEY_EQUAL)); +DEF_REPORT_SEQUENCE_NAMED(SHIFT_AND_RIGHTBRACE_FOLLOWED_BY_SPACE, DEF_REPORT(HID_MOD_KEY_LEFT_SHIFT, HID_KEY_RIGHTBRACE), DEF_REPORT(HID_MOD_KEY_NONE, HID_KEY_NONE), DEF_REPORT(HID_MOD_KEY_NONE, HID_KEY_SPACE)); +DEF_REPORT_SEQUENCE_NAMED(RALT_AND_RIGHTBRACE_FOLLOWED_BY_SPACE, DEF_REPORT(HID_MOD_KEY_LEFT_SHIFT, HID_KEY_RIGHTBRACE), DEF_REPORT(HID_MOD_KEY_NONE, HID_KEY_NONE), DEF_REPORT(HID_MOD_KEY_NONE, HID_KEY_SPACE)); #define LAYOUT_US(PROC_FUNC) \ PROC_FUNC(L'\t', HID_REPORT_SEQUENCE_US_TAB) \ @@ -598,6 +603,114 @@ DEF_REPORT_SEQUENCE_NAMED(SHIFT_AND_EQUAL_FOLLOWED_BY_SPACE, DEF_REPORT( PROC_FUNC(L'€', HID_REPORT_SEQUENCE_RALT_AND_E) \ PROC_FUNC(L'µ', HID_REPORT_SEQUENCE_RALT_AND_M) \ +#define LAYOUT_DA(PROC_FUNC) \ + PROC_FUNC(L'\t', HID_REPORT_SEQUENCE_US_TAB) \ + PROC_FUNC(L'\n', HID_REPORT_SEQUENCE_US_ENTER) \ + PROC_FUNC(L' ', HID_REPORT_SEQUENCE_US_SPACE) \ + PROC_FUNC(L'!', HID_REPORT_SEQUENCE_US_SHIFT_AND_1) \ + PROC_FUNC(L'\"', HID_REPORT_SEQUENCE_US_SHIFT_AND_2) \ + PROC_FUNC(L'#', HID_REPORT_SEQUENCE_US_SHIFT_AND_3) \ + PROC_FUNC(L'$', HID_REPORT_SEQUENCE_US_RALT_AND_4) \ + PROC_FUNC(L'%', HID_REPORT_SEQUENCE_US_SHIFT_AND_5) \ + PROC_FUNC(L'&', HID_REPORT_SEQUENCE_US_SHIFT_AND_6) \ + PROC_FUNC(L'\'', HID_REPORT_SEQUENCE_US_BACKSLASH) \ + PROC_FUNC(L'(', HID_REPORT_SEQUENCE_US_SHIFT_AND_8) \ + PROC_FUNC(L')', HID_REPORT_SEQUENCE_US_SHIFT_AND_9) \ + PROC_FUNC(L'*', HID_REPORT_SEQUENCE_US_SHIFT_AND_BACKSLASH) \ + PROC_FUNC(L'+', HID_REPORT_SEQUENCE_US_MINUS) \ + PROC_FUNC(L',', HID_REPORT_SEQUENCE_US_COMMA) \ + PROC_FUNC(L'-', HID_REPORT_SEQUENCE_US_SLASH) \ + PROC_FUNC(L'.', HID_REPORT_SEQUENCE_US_DOT) \ + PROC_FUNC(L'/', HID_REPORT_SEQUENCE_US_SHIFT_AND_7) \ + PROC_FUNC(L'0', HID_REPORT_SEQUENCE_US_0) \ + PROC_FUNC(L'1', HID_REPORT_SEQUENCE_US_1) \ + PROC_FUNC(L'2', HID_REPORT_SEQUENCE_US_2) \ + PROC_FUNC(L'3', HID_REPORT_SEQUENCE_US_3) \ + PROC_FUNC(L'4', HID_REPORT_SEQUENCE_US_4) \ + PROC_FUNC(L'5', HID_REPORT_SEQUENCE_US_5) \ + PROC_FUNC(L'6', HID_REPORT_SEQUENCE_US_6) \ + PROC_FUNC(L'7', HID_REPORT_SEQUENCE_US_7) \ + PROC_FUNC(L'8', HID_REPORT_SEQUENCE_US_8) \ + PROC_FUNC(L'9', HID_REPORT_SEQUENCE_US_9) \ + PROC_FUNC(L':', HID_REPORT_SEQUENCE_US_SHIFT_AND_DOT) \ + PROC_FUNC(L';', HID_REPORT_SEQUENCE_US_SHIFT_AND_COMMA) \ + PROC_FUNC(L'<', HID_REPORT_SEQUENCE_102ND) \ + PROC_FUNC(L'=', HID_REPORT_SEQUENCE_US_SHIFT_AND_0) \ + PROC_FUNC(L'>', HID_REPORT_SEQUENCE_SHIFT_AND_102ND) \ + PROC_FUNC(L'?', HID_REPORT_SEQUENCE_US_SHIFT_AND_MINUS) \ + PROC_FUNC(L'@', HID_REPORT_SEQUENCE_RALT_AND_Q) \ + PROC_FUNC(L'A', HID_REPORT_SEQUENCE_US_SHIFT_AND_A) \ + PROC_FUNC(L'B', HID_REPORT_SEQUENCE_US_SHIFT_AND_B) \ + PROC_FUNC(L'C', HID_REPORT_SEQUENCE_US_SHIFT_AND_C) \ + PROC_FUNC(L'D', HID_REPORT_SEQUENCE_US_SHIFT_AND_D) \ + PROC_FUNC(L'E', HID_REPORT_SEQUENCE_US_SHIFT_AND_E) \ + PROC_FUNC(L'F', HID_REPORT_SEQUENCE_US_SHIFT_AND_F) \ + PROC_FUNC(L'G', HID_REPORT_SEQUENCE_US_SHIFT_AND_G) \ + PROC_FUNC(L'H', HID_REPORT_SEQUENCE_US_SHIFT_AND_H) \ + PROC_FUNC(L'I', HID_REPORT_SEQUENCE_US_SHIFT_AND_I) \ + PROC_FUNC(L'J', HID_REPORT_SEQUENCE_US_SHIFT_AND_J) \ + PROC_FUNC(L'K', HID_REPORT_SEQUENCE_US_SHIFT_AND_K) \ + PROC_FUNC(L'L', HID_REPORT_SEQUENCE_US_SHIFT_AND_L) \ + PROC_FUNC(L'M', HID_REPORT_SEQUENCE_US_SHIFT_AND_M) \ + PROC_FUNC(L'N', HID_REPORT_SEQUENCE_US_SHIFT_AND_N) \ + PROC_FUNC(L'O', HID_REPORT_SEQUENCE_US_SHIFT_AND_O) \ + PROC_FUNC(L'P', HID_REPORT_SEQUENCE_US_SHIFT_AND_P) \ + PROC_FUNC(L'Q', HID_REPORT_SEQUENCE_US_SHIFT_AND_Q) \ + PROC_FUNC(L'R', HID_REPORT_SEQUENCE_US_SHIFT_AND_R) \ + PROC_FUNC(L'S', HID_REPORT_SEQUENCE_US_SHIFT_AND_S) \ + PROC_FUNC(L'T', HID_REPORT_SEQUENCE_US_SHIFT_AND_T) \ + PROC_FUNC(L'U', HID_REPORT_SEQUENCE_US_SHIFT_AND_U) \ + PROC_FUNC(L'V', HID_REPORT_SEQUENCE_US_SHIFT_AND_V) \ + PROC_FUNC(L'W', HID_REPORT_SEQUENCE_US_SHIFT_AND_W) \ + PROC_FUNC(L'X', HID_REPORT_SEQUENCE_US_SHIFT_AND_X) \ + PROC_FUNC(L'Y', HID_REPORT_SEQUENCE_US_SHIFT_AND_Y) \ + PROC_FUNC(L'Z', HID_REPORT_SEQUENCE_US_SHIFT_AND_Z) \ + PROC_FUNC(L'[', HID_REPORT_SEQUENCE_RALT_AND_8) \ + PROC_FUNC(L'\\', HID_REPORT_SEQUENCE_RALT_AND_102ND) \ + PROC_FUNC(L']', HID_REPORT_SEQUENCE_RALT_AND_9) \ + PROC_FUNC(L'^', HID_REPORT_SEQUENCE_SHIFT_AND_RIGHTBRACE_FOLLOWED_BY_SPACE) \ + PROC_FUNC(L'_', HID_REPORT_SEQUENCE_US_SHIFT_AND_SLASH) \ + PROC_FUNC(L'`', HID_REPORT_SEQUENCE_SHIFT_AND_EQUAL_FOLLOWED_BY_SPACE) \ + PROC_FUNC(L'a', HID_REPORT_SEQUENCE_US_A) \ + PROC_FUNC(L'b', HID_REPORT_SEQUENCE_US_B) \ + PROC_FUNC(L'c', HID_REPORT_SEQUENCE_US_C) \ + PROC_FUNC(L'd', HID_REPORT_SEQUENCE_US_D) \ + PROC_FUNC(L'e', HID_REPORT_SEQUENCE_US_E) \ + PROC_FUNC(L'f', HID_REPORT_SEQUENCE_US_F) \ + PROC_FUNC(L'g', HID_REPORT_SEQUENCE_US_G) \ + PROC_FUNC(L'h', HID_REPORT_SEQUENCE_US_H) \ + PROC_FUNC(L'i', HID_REPORT_SEQUENCE_US_I) \ + PROC_FUNC(L'j', HID_REPORT_SEQUENCE_US_J) \ + PROC_FUNC(L'k', HID_REPORT_SEQUENCE_US_K) \ + PROC_FUNC(L'l', HID_REPORT_SEQUENCE_US_L) \ + PROC_FUNC(L'm', HID_REPORT_SEQUENCE_US_M) \ + PROC_FUNC(L'n', HID_REPORT_SEQUENCE_US_N) \ + PROC_FUNC(L'o', HID_REPORT_SEQUENCE_US_O) \ + PROC_FUNC(L'p', HID_REPORT_SEQUENCE_US_P) \ + PROC_FUNC(L'q', HID_REPORT_SEQUENCE_US_Q) \ + PROC_FUNC(L'r', HID_REPORT_SEQUENCE_US_R) \ + PROC_FUNC(L's', HID_REPORT_SEQUENCE_US_S) \ + PROC_FUNC(L't', HID_REPORT_SEQUENCE_US_T) \ + PROC_FUNC(L'u', HID_REPORT_SEQUENCE_US_U) \ + PROC_FUNC(L'v', HID_REPORT_SEQUENCE_US_V) \ + PROC_FUNC(L'w', HID_REPORT_SEQUENCE_US_W) \ + PROC_FUNC(L'x', HID_REPORT_SEQUENCE_US_X) \ + PROC_FUNC(L'y', HID_REPORT_SEQUENCE_US_Y) \ + PROC_FUNC(L'z', HID_REPORT_SEQUENCE_US_Z) \ + PROC_FUNC(L'{', HID_REPORT_SEQUENCE_RALT_AND_7) \ + PROC_FUNC(L'|', HID_REPORT_SEQUENCE_US_RALT_AND_EQUAL) \ + PROC_FUNC(L'}', HID_REPORT_SEQUENCE_RALT_AND_0) \ + PROC_FUNC(L'~', HID_REPORT_SEQUENCE_RALT_AND_RIGHTBRACE_FOLLOWED_BY_SPACE) \ + PROC_FUNC(L'§', HID_REPORT_SEQUENCE_US_SHIFT_AND_GRAVE) \ + PROC_FUNC(L'å', HID_REPORT_SEQUENCE_US_LEFTBRACE) \ + PROC_FUNC(L'Å', HID_REPORT_SEQUENCE_US_SHIFT_AND_LEFTBRACE) \ + PROC_FUNC(L'æ', HID_REPORT_SEQUENCE_US_SEMICOLON) \ + PROC_FUNC(L'Æ', HID_REPORT_SEQUENCE_US_SHIFT_AND_SEMICOLON) \ + PROC_FUNC(L'ø', HID_REPORT_SEQUENCE_US_APOSTROPHE) \ + PROC_FUNC(L'Ø', HID_REPORT_SEQUENCE_US_SHIFT_AND_APOSTROPHE) \ + PROC_FUNC(L'€', HID_REPORT_SEQUENCE_RALT_AND_E) \ + PROC_FUNC(L'µ', HID_REPORT_SEQUENCE_RALT_AND_M) \ + #define LAYOUT_SWITCH_CASE(nameval, val) case nameval: {*p_out_report_seq=(void*)val; *out_rep_seq_len=sizeof(val) ;return NRF_SUCCESS; } @@ -606,6 +719,7 @@ DEF_REPORT_SEQUENCE_NAMED(SHIFT_AND_EQUAL_FOLLOWED_BY_SPACE, DEF_REPORT( typedef enum { LANGUAGE_LAYOUT_DE, LANGUAGE_LAYOUT_US, + LANGUAGE_LAYOUT_DA, } logitacker_keyboard_map_lang_t; typedef struct { diff --git a/logitacker/logitacker_options.c b/logitacker/logitacker_options.c index df8e090..d4a9ad7 100644 --- a/logitacker/logitacker_options.c +++ b/logitacker/logitacker_options.c @@ -204,6 +204,9 @@ void logitacker_options_print(nrf_cli_t const * p_cli) case LANGUAGE_LAYOUT_US: injection_lan_str = "us"; break; + case LANGUAGE_LAYOUT_DA: + injection_lan_str = "da"; + break; } char * workmode_str = "unknown"; diff --git a/logitacker/logitacker_processor_inject.c b/logitacker/logitacker_processor_inject.c index 56abc1e..6211f41 100644 --- a/logitacker/logitacker_processor_inject.c +++ b/logitacker/logitacker_processor_inject.c @@ -308,17 +308,17 @@ void processor_inject_timer_handler_func_(logitacker_processor_inject_ctx_t *sel case INJECT_TASK_TYPE_PRESS_KEYS: case INJECT_TASK_TYPE_TYPE_STRING: case INJECT_TASK_TYPE_TYPE_ALTSTRING: { - // if timer is called, write (and auto transmit) current ESB payload - logitacker_unifying_payload_update_checksum(self->tmp_tx_payload.data, self->tmp_tx_payload.length); - + // if timer is called, write (and auto transmit) current payload if (self->usb_inject) { //write USB HID report if (logitacker_usb_write_keyboard_input_report(self->tmp_tx_payload.data) != NRF_SUCCESS) { NRF_LOG_WARNING("Failed to write keyboard report, busy with old report"); } else { - NRF_LOG_DEBUG("keyboard report sent to USB"); + NRF_LOG_INFO("keyboard report sent to USB"); } } else { + // fix: only append checksum to report if ESB is used + logitacker_unifying_payload_update_checksum(self->tmp_tx_payload.data, self->tmp_tx_payload.length); if (nrf_esb_write_payload(&self->tmp_tx_payload) != NRF_SUCCESS) { NRF_LOG_INFO("Error writing payload"); } else { diff --git a/mdk-dongle/blank/config/sdk_config.h b/mdk-dongle/blank/config/sdk_config.h index 43c3f30..f7b54c0 100644 --- a/mdk-dongle/blank/config/sdk_config.h +++ b/mdk-dongle/blank/config/sdk_config.h @@ -1975,7 +1975,7 @@ // Note: This value is not editable in Configuration Wizard. // Serial number that is defined the same way like in @ref APP_USBD_STRINGS_MANUFACTURER. #ifndef APP_USBD_STRING_SERIAL -#define APP_USBD_STRING_SERIAL APP_USBD_STRING_DESC("v0.2.1-beta") +#define APP_USBD_STRING_SERIAL APP_USBD_STRING_DESC("v0.2.2-beta") #endif // diff --git a/mdk/blank/armgcc/Makefile b/mdk/blank/armgcc/Makefile index 6b66298..8f05594 100644 --- a/mdk/blank/armgcc/Makefile +++ b/mdk/blank/armgcc/Makefile @@ -273,12 +273,11 @@ $(foreach target, $(TARGETS), $(call define_target, $(target))) # Flash the program flash: default - @echo Flashing: $(OUTPUT_DIRECTORY)/nrf52840_xxaa.hex - nrfjprog -f nrf52 --program $(OUTPUT_DIRECTORY)/nrf52840_xxaa.hex --sectorerase - nrfjprog -f nrf52 --reset + @echo Flashing: $(OUTPUT_DIRECTORY)/logitacker_mdk.hex + pyocd flash -t nrf52840 $(OUTPUT_DIRECTORY)/logitacker_mdk.hex erase: - nrfjprog -f nrf52 --eraseall + pyocd erase -t nrf52840 --chip SDK_CONFIG_FILE := ../config/sdk_config.h CMSIS_CONFIG_TOOL := $(SDK_ROOT)/external_tools/cmsisconfig/CMSIS_Configuration_Wizard.jar diff --git a/mdk/blank/config/sdk_config.h b/mdk/blank/config/sdk_config.h index 5bae501..347b249 100644 --- a/mdk/blank/config/sdk_config.h +++ b/mdk/blank/config/sdk_config.h @@ -1975,7 +1975,7 @@ // Note: This value is not editable in Configuration Wizard. // Serial number that is defined the same way like in @ref APP_USBD_STRINGS_MANUFACTURER. #ifndef APP_USBD_STRING_SERIAL -#define APP_USBD_STRING_SERIAL APP_USBD_STRING_DESC("v0.2.1-beta") +#define APP_USBD_STRING_SERIAL APP_USBD_STRING_DESC("v0.2.2-beta") #endif // diff --git a/pca10059/blank/config/sdk_config.h b/pca10059/blank/config/sdk_config.h index 5ac9a1c..5be0660 100644 --- a/pca10059/blank/config/sdk_config.h +++ b/pca10059/blank/config/sdk_config.h @@ -1975,7 +1975,7 @@ // Note: This value is not editable in Configuration Wizard. // Serial number that is defined the same way like in @ref APP_USBD_STRINGS_MANUFACTURER. #ifndef APP_USBD_STRING_SERIAL -#define APP_USBD_STRING_SERIAL APP_USBD_STRING_DESC("v0.2.1-beta") +#define APP_USBD_STRING_SERIAL APP_USBD_STRING_DESC("v0.2.2-beta") #endif // diff --git a/python_tests/create_utf8_script_DA.py b/python_tests/create_utf8_script_DA.py new file mode 100755 index 0000000..57b92f9 --- /dev/null +++ b/python_tests/create_utf8_script_DA.py @@ -0,0 +1,91 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import struct + +''' +Important: This is a test script for LOGITacker's HID based programming interface. +The script assumes the raw HID interface accessible on /dev/hidraw1 and writes data to +this dev-file. There is no proper implementation to directly interface with LOGITacker on +the USB HID layer, neither is the protocol finalized. + +The python script demos how to create injection scripts, which include Unicode and thus +can't be entered using the serial CLI (ASCII based input). + +LOGITacker supports ONLY UTF-8 encoding (see 2nd line of this script). Support for Unicode +characters depends on chosen language layout and respective keymapping. The characters in +this script are supported with 'da' layout. +''' + +# report types +REPORT_TYPE_COMMAND = 0x02 + +# commands +COMMAND_SCRIPT_STRING = 0x10 +COMMAND_SCRIPT_ALTSTRING = 0x11 +COMMAND_SCRIPT_PRESS = 0x12 +COMMAND_SCRIPT_DELAY = 0x13 +COMMAND_SCRIPT_CLEAR = 0x14 + +def build_report(cmd, args=""): + report = chr(REPORT_TYPE_COMMAND) + chr(cmd) + args + report = report + (64 - len(report)) * '\x00' + return report + +def cmd_string(str=""): + l = len(str) + if l > 60: + l = 60 + + return build_report(COMMAND_SCRIPT_STRING, chr(l) + str[:l]) + +def cmd_altstring(str=""): + l = len(str) + if l > 60: + l = 60 + + return build_report(COMMAND_SCRIPT_ALTSTRING, chr(l) + str[:l]) + +def cmd_press(str=""): + l = len(str) + if l > 60: + l = 60 + + return build_report(COMMAND_SCRIPT_PRESS, chr(l) + str[:l]) + +def cmd_delay(delay=1): + d_str = struct.pack('