Jump to content

JimmyTheSaint

Member
  • Posts

    46
  • Joined

  • Last visited

Everything posted by JimmyTheSaint

  1. Thanks for introducing me to that debugger. Here's the screenshot. I guess it's some kind of n00bish mistake on my part, but I don't see it.
  2. What's the principle that it depends on? The workflow fails for me on every file I try in Path Finder, and I've tried mp3, text, doc, and pdf files. I select the Send via AirDrop workflow from the file actions, and nothing happens at all.
  3. In workflows, the hotkey feature requires hotkeys to use special characters (ctrl, opt, shift, cmd). As a touch-typist, it's greatly preferable to keep your fingers on the home row, and special characters require moving your hands away, slowing operating my keyboard down. I would like to be able to use simultaneous key presses to launch workflows. For example, simultaneously press the 'g' and 'n' keys to launch a bookmark to Google News. Because the key presses have to be simultaneous, the 'g' and 'n' keys would continue to function normally for typing text. The addition of non-special character 2-key chords would enable a lot of hotkey combos to sit comfortably under your fingers while your hands remain in the home position. I currently use Karabiner-Elements to map two-key chords to workflow external triggers, but if I could do these chords entirely within Alfred, I could streamline my computer configuration. From my experience with Karabiner, I've found that 3-chords and greater are less ergonomic, but that I type 2-key chords with 100% accuracy. I set up my most frequently used chords so that they're compact enough to actuate one-handed. I can then make the computer do stuff from arm's length, without actually sitting down at it.
  4. Thanks for this. It works for me when selecting files in Finder, but I user Path Finder as a Finder replacement, and it doesn't work with files selected in Path Finder. The Air Drop window simply never opens. Is there a fix?
  5. I did those two things, but there is no change, with the console listing the same sequence of messages. When I ran ffass, Alfred showed the message, "Registered. Re-open Firefox extension to connect." When I did the alternative method, I got this stuff posted in the terminal: Last login: Thu Jul 23 23:54:23 on console e@GRAY ~ % /Users/e/Documents/var/computing/MacOS/Alfred/GRAY16/Alfred.alfredpreferences/workflows/user.workflow.159A6778-728D-47CD-8977-213AB04106F0/alfred-firefox ; exit; panic: invalid Workflow environment: alfred_workflow_bundleid is not set, alfred_workflow_cache is not set, alfred_workflow_data is not set goroutine 1 [running]: github.com/deanishe/awgo.NewFromEnv(0x0, 0x0, 0xc0001260c0, 0x3, 0x3, 0xc0001260c0) /Users/daj/pkg/mod/github.com/deanishe/awgo@v0.22.1/workflow.go:159 +0xbe3 github.com/deanishe/awgo.New(0xc0001260c0, 0x3, 0x3, 0xc0001260a0) /Users/daj/pkg/mod/github.com/deanishe/awgo@v0.22.1/workflow.go:149 +0x47 main.init() /Users/daj/Code/Alfred/alfred-firefox-assistant/main.go:53 +0x360 [Process completed]
  6. I think it needs another update. I get this warning.
  7. Here's what was generated in the "Console" tab when I opened the extension: [popup] started popup.js:36:11 connected to popup alfred.js:118:13 received message Object { command: "status" } alfred.js:127:13 sent message Object { status: "disconnected" } alfred.js:123:13 [popup] status=disconnected popup.js:14:15 received message Object { command: "status" } alfred.js:127:13 sent message Object { status: "disconnected" } alfred.js:123:13 received message Object { command: "reconnect" } alfred.js:127:13 reconnecting to native app ... alfred.js:134:19 [popup] status=disconnected popup.js:14:15 native client connection failed: alfred.js:172:13 received message Object { command: "status" } alfred.js:127:13 sent message Object { status: "disconnected" } alfred.js:123:13 received message Object { command: "reconnect" } alfred.js:127:13 reconnecting to native app ... alfred.js:134:19 [popup] status=disconnected popup.js:14:15 native client connection failed:
  8. Also, I'm attaching a screenshot of the debugger in case you need me to access something else from it:
  9. I was only guessing that a "stack trace" was important. I had no idea the extension debugger was the important one because when I opened it, it seemed to show a lot less information than the log. Now I see if I click on the part on the left side that says "JS alfred.js" it shows a lot of info. I'm pasting that info here: /* global browser */ /** * Name of native application according to application manifest. * @var {string} appName */ const appName = 'net.deanishe.alfred.firefox'; const iconConnected = 'icons/bowler.svg'; const iconDisconnected = 'icons/bowler-red.svg'; /** * Tab object. * @param {tabs.Tab} tab - Native tab object to create Tab from. * @return {Object} - API Tab object. */ const Tab = tab => { let obj = {}; tab = tab || {}; obj.id = tab.id || 0; obj.windowId = tab.windowId || 0; obj.index = tab.index || 0; obj.title = tab.title || ''; obj.url = new URL(tab.url || ''); // obj.favicon = tab.favIconUrl || ''; obj.active = tab.active || false; obj.toString = function() { return `#${this.id} (${this.windowId}x${this.index}) "${this.title}" - ${this.url}`; }; return obj; }; /** * Bookmark object. * @param {bookmarks.BookmarkTreeNode} bm - Native object to create Bookmark from. * @return {Object} - API Bookmark object. */ const Bookmark = bm => { let obj = {}; bm = bm || {}; obj.id = bm.id || 0; obj.index = bm.index || 0; obj.title = bm.title || ''; obj.parentId = bm.parentId || 0; obj.type = bm.type || ''; obj.url = bm.url || ''; obj.toString = function() { return `#${this.id} "${this.title}" - ${this.url}`; }; return obj; }; /** * HistoryEntry object. * @param {history.HistoryItem} hi - Native object to create HistoryEntry from. * @return {Object} - API History object. */ const HistoryEntry = hi => { let obj = {}; hi = hi || {}; obj.id = hi.id || 0; obj.url = hi.url || ''; obj.title = hi.title || hi.url; obj.toString = function() { return `#${this.id} "${this.title}" - ${this.url}`; }; return obj; }; /** * Download object. * @param {downloads.DownloadItem} di - Native object to create Download from. * @return {Object} - API Download object. */ const Download = di => { let obj = {}; di = di || {}; obj.id = di.id || 0; obj.path = di.filename || ''; obj.size = di.fileSize || 0; obj.url = di.url || ''; obj.mime = di.mime || ''; obj.exists = di.exists || false; obj.error = di.error || ''; obj.toString = function() { return `#${this.id} "${this.path}" - ${this.url}`; }; return obj; }; /** * Extension application object. * @constructor */ const Background = function() { const self = this; self.port = null, self.nativePort = null, self.connected = false; self.onConnected = port => { self.port = port; port.onMessage.addListener(self.receive); console.debug('connected to popup'); }; self.send = msg => { self.port.postMessage(msg); console.debug('sent message', msg); }; self.receive = msg => { console.debug('received message', msg); if ('command' in msg) { switch (msg.command) { case 'status': self.send({ status: self.connected ? 'connected' : 'disconnected' }); return; case 'reconnect': console.debug('reconnecting to native app ...'); self.connectNative(); return; case 'reload': console.debug('reloading extension ...'); browser.runtime.reload(); return; } } }; self.connectNative = () => { self.connected = false; let listener = payload => { if (!self.connected) { self.connected = true; // self.nativePort.onDisconnect.removeListener(self.connectNativeFailed); self.onConnectedNative(); } self.receiveNative(payload); }; self.nativePort = browser.runtime.connectNative(appName); self.nativePort.onMessage.addListener(listener); self.nativePort.onDisconnect.addListener(self.connectNativeFailed); }; /** * Callback for connection failure. * Logs an error message to the console. */ self.connectNativeFailed = port => { let msg = ''; if (port.error) { msg = port.error.message; } self.connected = false; console.error(`native client connection failed: ${msg}`); browser.browserAction.setIcon({ path: iconDisconnected }); }; /** * Callback for successful connection to native application. * Logs a message to the console. */ self.onConnectedNative = () => { console.log('connected to native client'); browser.browserAction.setIcon({ path: iconConnected }); }; /** * Handle commands from native application. * @param {Object} msg - Data from native application. * @param {string} msg.id - Command/response ID. * @param {Object} msg.params - Arguments to command. */ self.receiveNative = msg => { console.log(`received:`, msg); let p = null; if ('command' in msg) { switch (msg.command) { case 'ping': p = self.ping(); break; // case 'all-windows': // p = self.allWindows(); // break; // case 'current-window': // p = self.currentWindow(); // break; case 'all-tabs': p = self.allTabs(); break; // DEPRECATED - replaced by self.tab(); unused by newer // versions 0.2.0+ of workflow // Remove from future versions case 'current-tab': p = self.tab(0); break; case 'tab': p = self.tab(msg.params); break; case 'all-bookmarks': p = self.allBookmarks(); break; case 'search-bookmarks': p = self.searchBookmarks(msg.params); break; case 'search-history': p = self.searchHistory(msg.params); break; case 'search-downloads': p = self.searchDownloads(msg.params); break; case 'activate-tab': p = self.activateTab(msg.params); break; case 'close-tabs-left': p = self.closeTabsLeft(msg.params); break; case 'close-tabs-right': p = self.closeTabsRight(msg.params); break; case 'close-tabs-other': p = self.closeTabsOther(msg.params); break; case 'execute-js': p = self.executeJS(msg.params); break; case 'run-bookmarklet': p = self.runBookmarklet(msg.params); break; case 'open-incognito': p = self.openIncognito(msg.params); break; default: console.error(`unknown command: ${msg.command}`); self.sendError(msg.id, 'unknown command'); return; } p.then(payload => { self.sendNative({ id: msg.id, payload: payload }); }).catch(err => { self.sendError(msg.id, err.message); }); } else { self.sendError(msg.id, 'no command given'); } }; /** * Send response to native application. * @param {Object} msg - Data to send to native application. * @param {string} msg.id - Command/response ID. * @param {string|bool|Object} msg.payload - Actual response data. * @param {string} msg.error - Error message if command failed. */ self.sendNative = msg => { if (self.nativePort) { self.nativePort.postMessage(msg) .then(resp => { console.log(`sent:`, msg); console.log(`response:`, resp); }) .catch(err => { console.error(`send error: ${err.message}`); }); } }; /** * Send error respones to native application. * @param {string} id - Command/response ID. * @param {string} msg - Error message. */ self.sendError = (id, msg) => { self.sendNative({ id: id, error: msg }); }; /** * Handle "ping" command. * @return {Promise} - Resolves to string "pong". */ self.ping = () => { return new Promise(resolve => { resolve('pong'); }); }; /** * Handle "all-tabs" command. * @return {Promise} - Resolves to array of Tab objects for all tabs. */ self.allTabs = () => { return browser.tabs.query({}).then(tabs => { return tabs.map(t => Tab(t)); }); }; /** * Handle "activate-tab" command. * @param {number} id - ID of tab to activate. */ self.activateTab = id => { return browser.tabs .update(id, { active: true }) .then(() => { return browser.tabs.get(id); }) .then(tab => { return browser.windows.update(tab.windowId, { focused: true }); }); }; /** * Handle "current-tab" command. * @return {Promise} - Resolves to Tab for current tab. * Throws an error if there is no current tab. */ // self.currentTab = () => { // return self.activeTab(null).then(t => { // if (!t) throw 'no current tab'; // let tab = Tab(t); // console.log(`[current-tab] ${tab}`); // return tab; // }); // }; /** * Handle "tab" command. * @param {number} tabId - ID of tab to return. * @return {Promise} - Resolves to Tab for current tab. * Throws an error if there is no current tab. */ self.tab = tabId => { if (!tabId) { return self.activeTab(null).then(t => { if (!t) throw 'no current tab'; let tab = Tab(t); console.log(`[current-tab] ${tab}`); return tab; }); } return browser.tabs .get(tabId) .then(t => { return Tab(t); }) }; /** * Handle "all-bookmarks" command. * @return {Promise} - Resolves to array of Bookmark objects for all bookmarks * and folders. */ self.allBookmarks = () => { let bookmarks = []; let addBookmarks = node => { if (node.url) bookmarks.push(Bookmark(node)); if (node.children) node.children.map(n => addBookmarks(n)); }; return browser.bookmarks.getTree().then(root => { addBookmarks(root[0]); return bookmarks; }); }; /** * Handle "search-bookmarks" command. * @param {string} query - Search query. * @return {Promies} - Resolves to array of Bookmark objects matching query. */ self.searchBookmarks = query => { return browser.bookmarks.search(query).then(nodes => { let bookmarks = nodes.filter(n => n.url).map(n => Bookmark(n)); console.debug(`${bookmarks.length} bookmark(s) for "${query}"`); return bookmarks; }); }; /** * Handle "search-history" command. * @param {string} query - Search query. * @return {Promies} - Resolves to array of History objects matching query. */ self.searchHistory = query => { return browser.history.search({ text: query, startTime: 0 }).then(items => { let history = items.filter(it => it.url).map(it => HistoryEntry(it)); console.debug(`${history.length} history item(s) for "${query}"`); return history; }); }; /** * Handle "search-downloads" command. * @param {string} query - Search query. * @return {Promise} - Resolves to array of Download objects matching query. */ self.searchDownloads = query => { return browser.downloads .search({ query: [query], exists: true, }) .then(items => { console.debug(`${items.length} download(s) for "${query}"`); return items.map(it => Download(it)); }); }; /** * Handle "close-tabs-left" command. * @param {number} tabId - ID of tab whose neighbours to close. * @return {Promise} - Result of browser.tabs.remove() */ self.closeTabsLeft = tabId => { console.debug(`closing tabs to left of tab #${tabId} ...`); let activeTab = null; return browser.tabs .get(tabId) .then(tab => { if (!tab) throw 'no current tab'; activeTab = tab; return browser.tabs.query({ windowId: tab.windowId }); }) .then(tabs => { let ids = tabs.filter(t => t.index < activeTab.index).map(t => t.id); return browser.tabs.remove(ids); }); }; /** * Handle "close-tabs-right" command. * @param {number} tabId - ID of tabs whose neighbours to close. * @return {Promise} - Result of browser.tabs.remove() */ self.closeTabsRight = tabId => { console.debug(`closing tabs to right of tab #${tabId} ...`); let activeTab = null; return browser.tabs .get(tabId) .then(tab => { if (!tab) throw 'no current tab'; activeTab = tab; return browser.tabs.query({ windowId: tab.windowId }); }) .then(tabs => { let ids = tabs.filter(t => t.index > activeTab.index).map(t => t.id); return browser.tabs.remove(ids); }); }; /** * Handle "close-tabs-other" command. * @param {number} tabId - ID of window to close tabs in. * @return {Promise} - Result of browser.tabs.remove() */ self.closeTabsOther = tabId => { console.debug(`closing other tabs in window of tab #${tabId} ...`); let activeTab = null; return browser.tabs .get(tabId) .then(tab => { activeTab = tab; return browser.tabs.query({ windowId: tab.windowId }); }) .then(tabs => { let ids = tabs.filter(t => t.id !== activeTab.id).map(t => t.id); return browser.tabs.remove(ids); }); }; /** Handle "execute-js" command. */ // self.executeJS = js => { // return browser.tabs.executeScript({ code: js }).then(results => { // console.debug(`js=${js}, results=`, results); // }); // }; /** * Handle "execute-js" command. * @param {Object} params - Tab and bookmarklet IDs. * @param {number} params.tabId - ID of tab to execute JS in. * If tabId is 0, JS is executed in the active tab. * @param {string} params.js - JavaScript to execute. */ self.executeJS = params => { console.debug(`execute-js`, params); var p; if (params.tabId) { p = browser.tabs.executeScript(params.tabId, { code: params.js }); } else { p = browser.tabs.executeScript({ code: params.js }); } return p.then(result => { return JSON.stringify(result); }); }; /** * Handle "run-bookmarklet" command. * @param {Object} params - Tab and bookmarklet IDs. * @param {number} params.tabId - ID of tab to execute bookmarklet in. * If tabId is 0, bookmarklet is executed in the active tab. * @param {string} params.bookmarkId - ID of bookmarklet to execute. */ self.runBookmarklet = params => { console.debug(`run-bookmarklet`, params); return browser.bookmarks.get(params.bookmarkId).then(bookmarks => { if (!bookmarks.length) throw 'bookmark not found'; let bm = bookmarks[0]; if (!bm.url.startsWith('javascript:')) throw 'not a bookmarklet'; let js = decodeURI(bm.url.slice(11)); if (params.tabId) browser.tabs.executeScript(params.tabId, { code: js }); else browser.tabs.executeScript({ code: js }); }); }; /** * Handle "open-incognito" command. * @param {string} url - URL to open in a new Incognito window. * @return {Promise} - Promise that resolves to null. */ self.openIncognito = url => { console.debug(`open-incognito ${url}`); return browser.windows.create({ incognito: true, url: url }); }; /** * Return active tab. * @param {number} winId - ID of window to get active tab of. * If 0 or null, current window is used. * @return {Promise} - Promise resolves to null or a tabs.Tab. */ self.activeTab = winId => { winId = winId || browser.windows.WINDOW_ID_CURRENT; return browser.tabs .query({ active: true, windowId: winId, }) .then(tabs => { if (tabs.length) return tabs[0]; return null; }); }; browser.runtime.onConnect.addListener(self.onConnected); self.connectNative(); console.log(`started`); }; browser.browserAction.setIcon({ path: iconDisconnected }); new Background();
  10. Can you help determine how to connect the extension to the workflow or what's preventing the extension from connecting to the workflow at the Firefox end? Not being a programmer, I don't have the first idea of what a stack trace is saying. I can follow instructions. I also have a second laptop set up almost identically, and it's got exactly the same error, so there's no new information there.
  11. I don't know exactly what this info implies, so I'm pasting the part from the log file that lists the first occurrence of the "dial unix" error. That Firefox extension debugger is totally beyond me. Is there some info from it I should post to shed light on the error? Should I post more of the log file? 18:51:57 [warning] info.plist not found. Guessed: /Users/e/Documents/var/computing/MacOS/Alfred/GRAY16/Alfred.alfredpreferences/workflows/user.workflow.159A6778-728D-47CD-8977-213AB04106F0 18:51:57 ----- Firefox Assistant/0.2.1 (AwGo/0.20.2) ------ 18:51:57 loaded URL action "Open in Firefox" from "~/Documents/var/computing/MacOS/Alfred/GRAY16/Alfred.alfredpreferences/workflows/user.workflow.159A6778-728D-47CD-8977-213AB04106F0/scripts/Open in Firefox.sh" 18:51:57 loaded URL action "Open in Safari" from "~/Documents/var/computing/MacOS/Alfred/GRAY16/Alfred.alfredpreferences/workflows/user.workflow.159A6778-728D-47CD-8977-213AB04106F0/scripts/Open in Safari.sh" 18:51:57 loaded URL action "Open in Chrome" from "~/Documents/var/computing/MacOS/Alfred/GRAY16/Alfred.alfredpreferences/workflows/user.workflow.159A6778-728D-47CD-8977-213AB04106F0/scripts/Open in Chrome.sh" 18:51:57 loaded URL action "Open in Default Application" from "~/Documents/var/computing/MacOS/Alfred/GRAY16/Alfred.alfredpreferences/workflows/user.workflow.159A6778-728D-47CD-8977-213AB04106F0/scripts/Open in Default Application.sh" 18:51:57 7.14249s since last check for update 18:51:57 searching bookmarks for "wor" ... 18:51:57 [ERROR] dial unix /tmp/alfred-firefox.501.sock: connect: no such file or directory 18:51:57 ------------------ FATAL ERROR ------------------- 18:51:57 Cannot Connect to Extension : goroutine 1 [running]: runtime/debug.Stack(0xc00011d990, 0x1, 0x1) /usr/local/opt/go/libexec/src/runtime/debug/stack.go:24 +0x9d github.com/deanishe/awgo.(*Workflow).Run.func2(0xc00014c000) /Users/daj/pkg/mod/github.com/deanishe/awgo@v0.22.1/workflow.go:343 +0xe7 panic(0x140f940, 0x1544170) /usr/local/opt/go/libexec/src/runtime/panic.go:679 +0x1b2 main.mustClient(0x14c15b5) /Users/daj/Code/Alfred/alfred-firefox-assistant/rpc_client.go:37 +0xb4 main.runBookmarks(0xc0000d2030, 0x0, 0x0, 0x0, 0x0) /Users/daj/Code/Alfred/alfred-firefox-assistant/client.go:249 +0xc1 github.com/peterbourgon/ff/ffcli.(*Command).Run(0x1831c40, 0xc0000d2030, 0x0, 0x0, 0x183a601, 0x2) /Users/daj/pkg/mod/github.com/peterbourgon/ff@v1.7.1-0.20200101221212-72e429b6ad42/ffcli/command.go:96 +0x248 github.com/peterbourgon/ff/ffcli.(*Command).Run(0x1832500, 0xc0000d2010, 0x3, 0x3, 0x14b6453, 0x9) /Users/daj/pkg/mod/github.com/peterbourgon/ff@v1.7.1-0.20200101221212-72e429b6ad42/ffcli/command.go:90 +0x1f1 main.run() /Users/daj/Code/Alfred/alfred-firefox-assistant/main.go:144 +0x191 github.com/deanishe/awgo.(*Workflow).Run(0xc00014c000, 0x14d4a18) /Users/daj/pkg/mod/github.com/deanishe/awgo@v0.22.1/workflow.go:357 +0x2af main.main() /Users/daj/Code/Alfred/alfred-firefox-assistant/main.go:149 +0x39 18:51:57 ---------------- END STACK TRACE -----------------
  12. I can't get the Firefox extension to connect. Its status always shows "disconnected." I installed the workflow first, then the extension via the workflow. I got through MacOS's security and privacy checks, no problem, but when I run the workflow, it seems to run correctly, but shows "Cannot connect to extension," which makes sense because the extension is always disconnected. I've tried re-starting Firefox. Any troubleshooting suggestions? EDIT: When doing ffass, under "No Connection to Browser," it says, "dial unix /tmp/alfred-firefox.501.sock: connect: no such file or directory"
  13. Yes, that worked, thanks. I see my mistake now: I cut and pasted from my Karabiner.json where the call to Alfred's workflow is in fact inside double quote, necessitating escaping the nested double quotes. But it still doesn't work as expected. When I do: $ /usr/bin/osascript -e 'tell application "Alfred 3" to run trigger "AstrillToggle-ext" in workflow "com.jimmy34742.alfred.AstrillToggle"' it opens Alfred's window with the workflow ready to run, and I still have to hit the return key to execute the workflow. How do I make that command line directly execute the workflow without opening Alfred's window and waiting for user input?
  14. When I do it without adding the single quotes as you suggested, I get this expected error: syntax error: Expected expression but found end of script. (-2741)
  15. Thanks for taking a look. That is indeed one of the variations I'd tried. When I do: /usr/bin/osascript -e 'tell application \"Alfred 3\" to run trigger \"AstrillToggle-ext\" in workflow \"com.jimmy34742.alfred.AstrillToggle\"' Terminal returns: syntax error: Expected expression, property or key form, etc. but found unknown token. (-2741) I've gone over it with a fine tooth comb, but I don't see any typos. I have several workflows that I've made external triggers for, and they work fine. When I run the workflow from Alfred, it works correctly.
  16. I'm trying to run a workflow from a Terminal command line in preparation to use Sleepwatcher to run that workflow every time I close the lid. But apparently I don't have things quoted and escaped correctly, and I can't figure it out. Can I get some correction on the following? $ /usr/bin/osascript -e tell application \"Alfred 3\" to run trigger \"MyExternalTrigger\" in workflow \"com.jimmy34742.alfred.MyWorkflow\"
  17. Nice, but it launches a new instance of the Terminal app at every invocation and then leaves that Terminal running. I use PathFinder as a Finder replacement, so maybe that has something to do with it? in any case, the workflow doesn't toggle PathFinder's status regarding showing hidden files.
  18. Thanks, but K-E doesn't have that Parameters page. I only know of those two timing parameters that I have to edit directly in karabiner.json.
  19. I made a launcher that emphasizes home row keys 's', 'd', 'f'', 'j', 'k', and 'l', and the 'w', 'e', 'i', and 'o' keys because they require the least energy to move to. I find moving the index finger up a row to be far less ergonomic than the middle and ring fingers. The total spread of the two-key launch sequences is narrow enough to be one-handable. The file is here https://gist.github.com/Jimmy34742/c442fd432115f55b752f1d3982b2acff Most of the my spacebar-based launcher remains active in that file. The spacebar-based launcher is now here https://gist.github.com/Jimmy34742/7be28de581e706c37b059b395bf8900f Switching apps feels good, but I could use some help with optimizing the timing parameters to ensure a good typing feel "basic.to_delayed_action_delay_milliseconds": 0, "basic.to_if_alone_timeout_milliseconds": 500 Yes, I know this thread suffers from topic creep, but I couldn't think of a better place to post this.
  20. My K+A example was just for purposes of illustration. I hear you on the HJKL keys and also on the semicolon key. Actually, I use emacs keybindings--and very happily--but it had become clear to me on my own early on that all the home row keys are particularly valuable to a user interface's ergonomics. In fact, I prefer to avoid 'A' and semicolon because a more compact layout can be used one-handed when necessary. I first made a home row launcher (which I sent you--did you get it?), but I couldn't seem to hit on a combination of those two timing parameters that would prevent mistakes due to home row characters being captured by K-E. My typing technique obviously falls into some overlapping, but that's not an issue for typing on a keyboard that hasn't been re-mapped. I think overlapping allows faster typing because you use less physical energy, but now the modifier key-based launcher that I had turned to is running out of available ergonomic key combos. I don't want to turn to command, option, or function keys because they require shifts in hand position. My interface that I posted on Github uses spacebar and tab to enter modes. By the way, I have caps_lock mapped to left_control. So I want to add home row keys to initiate modes, but that's going to lead to a ton of typing errors until I can impose a rather harsh discipline on my typing technique that will slow my--and I think anybody's--typing down.
  21. @nikivi: when you use simultaneous keypresses in Karabiner, does your typing have to be 100% precise so that you don't inadvertently activate a Karabiner combo? For example, if K+A switches to Safari, then when you type the word "karabiner," if the leading 'k' and 'a' overlap even slightly, you'll accidentally switch to Safari. Do you use 100% separated typing technique? If so, do you think that's a better typing technique, or is it a sacrifice you make in order to use simultaneous keypresses for other things? I'm asking because, since Karabiner-Elements doesn't yet have simultaneous keypresses, I can simulate it by, for example, creating a 'k' mode and then launching Safari by holding 'k' down and then pressing 'a'. This works fine as long as I have 100% separated typing technique. My typing isn't 100% separated because it doesn't have to be, and because I perceive fully separating keypresses as slower when typing text. I'm trying to decide if it's worth getting used to a different typing technique for the sake of (emulated) simultaneous keypresses.
  22. yes, that worked. I thought I'd already tried all combinations of escaping stuff.
  23. I posted my K-E launcher at https://gist.github.com/Jimmy34742/7be28de581e706c37b059b395bf8900f It uses spacebar and tab as sticky keys. The organization is: spacebar + letter => application spacebar + number => folder or file spacebar + shift + number => a logically (to me) different category of folder or file tab => URL's, Alfred workflows and (I intend) LaunchBar actions (future) tab + spacebar => workflows and actions and tab (above) only launches URL's. All suggestions and comments welcome.
  24. In the other thread, @deanishe wrote: To run an .scpt file: /usr/bin/osascript /path/to/applescript.scpt or to run AppleScript: /usr/bin/osascript -e 'tell application "Alfred 3" to ...' My script consists of this one "tell" statement: tell application "Alfred 3" to run trigger "SafariTabs-ext" in workflow "com.my.SearchTabs" The script works fine when I trigger it from a key_code using this piece of code in my Karabiner-Elements json file: "to": [ { "shell_command": "/usr/bin/osascript ~/Documents/SafariTabs-my.scpt" } Since the scripts I intend to write will all be one-liners, I would rather put the "tell" statement inside the json file rather than call a script. What's the proper K-E json syntax to make that "tell" statement part of the shell_command? I would think that I have to escape the spaces and double quotation marks, but I haven't been able to get it right.
  25. On the contrary, it was a productive and intelligent discussion among thoughtful, experienced users who are also paying customers. It was honestly critical and honestly praiseworthy as appropriate. The topic was to compare user experiences of Alfred and LaunchBar, and it stayed on topic quite well. When points are being debated back and forth, that is neither unnecessarily negative nor repetitive. Why not honor everyone who put time and labor into the forum, restore it, and let readers decide what they think? Perhaps edit out the posts that merely characterize what other people have written rather than responding to content with content.
×
×
  • Create New...