├── LICENSE ├── README.md ├── code.lua ├── code.multi.lua ├── docs ├── APIDocs.pdf ├── generator.html ├── generator.js ├── index.html ├── io.js ├── tutorial.html └── tutorial_images │ ├── copy.JPG │ ├── saved.JPG │ ├── scripting.JPG │ └── unsaved.JPG ├── mouse.lua ├── template.lua └── template.lua.b64 /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Tom 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Toggle buttons using Logitech gaming software 2 | 3 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/6a099c5490704c52abd7043d0ad00a2b)](https://app.codacy.com/app/tom.k.hipwell/logitech-toggle-keys?utm_source=github.com&utm_medium=referral&utm_content=Douile/logitech-toggle-keys&utm_campaign=Badge_Grade_Dashboard) 4 | 5 | _Version 8.97.88_ 6 | 7 | _LUA API Version 8.45_ 8 | 9 | --- 10 | 11 | The code below can be used in the script section of profiles in logitech gaming software to toggle pressing keys. 12 | 13 | **Enjoy!** 14 | 15 | [code](/code.lua) 16 | 17 | [generator](https://douile.github.io/logitech-toggle-keys/generator.html) 18 | -------------------------------------------------------------------------------- /code.lua: -------------------------------------------------------------------------------- 1 | -- choose your keys here 2 | -- e.g. if I wanted button 1 to toggle e I would put {e=1}; 3 | -- e.g. if I wanted button 3 to toggle e I would put {e=3,f=3,g=2}; 4 | keysetup = {f={5,2},a={4,0}}; 5 | -- if using mouse set to true 6 | mouse = false; 7 | -- set to true to log all button presses (useful when you don't know what number a key is) 8 | logall = true; 9 | -- change the delay between taps 10 | tap_delay = 30; 11 | tap_hold_delay = 5; 12 | 13 | -- do not change the code below 14 | OutputLogMessage("Script initialized\nWritten by: Douile\n"); 15 | if (mouse == true) then 16 | eventlisten = "MOUSE_BUTTON_PRESSED"; 17 | OutputLogMessage("Configured for mouse buttons\n"); 18 | else 19 | eventlisten = "G_PRESSED"; 20 | OutputLogMessage("Configured for keyboard buttons\n"); 21 | end 22 | for k,v in pairs(keysetup) do 23 | OutputLogMessage("Button %d will toggle %s (%d presses)\n",v[1],k,v[2]); 24 | end 25 | OutputLogMessage("\n- start runtime log -\n"); 26 | 27 | keyspressed = {}; 28 | 29 | function OnEvent(event, arg) 30 | if (event == eventlisten) then 31 | if (logall == true) then 32 | OutputLogMessage("Key %d pressed\n",arg); 33 | end 34 | for k,v in pairs(keysetup) do 35 | if (arg == v[1] and k ~= null) then 36 | if (keyspressed[k] == true) then 37 | ReleaseKey(k); 38 | keyspressed[k] = false; 39 | OutputLogMessage("Recieved %s %d released %s\n",event,v[1],k); 40 | OutputLCDMessage(string.format("Pressing %s",k)); 41 | else 42 | for i=0,v[2] do 43 | PressKey(k); 44 | Sleep(tap_hold_delay); 45 | ReleaseKey(k); 46 | Sleep(tap_delay); 47 | end 48 | PressKey(k); 49 | keyspressed[k] = true; 50 | OutputLogMessage("Recieved %s %d pressed %s\n",event,v[1],k); 51 | OutputLCDMessage(string.format("Releasing %s",k)); 52 | end 53 | end 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /code.multi.lua: -------------------------------------------------------------------------------- 1 | -- keysetup format for each key: 2 | -- {event_register,event_number,{args...},{actions...}} 3 | -- args -> hash map 4 | -- actions -> array -> hash-map (key "action" always set to action name and key "key" always set to the name of the key to press) 5 | -- remember arrays are 1 based not 0 based in lua 6 | 7 | keysetup = {{"G_PRESSED",4,{},{{action="toggle_key",key="f"},{action="tap_key",key="x",count=3,duration=30,delay=20}}},{"TIMED",5,{time=1500,event_prefix="G"},{{{action="toggle_key",key="a"}},{{action="toggle_key",key="b"}}}}}; 8 | 9 | logging = true; 10 | 11 | -- do not change the code below 12 | OutputLogMessage("Script initialized\nWritten by: Douile\nhttps://github.com/Douile/logitech-toggle-keys/\n"); 13 | for i,v in pairs(keysetup) do 14 | OutputLogMessage("%s:%d registered...\n",v[1],v[2]); 15 | end 16 | OutputLogMessage("\n- start runtime log -\n"); 17 | 18 | keyspressed = {}; 19 | keytimes = {}; 20 | 21 | function update_key(key,state) 22 | if (state == true) then 23 | PressKey(key); 24 | keyspressed[key] = true; 25 | word = "Pressed"; 26 | else 27 | ReleaseKey(key); 28 | keyspressed[key] = nil; 29 | word = "Released" 30 | end 31 | if (logging == true) then 32 | OutputLogMessage("+%d - %s %s\n",GetRunningTime(),word,key); 33 | end 34 | end 35 | 36 | function handle_custom_events(setup_info,event,arg) 37 | -- handle custom listeners such as G keys held 38 | if (setup_info[1] == "TIMED") then 39 | prefix = setup_info[3]["event_prefix"]; 40 | if (event == prefix.."_PRESSED" and setup_info[2] == arg) then 41 | id = string.format("%s_%d",prefix,arg); 42 | keytimes[id] = GetRunningTime(); 43 | if (logging == true) then 44 | OutputLogMessage("+%d - Starting holding %s\n",GetRunningTime(),id); 45 | end 46 | elseif (event == prefix.."_RELEASED" and setup_info[2] == arg) then 47 | id = string.format("%s_%d",prefix,arg); 48 | time_held = GetRunningTime()-keytimes[id]; 49 | keytimes[id] = nil; 50 | -- possibly add support for multiple time ranges of time held 51 | if (time_held < setup_info[3]["time"]) then 52 | dispatch_actions(setup_info[3],setup_info[4][1]); 53 | else 54 | dispatch_actions(setup_info[3],setup_info[4][2]); 55 | end 56 | end 57 | return true; 58 | end 59 | return false; 60 | end 61 | 62 | function dispatch_actions(args,actions) 63 | for i,action in pairs(actions) do 64 | v = action["action"]; 65 | key = action["key"]; 66 | if (v == "toggle_key") then 67 | if (keyspressed[key] == true) then 68 | update_key(key,false); 69 | else 70 | update_key(key,true); 71 | end 72 | elseif (v == "press_key") then 73 | update_key(key,true); 74 | elseif (v == "release_key") then 75 | update_key(key,false); 76 | elseif (v == "tap_key") then 77 | for n=0,action["count"],1 do 78 | PressKey(key); 79 | Sleep(action["duration"]); 80 | ReleaseKey(key); 81 | Sleep(action["delay"]); 82 | end 83 | end 84 | end 85 | end 86 | 87 | function OnEvent(event, arg) 88 | for i,v in pairs(keysetup) do 89 | did_custom = handle_custom_events(v,event,arg); 90 | if (did_custom == false) then -- (not did_custom) 91 | if (event == v[1] and arg == v[2]) then 92 | dispatch_actions(v[3],v[4]); 93 | end 94 | end 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /docs/APIDocs.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Douile/logitech-toggle-keys/46a845003a6c6168b97d4f2d30e513e71c5977cb/docs/APIDocs.pdf -------------------------------------------------------------------------------- /docs/generator.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ToggleKeys 6 | 7 | 8 | 9 | 105 | 106 | 107 | 112 |
113 |
Press any key to continue...
114 |
115 | 116 |
117 |
118 |

Press any key to continue...

119 |
120 |
121 | 122 |
123 |
124 | 125 |

Enter file name

126 |
127 | 128 | 129 |
130 |
131 | 132 |
133 |
134 | 135 |

Help

136 |
137 | 138 | 139 |
140 |

This page generates a lua script for toggling and tapping keys in the logitech gaming framework.

141 |
142 | 143 | 144 |
145 |

If a key you're inputting is not working simply right click on the key box and type in the key code found in Appendix A of the API documentation.

146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 | Toggle Keys Script Generator 155 | 156 | 157 | 158 | 159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 | 170 | 171 | 172 | 173 |
174 |
175 |
176 |

177 |   
178 | 179 | 180 | -------------------------------------------------------------------------------- /docs/generator.js: -------------------------------------------------------------------------------- 1 | // sorry about this messy ass code 2 | 3 | const OUTPUT_TEMPLATE = atob('LS0gY2hvb3NlIHlvdXIga2V5cyBoZXJlCmtleXNldHVwID0gJXNldHVwJTsKLS0gaWYgdXNpbmcgbW91c2Ugc2V0IHRvIHRydWUKbW91c2UgPSAlbW91c2UlOwotLSBzZXQgdG8gdHJ1ZSB0byBsb2cgYWxsIGJ1dHRvbiBwcmVzc2VzICh1c2VmdWwgd2hlbiB5b3UgZG9uJ3Qga25vdyB3aGF0IG51bWJlciBhIGtleSBpcykKbG9nYWxsID0gJWxvZyU7Ci0tIGNoYW5nZSB0aGUgZGVsYXkgYmV0d2VlbiB0YXBzCnRhcF9kZWxheSA9ICVkZWxheSU7CnRhcF9ob2xkX2RlbGF5ID0gJWhvbGRfZGVsYXklOwoKLS0gZG8gbm90IGNoYW5nZSB0aGUgY29kZSBiZWxvdwpPdXRwdXRMb2dNZXNzYWdlKCJTY3JpcHQgaW5pdGlhbGl6ZWRcbldyaXR0ZW4gYnk6IERvdWlsZVxuIik7CmlmIChtb3VzZSA9PSB0cnVlKSB0aGVuCiAgZXZlbnRsaXN0ZW4gPSAiTU9VU0VfQlVUVE9OX1BSRVNTRUQiOwogIE91dHB1dExvZ01lc3NhZ2UoIkNvbmZpZ3VyZWQgZm9yIG1vdXNlIGJ1dHRvbnNcbiIpOwplbHNlCiAgZXZlbnRsaXN0ZW4gPSAiR19QUkVTU0VEIjsKICBPdXRwdXRMb2dNZXNzYWdlKCJDb25maWd1cmVkIGZvciBrZXlib2FyZCBidXR0b25zXG4iKTsKZW5kCmZvciBrLHYgaW4gcGFpcnMoa2V5c2V0dXApIGRvCiAgT3V0cHV0TG9nTWVzc2FnZSgiQnV0dG9uICVkIHdpbGwgdG9nZ2xlICVzICglZCBwcmVzc2VzKVxuIix2WzFdLGssdlsyXSk7CmVuZApPdXRwdXRMb2dNZXNzYWdlKCJcbi0gc3RhcnQgcnVudGltZSBsb2cgLVxuIik7CgprZXlzcHJlc3NlZCA9IHt9OwoKZnVuY3Rpb24gT25FdmVudChldmVudCwgYXJnKQogIGlmIChldmVudCA9PSBldmVudGxpc3RlbikgdGhlbgogICAgaWYgKGxvZ2FsbCA9PSB0cnVlKSB0aGVuCiAgICAgIE91dHB1dExvZ01lc3NhZ2UoIktleSAlZCBwcmVzc2VkXG4iLGFyZyk7CiAgICBlbmQKICAgIGZvciBrLHYgaW4gcGFpcnMoa2V5c2V0dXApIGRvCiAgICAgIGlmIChhcmcgPT0gdlsxXSBhbmQgayB+PSBudWxsKSB0aGVuCiAgICAgICAgaWYgKGtleXNwcmVzc2VkW2tdID09IHRydWUpIHRoZW4KICAgICAgICAgIFJlbGVhc2VLZXkoayk7CiAgICAgICAgICBrZXlzcHJlc3NlZFtrXSA9IGZhbHNlOwogICAgICAgICAgT3V0cHV0TG9nTWVzc2FnZSgiUmVjaWV2ZWQgJXMgJWQgcmVsZWFzZWQgJXNcbiIsZXZlbnQsdlsxXSxrKTsKICAgICAgICAgIE91dHB1dExDRE1lc3NhZ2Uoc3RyaW5nLmZvcm1hdCgiUHJlc3NpbmcgJXMiLGspKTsKICAgICAgICBlbHNlCiAgICAgICAgICBmb3IgaT0wLHZbMl0gZG8KICAgICAgICAgICAgUHJlc3NLZXkoayk7CiAgICAgICAgICAgIFNsZWVwKHRhcF9ob2xkX2RlbGF5KTsKICAgICAgICAgICAgUmVsZWFzZUtleShrKTsKICAgICAgICAgICAgU2xlZXAodGFwX2RlbGF5KTsKICAgICAgICAgIGVuZAogICAgICAgICAgUHJlc3NLZXkoayk7CiAgICAgICAgICBrZXlzcHJlc3NlZFtrXSA9IHRydWU7CiAgICAgICAgICBPdXRwdXRMb2dNZXNzYWdlKCJSZWNpZXZlZCAlcyAlZCBwcmVzc2VkICVzXG4iLGV2ZW50LHZbMV0sayk7CiAgICAgICAgICBPdXRwdXRMQ0RNZXNzYWdlKHN0cmluZy5mb3JtYXQoIlJlbGVhc2luZyAlcyIsaykpOwogICAgICAgIGVuZAogICAgICBlbmQKICAgIGVuZAogIGVuZAplbmQK'); 4 | 5 | 6 | const VALUES = { 7 | get deviceType() { 8 | return document.querySelector('select[name=device-type]').value; 9 | }, 10 | get logging() { 11 | return document.querySelector('input[name=logging]').checked; 12 | }, 13 | set active(value) { 14 | let dom = document.querySelector('#toggle-no'); 15 | dom.innerText = value; 16 | }, 17 | get toggleCount() { 18 | return document.querySelectorAll('.toggle').length; 19 | }, 20 | get toggleContainer() { 21 | return document.querySelector('.inputs'); 22 | }, 23 | get toggles() { 24 | var output = [], 25 | nodes = document.querySelectorAll('.toggle'); 26 | for (var i=0;i select').value, 31 | 'taps': node.querySelector('.number-input > input').value 32 | }; 33 | output.push(nodeData); 34 | } 35 | return output; 36 | }, 37 | get tapDelay() { 38 | return document.querySelector('input[name=tap-delay]').value; 39 | }, 40 | get tapHoldDelay() { 41 | return document.querySelector('input[name=tap-hold-delay]').value; 42 | }, 43 | addToggle: function() { 44 | let dom = VALUES.newToggle(); 45 | VALUES.toggleContainer.appendChild(dom); 46 | VALUES.active = VALUES.toggleCount; 47 | Actions.update(); 48 | }, 49 | newToggle: function() { 50 | let dom = document.createElement('div'); 51 | dom.setAttribute('class','toggle row'); 52 | let key = VALUES.elements.newKey(); 53 | dom.appendChild(key); 54 | let button = VALUES.elements.newButton(); 55 | dom.appendChild(button); 56 | let number = VALUES.elements.newNumber(); 57 | dom.appendChild(number); 58 | let spacer = VALUES.elements.newSpacer(); 59 | dom.appendChild(spacer); 60 | let remove = VALUES.elements.newRemove(); 61 | dom.appendChild(remove); 62 | return dom; 63 | }, 64 | 'elements': { 65 | newKey: function() { 66 | var dom = document.createElement('div'); 67 | dom.setAttribute('class','col-sm-2'); 68 | let span = document.createElement('span'); 69 | span.setAttribute('class','tooltip'); 70 | span.setAttribute('aria-label','Right click me for manual input'); 71 | dom.appendChild(span); 72 | let input = document.createElement('input'); 73 | input.setAttribute('type','text'); 74 | input.setAttribute('placeholder','Key'); 75 | input.setAttribute('class','toggle-key'); 76 | input.addEventListener('click',Actions.keyHandler); 77 | input.addEventListener('contextmenu',Actions.keyContHandler); 78 | span.appendChild(input); 79 | return dom; 80 | }, 81 | newButton: function() { 82 | var dom = document.createElement('div'); 83 | dom.setAttribute('class','col-sm-2 toggle-button'); 84 | let label = document.createElement('label'); 85 | label.innerText = 'Button: '; 86 | dom.appendChild(label); 87 | let select = document.createElement('select'); 88 | let optionKeyCount = 18; 89 | for (var x=1;x < optionKeyCount+1;x++) { 90 | let option = document.createElement('option'); 91 | option.innerText = `G${x}`; 92 | option.setAttribute('value',x); 93 | select.appendChild(option); 94 | } 95 | dom.appendChild(select); 96 | dom.addEventListener('change',Actions.update); 97 | return dom; 98 | }, 99 | newRemove: function() { 100 | var dom = document.createElement('div'); 101 | dom.setAttribute('class','col-sm-1'); 102 | let input = document.createElement('input'); 103 | input.setAttribute('type','submit'); 104 | input.setAttribute('value','Remove'); 105 | input.addEventListener('click',Actions.closeInput); 106 | dom.appendChild(input); 107 | return dom; 108 | }, 109 | newNumber: function() { 110 | var dom = document.createElement('div'); 111 | dom.setAttribute('class','col-sm-2 number-input'); 112 | let label = document.createElement('label'); 113 | label.innerText = 'Tap count: '; 114 | dom.appendChild(label); 115 | let input = document.createElement('input'); 116 | input.setAttribute('type','text'); 117 | input.setAttribute('value','0'); 118 | input.setAttribute('class','number') 119 | // input.addEventListener('keydown',Actions.numberHandlerStart); 120 | // input.addEventListener('keyup',Actions.numberHandlerEnd); 121 | dom.appendChild(input); 122 | return dom; 123 | }, 124 | newSpacer: function() { 125 | var dom = document.createElement('div'); 126 | dom.setAttribute('class','col-sm-5'); 127 | return dom; 128 | } 129 | } 130 | } 131 | 132 | const Actions = { 133 | closeInput: function(e) { 134 | e.target.parentNode.parentNode.remove(); 135 | VALUES.active = VALUES.toggleCount; 136 | Actions.update(); 137 | }, 138 | keyHandler: function(e) { 139 | if (e.button === 0) { 140 | Actions.keyInput(e); 141 | } else if (e.button === 2) { 142 | Actions.keyManual(e); 143 | } 144 | }, 145 | keyContHandler: function(e) { 146 | e.preventDefault(); 147 | Actions.keyManual(e); 148 | }, 149 | keyManual: function(e) { 150 | var key = prompt('Manually input key code',''); 151 | e.target.value = key; 152 | e.target.blur(); 153 | Actions.update(); 154 | }, 155 | keyInput: function(e) { 156 | //e.target.blur(); 157 | e.target.setAttribute('active-key',''); 158 | document.querySelector('#key-modal').checked = true; 159 | }, 160 | captureKey: function(e) { 161 | let keyCapture = document.querySelector('#key-modal'); 162 | if (keyCapture.checked === true) { 163 | e.preventDefault(); 164 | let key = parseKey(e.code); 165 | let node = document.querySelector('.toggle-key[active-key]'); 166 | node.value = key; 167 | node.removeAttribute('active-key'); 168 | node.blur(); 169 | keyCapture.checked = false; 170 | Actions.update(); 171 | } 172 | }, 173 | update: function() { 174 | output(); 175 | }, 176 | copy: function() { 177 | Actions.update(); 178 | var text = document.querySelector('#output-area').innerText; 179 | copyTextToClipboard(text); 180 | toast('Copied...',1500,500); 181 | }, 182 | save: function() { 183 | Actions.update(); 184 | var text = document.querySelector('#output-area').innerText; 185 | var filename = document.querySelector('input[name=download_name]').value; 186 | if (filename !== null) { 187 | saveTextFile(filename,text); 188 | } 189 | }, 190 | help: function() { 191 | alert('HELP\nClick key button to input a key (WARNING f keys still do normal function).\nIf unable to input key you can manually input the keyname by right clicking key button\n'); 192 | }, 193 | numberHandlerStart: function(e) { 194 | if (e.key.match(/[^0-9]/) && e.key !== 'Backspace') { 195 | e.preventDefault(); 196 | } 197 | }, 198 | numberHandlerEnd: function(e) { 199 | e.target.value = e.target.value.replace(/[^0-9]/g,''); 200 | let n = parseInt(e.target.value).toString(); 201 | if (isNaN(n)) { 202 | n = 0; 203 | } 204 | e.target.value = n.toString(); 205 | Actions.update(); 206 | } 207 | } 208 | 209 | function parseKey(code) { 210 | console.log(code); 211 | var key = code; 212 | // too much regex. idc 213 | if (/^key[a-z]$/i.test(code)) { 214 | key = code.substr(3,1); 215 | } else if (/^digit[0-9]$/i.test(code)) { 216 | key = code.substr(5,1); 217 | } else if (/^f[0-9]{1,2}$/i.test(code)) { 218 | key = code; 219 | } else if (/^numpad[0-9]$/i.test(code)) { 220 | key = 'num'+code.substr(6,1); 221 | } else if (/^arrow(?:up|down|left|right)$/i.test(code)) { 222 | key = code.substr(5); 223 | } else if (/^bracket(?:left|right)$/i.test(code)) { 224 | key = code.substr(7,1)+'bracket'; 225 | } else if (/^shift(?:left|right)$/i.test(code)) { 226 | key = code.substr(5,1)+'shift'; 227 | } else if (/^control(?:left|right)$/i.test(code)) { 228 | key = code.substr(7,1)+'ctrl'; 229 | } else if (/^alt(?:left|right)$/i.test(code)) { 230 | key = code.substr(3,1)+'alt'; 231 | } else if (/^intlbackslash$/i.test(code)) { 232 | key = 'backslash'; 233 | } else if (/^backquote$/i.test(code)) { 234 | key = 'tilde'; 235 | } else if (/^numpaddivide$/i.test(code)) { 236 | key = 'numslash'; 237 | } else if (/^numpadmultiply$/i.test(code)) { 238 | key = 'nummult'; // not sure about this one 239 | } else if (/^numpadadd$/i.test(code)) { 240 | key = 'numplus'; 241 | } else if (/^numpadsubtract$/i.test(code)) { 242 | key = 'numminus'; 243 | } else if (/^numpadenter$/i.test(code)) { 244 | key = 'numenter'; 245 | } else if (/^numpaddecimal$/i.test(code)) { 246 | key = 'numperiod'; 247 | } 248 | key = key.toLowerCase(); 249 | return key; 250 | } 251 | 252 | function output() { 253 | var mouse = VALUES.deviceType === 'Mouse' ? 'true' : 'false'; 254 | var log = VALUES.logging; 255 | var tapDelay = VALUES.tapDelay; 256 | var tapHoldDelay = VALUES.tapHoldDelay; 257 | var keySetup = '{'; 258 | var keys = VALUES.toggles; 259 | for (var i=0;i 0) { 285 | setTimeout(update,interval); 286 | } else { 287 | node.remove(); 288 | } 289 | } 290 | setTimeout(update,delay); 291 | } 292 | 293 | function init() { 294 | VALUES.addToggle(); 295 | document.querySelector('#add-toggle').addEventListener('click',VALUES.addToggle); 296 | window.addEventListener('keydown',Actions.captureKey); 297 | document.querySelector('input[name=logging]').addEventListener('click',Actions.update); 298 | document.querySelector('select[name=device-type]').addEventListener('change',Actions.update); 299 | document.querySelector('#copy-output').addEventListener('click',Actions.copy); 300 | document.querySelector('#download-output').addEventListener('click',Actions.save); 301 | document.querySelector('label[for=download-modal]').addEventListener('click',() => { 302 | document.querySelector('input[name=download_name]').value = 'toggle_keys.lua'; 303 | }) 304 | // document.querySelector('#help').addEventListener('click',Actions.help); 305 | window.addEventListener('keydown',(e) => { 306 | if (e.target.tagName === 'INPUT') { 307 | if (e.target.classList.contains('number')) { 308 | Actions.numberHandlerStart(e); 309 | } 310 | } 311 | }); 312 | window.addEventListener('keyup',(e) => { 313 | if (e.target.tagName === 'INPUT') { 314 | if (e.target.classList.contains('number')) { 315 | Actions.numberHandlerEnd(e); 316 | } 317 | } 318 | }); 319 | } 320 | 321 | init(); 322 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Douile/logitech-toggle-keys 5 | 11 | 12 | 13 |

Your viewing the home page for github/douile/logitech-toggle-keys

14 |

Links

15 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/io.js: -------------------------------------------------------------------------------- 1 | // https://stackoverflow.com/a/30810322 2 | 3 | function fallbackCopyTextToClipboard(text) { 4 | var textArea = document.createElement("textarea"); 5 | textArea.value = text; 6 | document.body.appendChild(textArea); 7 | textArea.focus(); 8 | textArea.select(); 9 | 10 | try { 11 | var successful = document.execCommand('copy'); 12 | var msg = successful ? 'successful' : 'unsuccessful'; 13 | console.log('Fallback: Copying text command was ' + msg); 14 | } catch (err) { 15 | console.error('Fallback: Oops, unable to copy', err); 16 | } 17 | 18 | document.body.removeChild(textArea); 19 | } 20 | function copyTextToClipboard(text) { 21 | if (!navigator.clipboard) { 22 | fallbackCopyTextToClipboard(text); 23 | return; 24 | } 25 | navigator.clipboard.writeText(text).then(function() { 26 | console.log('Async: Copying to clipboard was successful!'); 27 | }, function(err) { 28 | console.error('Async: Could not copy text: ', err); 29 | }); 30 | } 31 | 32 | function saveTextFile(filename,text) { 33 | var blob = new Blob([text],{'type':'text/plain'}); 34 | var url = URL.createObjectURL(blob); 35 | var a = document.createElement('a'); 36 | a.href = url; 37 | a.download = filename; 38 | document.body.appendChild(a); 39 | a.click(); 40 | a.remove(); 41 | URL.revokeObjectURL(url); 42 | } 43 | -------------------------------------------------------------------------------- /docs/tutorial_images/copy.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Douile/logitech-toggle-keys/46a845003a6c6168b97d4f2d30e513e71c5977cb/docs/tutorial_images/copy.JPG -------------------------------------------------------------------------------- /docs/tutorial_images/saved.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Douile/logitech-toggle-keys/46a845003a6c6168b97d4f2d30e513e71c5977cb/docs/tutorial_images/saved.JPG -------------------------------------------------------------------------------- /docs/tutorial_images/scripting.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Douile/logitech-toggle-keys/46a845003a6c6168b97d4f2d30e513e71c5977cb/docs/tutorial_images/scripting.JPG -------------------------------------------------------------------------------- /docs/tutorial_images/unsaved.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Douile/logitech-toggle-keys/46a845003a6c6168b97d4f2d30e513e71c5977cb/docs/tutorial_images/unsaved.JPG -------------------------------------------------------------------------------- /mouse.lua: -------------------------------------------------------------------------------- 1 | -- https://community.logitech.com/s/question/0D75A000004H5ihSAC/ 2 | -- this is a modified version of my original script designed to press a key when a button is pressed or released 3 | keysetup = {b=4}; 4 | 5 | eventlisten = {"MOUSE_BUTTON_PRESSED","MOUSE_BUTTON_RELEASED"}; 6 | -- uncomment below if buttons not working 7 | --eventlisten = {"M_PRESSED","M_RELEASED"}; 8 | 9 | -- do not change the code below 10 | local function contains(arr, item) 11 | for key, value in pairs(arr) do 12 | if value == item then 13 | return true 14 | end 15 | end 16 | return false 17 | end 18 | 19 | OutputLogMessage("Script initialized\nWritten by: Douile\n"); 20 | for k,v in pairs(keysetup) do 21 | OutputLogMessage("Mouse button %d will toggle %s\n",v,k); 22 | if (v == 1 and (contains(eventlisten,"MOUSE_BUTTON_PRESSED") or contains(eventlisten,"MOUSE_BUTTON_RELEASED"))) then 23 | EnablePrimaryMouseButtonEvents(true); 24 | end 25 | end 26 | OutputLogMessage("\n- start runtime log -\n"); 27 | 28 | 29 | function OnEvent(event, arg) 30 | if (contains(eventlisten,event)) then 31 | for k,v in pairs(keysetup) do 32 | if (arg == v and k ~= null) then 33 | PressAndReleaseKey(k); 34 | OutputLogMessage("Received button %d event: pressed %s\n",v,k); 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /template.lua: -------------------------------------------------------------------------------- 1 | -- choose your keys here 2 | keysetup = %setup%; 3 | -- if using mouse set to true 4 | mouse = %mouse%; 5 | -- set to true to log all button presses (useful when you don't know what number a key is) 6 | logall = %log%; 7 | -- change the delay between taps 8 | tap_delay = %delay%; 9 | tap_hold_delay = %hold_delay%; 10 | 11 | -- do not change the code below 12 | OutputLogMessage("Script initialized\nWritten by: Douile\n"); 13 | if (mouse == true) then 14 | eventlisten = "MOUSE_BUTTON_PRESSED"; 15 | OutputLogMessage("Configured for mouse buttons\n"); 16 | else 17 | eventlisten = "G_PRESSED"; 18 | OutputLogMessage("Configured for keyboard buttons\n"); 19 | end 20 | for k,v in pairs(keysetup) do 21 | OutputLogMessage("Button %d will toggle %s (%d presses)\n",v[1],k,v[2]); 22 | end 23 | OutputLogMessage("\n- start runtime log -\n"); 24 | 25 | keyspressed = {}; 26 | 27 | function OnEvent(event, arg) 28 | if (event == eventlisten) then 29 | if (logall == true) then 30 | OutputLogMessage("Key %d pressed\n",arg); 31 | end 32 | for k,v in pairs(keysetup) do 33 | if (arg == v[1] and k ~= null) then 34 | if (keyspressed[k] == true) then 35 | ReleaseKey(k); 36 | keyspressed[k] = false; 37 | OutputLogMessage("Recieved %s %d released %s\n",event,v[1],k); 38 | OutputLCDMessage(string.format("Pressing %s",k)); 39 | else 40 | for i=0,v[2] do 41 | PressKey(k); 42 | Sleep(tap_hold_delay); 43 | ReleaseKey(k); 44 | Sleep(tap_delay); 45 | end 46 | PressKey(k); 47 | keyspressed[k] = true; 48 | OutputLogMessage("Recieved %s %d pressed %s\n",event,v[1],k); 49 | OutputLCDMessage(string.format("Releasing %s",k)); 50 | end 51 | end 52 | end 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /template.lua.b64: -------------------------------------------------------------------------------- 1 | LS0gY2hvb3NlIHlvdXIga2V5cyBoZXJlDQprZXlzZXR1cCA9ICVzZXR1cCU7DQotLSBpZiB1c2luZyBtb3VzZSBzZXQgdG8gdHJ1ZQ0KbW91c2UgPSAlbW91c2UlOw0KLS0gc2V0IHRvIHRydWUgdG8gbG9nIGFsbCBidXR0b24gcHJlc3NlcyAodXNlZnVsIHdoZW4geW91IGRvbid0IGtub3cgd2hhdCBudW1iZXIgYSBrZXkgaXMpDQpsb2dhbGwgPSAlbG9nJTsNCi0tIGNoYW5nZSB0aGUgZGVsYXkgYmV0d2VlbiB0YXBzDQp0YXBfZGVsYXkgPSAlZGVsYXklOw0KdGFwX2hvbGRfZGVsYXkgPSAlaG9sZF9kZWxheSU7DQoNCi0tIGRvIG5vdCBjaGFuZ2UgdGhlIGNvZGUgYmVsb3cNCk91dHB1dExvZ01lc3NhZ2UoIlNjcmlwdCBpbml0aWFsaXplZFxuV3JpdHRlbiBieTogRG91aWxlXG4iKTsNCmlmIChtb3VzZSA9PSB0cnVlKSB0aGVuDQogIGV2ZW50bGlzdGVuID0gIk1PVVNFX0JVVFRPTl9QUkVTU0VEIjsNCglPdXRwdXRMb2dNZXNzYWdlKCJDb25maWd1cmVkIGZvciBtb3VzZSBidXR0b25zXG4iKTsNCmVsc2UNCglldmVudGxpc3RlbiA9ICJHX1BSRVNTRUQiOw0KCU91dHB1dExvZ01lc3NhZ2UoIkNvbmZpZ3VyZWQgZm9yIGtleWJvYXJkIGJ1dHRvbnNcbiIpOw0KZW5kDQpmb3Igayx2IGluIHBhaXJzKGtleXNldHVwKSBkbw0KCU91dHB1dExvZ01lc3NhZ2UoIkJ1dHRvbiAlZCB3aWxsIHRvZ2dsZSAlcyAoJWQgcHJlc3NlcylcbiIsdlsxXSxrLHZbMl0pOw0KZW5kDQpPdXRwdXRMb2dNZXNzYWdlKCJcbi0gc3RhcnQgcnVudGltZSBsb2cgLVxuIik7DQoNCmtleXNwcmVzc2VkID0ge307DQoNCmZ1bmN0aW9uIE9uRXZlbnQoZXZlbnQsIGFyZykNCiAgaWYgKGV2ZW50ID09IGV2ZW50bGlzdGVuKSB0aGVuDQogICAgaWYgKGxvZ2FsbCA9PSB0cnVlKSB0aGVuDQogICAgICBPdXRwdXRMb2dNZXNzYWdlKCJLZXkgJWQgcHJlc3NlZFxuIixhcmcpOw0KICAgIGVuZA0KICAgIGZvciBrLHYgaW4gcGFpcnMoa2V5c2V0dXApIGRvDQogICAgICBpZiAoYXJnID09IHZbMV0gYW5kIGsgfj0gbnVsbCkgdGhlbg0KICAgICAgICAgIGlmIChrZXlzcHJlc3NlZFtrXSA9PSB0cnVlKSB0aGVuDQogICAgICAgICAgICBSZWxlYXNlS2V5KGspOw0KICAgICAgICAgICAga2V5c3ByZXNzZWRba10gPSBmYWxzZTsNCiAgICAgICAgICAgIE91dHB1dExvZ01lc3NhZ2UoIlJlY2lldmVkICVzICVkIHJlbGVhc2VkICVzXG4iLGV2ZW50LHZbMV0sayk7DQogICAgICAgICAgICBPdXRwdXRMQ0RNZXNzYWdlKHN0cmluZy5mb3JtYXQoIlByZXNzaW5nICVzIixrKSk7DQogICAgICAgICAgZWxzZQ0KICAgICAgICAgICAgZm9yIGk9MCx2WzJdIGRvDQogICAgICAgICAgICAgIFByZXNzS2V5KGspOw0KICAgICAgICAgICAgICBTbGVlcCh0YXBfaG9sZF9kZWxheSk7DQogICAgICAgICAgICAgIFJlbGVhc2VLZXkoayk7DQogICAgICAgICAgICAgIFNsZWVwKHRhcF9kZWxheSk7DQogICAgICAgICAgICBlbmQNCiAgICAgICAgICAgIFByZXNzS2V5KGspOw0KICAgICAgICAgICAga2V5c3ByZXNzZWRba10gPSB0cnVlOw0KICAgICAgICAgICAgT3V0cHV0TG9nTWVzc2FnZSgiUmVjaWV2ZWQgJXMgJWQgcHJlc3NlZCAlc1xuIixldmVudCx2WzFdLGspOw0KICAgICAgICAgICAgT3V0cHV0TENETWVzc2FnZShzdHJpbmcuZm9ybWF0KCJSZWxlYXNpbmcgJXMiLGspKTsNCiAgICAgICAgICBlbmQNCiAgICAgICAgZW5kDQogICAgICBlbmQNCiAgICBlbmQNCiAgZW5kDQplbmQNCg== --------------------------------------------------------------------------------