-
-
Save hym3242/8e8bc10a2fed8e55973c500f1798c234 to your computer and use it in GitHub Desktop.
$ # plz forgive this dumb method of visualization. | |
$ cp /System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict . | |
$ plutil -convert xml1 StandardKeyBinding.dict | |
$ plutil -p StandardKeyBinding.dict | unicode-vis | cat -v | tr '\t' '+' | |
{ | |
"^C" => "insertNewline:" | |
"^H" => "deleteBackward:" | |
"^Y" => "insertBacktab:" //shift+tab | |
"^[" => "cancelOperation:" | |
"^?" => "deleteBackward:" | |
"+" => "insertTab:" | |
" | |
" => "insertNewline:" | |
"^M" => "insertNewline:" | |
"@" => "noop:" | |
"@^?" => "deleteToBeginningOfLine:" | |
"@ " => "cycleToNextInputScript:" | |
"@." => "cancelOperation:" | |
"@^ " => "togglePlatformInputSystem:" | |
"@^U+F701" => "makeBaseWritingDirectionNatural:" | |
"@^U+F702" => "makeBaseWritingDirectionRightToLeft:" | |
"@^U+F703" => "makeBaseWritingDirectionLeftToRight:" | |
"@~ " => "cycleToNextInputKeyboardLayout:" | |
"@~^U+F701" => "makeTextWritingDirectionNatural:" | |
"@~^U+F702" => "makeTextWritingDirectionRightToLeft:" | |
"@~^U+F703" => "makeTextWritingDirectionLeftToRight:" | |
"@$U+F700" => "moveToBeginningOfDocumentAndModifySelection:" | |
"@$U+F701" => "moveToEndOfDocumentAndModifySelection:" | |
"@$U+F702" => "moveToLeftEndOfLineAndModifySelection:" | |
"@$U+F703" => "moveToRightEndOfLineAndModifySelection:" | |
"@U+F700" => "moveToBeginningOfDocument:" | |
"@U+F701" => "moveToEndOfDocument:" | |
"@U+F702" => "moveToLeftEndOfLine:" | |
"@U+F703" => "moveToRightEndOfLine:" | |
"^" => "noop:" | |
"^^C" => "insertLineBreak:" | |
"^^Y" => "selectPreviousKeyView:" //ctrl+shift+tab (remember that tab is ^I(0x09) and shift got its name because it shifts one bit?) (i forgot the source sorry! maybe checkout "things every hacker once knew") | |
"^^?" => "deleteBackwardByDecomposingPreviousCharacter:" | |
"^+" => "selectNextKeyView:" | |
"^ | |
" => "insertLineBreak:" | |
"^^M" => "insertLineBreak:" | |
"^'" => "insertSingleQuoteIgnoringSubstitution:" | |
"^"" => "insertDoubleQuoteIgnoringSubstitution:" | |
"^/" => "insertRightToLeftSlash:" | |
"^$U+F702" => "moveToLeftEndOfLineAndModifySelection:" | |
"^$U+F703" => "moveToRightEndOfLineAndModifySelection:" | |
"^a" => "moveToBeginningOfParagraph:" | |
"^A" => "moveToBeginningOfParagraphAndModifySelection:" | |
"^b" => "moveBackward:" | |
"^B" => "moveBackwardAndModifySelection:" | |
"^d" => "deleteForward:" | |
"^e" => "moveToEndOfParagraph:" | |
"^E" => "moveToEndOfParagraphAndModifySelection:" | |
"^f" => "moveForward:" | |
"^F" => "moveForwardAndModifySelection:" | |
"^h" => "deleteBackward:" | |
"^k" => "deleteToEndOfParagraph:" | |
"^l" => "centerSelectionInVisibleArea:" | |
"^n" => "moveDown:" | |
"^N" => "moveDownAndModifySelection:" | |
"^o" => [ | |
0 => "insertNewlineIgnoringFieldEditor:" | |
1 => "moveBackward:" | |
] | |
"^p" => "moveUp:" | |
"^P" => "moveUpAndModifySelection:" | |
"^t" => "transpose:" | |
"^v" => "pageDown:" | |
"^V" => "pageDownAndModifySelection:" | |
"^y" => "yank:" | |
"^U+F700" => "scrollPageUp:" | |
"^U+F701" => "scrollPageDown:" | |
"^U+F702" => "moveToLeftEndOfLine:" | |
"^U+F703" => "moveToRightEndOfLine:" | |
"~^C" => "insertNewlineIgnoringFieldEditor:" | |
"~^H" => "deleteWordBackward:" | |
"~^[" => "complete:" | |
"~^?" => "deleteWordBackward:" | |
"~+" => "insertTabIgnoringFieldEditor:" | |
"~ | |
" => "insertNewlineIgnoringFieldEditor:" | |
"~^M" => "insertNewlineIgnoringFieldEditor:" | |
"~^^?" => "deleteWordBackward:" | |
"~^b" => "moveWordBackward:" | |
"~^B" => "moveWordBackwardAndModifySelection:" | |
"~^f" => "moveWordForward:" | |
"~^F" => "moveWordForwardAndModifySelection:" | |
"~$U+F700" => "moveParagraphBackwardAndModifySelection:" | |
"~$U+F701" => "moveParagraphForwardAndModifySelection:" | |
"~$U+F702" => "moveWordLeftAndModifySelection:" | |
"~$U+F703" => "moveWordRightAndModifySelection:" | |
"~U+F700" => [ | |
0 => "moveBackward:" | |
1 => "moveToBeginningOfParagraph:" | |
] | |
"~U+F701" => [ | |
0 => "moveForward:" | |
1 => "moveToEndOfParagraph:" | |
] | |
"~U+F702" => "moveWordLeft:" | |
"~U+F703" => "moveWordRight:" | |
"~U+F704" => "noop:" | |
"~U+F705" => "noop:" | |
"~U+F706" => "noop:" | |
"~U+F707" => "noop:" | |
"~U+F708" => "noop:" | |
"~U+F709" => "noop:" | |
"~U+F70A" => "noop:" | |
"~U+F70B" => "noop:" | |
"~U+F70C" => "noop:" | |
"~U+F70D" => "noop:" | |
"~U+F70E" => "noop:" | |
"~U+F70F" => "noop:" | |
"~U+F710" => "noop:" | |
"~U+F711" => "noop:" | |
"~U+F712" => "noop:" | |
"~U+F713" => "noop:" | |
"~U+F714" => "noop:" | |
"~U+F715" => "noop:" | |
"~U+F716" => "noop:" | |
"~U+F717" => "noop:" | |
"~U+F718" => "noop:" | |
"~U+F719" => "noop:" | |
"~U+F71A" => "noop:" | |
"~U+F71B" => "noop:" | |
"~U+F71C" => "noop:" | |
"~U+F71D" => "noop:" | |
"~U+F71E" => "noop:" | |
"~U+F71F" => "noop:" | |
"~U+F720" => "noop:" | |
"~U+F721" => "noop:" | |
"~U+F722" => "noop:" | |
"~U+F723" => "noop:" | |
"~U+F724" => "noop:" | |
"~U+F725" => "noop:" | |
"~U+F726" => "noop:" | |
"~U+F727" => "noop:" | |
"~U+F728" => "deleteWordForward:" | |
"~U+F729" => "noop:" | |
"~U+F72A" => "noop:" | |
"~U+F72B" => "noop:" | |
"~U+F72C" => "pageUp:" | |
"~U+F72D" => "pageDown:" | |
"~U+F72E" => "noop:" | |
"~U+F72F" => "noop:" | |
"~U+F730" => "noop:" | |
"~U+F731" => "noop:" | |
"~U+F732" => "noop:" | |
"~U+F733" => "noop:" | |
"~U+F734" => "noop:" | |
"~U+F735" => "noop:" | |
"~U+F736" => "noop:" | |
"~U+F737" => "noop:" | |
"~U+F738" => "noop:" | |
"~U+F739" => "noop:" | |
"~U+F73A" => "noop:" | |
"~U+F73B" => "noop:" | |
"~U+F73C" => "noop:" | |
"~U+F73D" => "noop:" | |
"~U+F73E" => "noop:" | |
"~U+F73F" => "noop:" | |
"~U+F740" => "noop:" | |
"~U+F741" => "noop:" | |
"~U+F742" => "noop:" | |
"~U+F743" => "noop:" | |
"~U+F744" => "noop:" | |
"~U+F745" => "noop:" | |
"~U+F746" => "noop:" | |
"~U+F747" => "noop:" | |
"$U+F700" => "moveUpAndModifySelection:" | |
"$U+F701" => "moveDownAndModifySelection:" | |
"$U+F702" => "moveLeftAndModifySelection:" | |
"$U+F703" => "moveRightAndModifySelection:" | |
"$U+F729" => "moveToBeginningOfDocumentAndModifySelection:" | |
"$U+F72B" => "moveToEndOfDocumentAndModifySelection:" | |
"$U+F72C" => "pageUpAndModifySelection:" | |
"$U+F72D" => "pageDownAndModifySelection:" | |
"U+F700" => "moveUp:" | |
"U+F701" => "moveDown:" | |
"U+F702" => "moveLeft:" | |
"U+F703" => "moveRight:" | |
"U+F704" => "noop:" | |
"U+F705" => "noop:" | |
"U+F706" => "noop:" | |
"U+F707" => "noop:" | |
"U+F708" => "complete:" | |
"U+F709" => "noop:" | |
"U+F70A" => "noop:" | |
"U+F70B" => "noop:" | |
"U+F70C" => "noop:" | |
"U+F70D" => "noop:" | |
"U+F70E" => "noop:" | |
"U+F70F" => "noop:" | |
"U+F710" => "noop:" | |
"U+F711" => "noop:" | |
"U+F712" => "noop:" | |
"U+F713" => "noop:" | |
"U+F714" => "noop:" | |
"U+F715" => "noop:" | |
"U+F716" => "noop:" | |
"U+F717" => "noop:" | |
"U+F718" => "noop:" | |
"U+F719" => "noop:" | |
"U+F71A" => "noop:" | |
"U+F71B" => "noop:" | |
"U+F71C" => "noop:" | |
"U+F71D" => "noop:" | |
"U+F71E" => "noop:" | |
"U+F71F" => "noop:" | |
"U+F720" => "noop:" | |
"U+F721" => "noop:" | |
"U+F722" => "noop:" | |
"U+F723" => "noop:" | |
"U+F724" => "noop:" | |
"U+F725" => "noop:" | |
"U+F726" => "noop:" | |
"U+F727" => "noop:" | |
"U+F728" => "deleteForward:" | |
"U+F729" => "scrollToBeginningOfDocument:" | |
"U+F72A" => "noop:" | |
"U+F72B" => "scrollToEndOfDocument:" | |
"U+F72C" => "scrollPageUp:" | |
"U+F72D" => "scrollPageDown:" | |
"U+F72E" => "noop:" | |
"U+F72F" => "noop:" | |
"U+F730" => "noop:" | |
"U+F731" => "noop:" | |
"U+F732" => "noop:" | |
"U+F733" => "noop:" | |
"U+F734" => "noop:" | |
"U+F735" => "noop:" | |
"U+F736" => "noop:" | |
"U+F737" => "noop:" | |
"U+F738" => "noop:" | |
"U+F739" => "delete:" | |
"U+F73A" => "noop:" | |
"U+F73B" => "noop:" | |
"U+F73C" => "noop:" | |
"U+F73D" => "noop:" | |
"U+F73E" => "noop:" | |
"U+F73F" => "noop:" | |
"U+F740" => "noop:" | |
"U+F741" => "noop:" | |
"U+F742" => "noop:" | |
"U+F743" => "noop:" | |
"U+F744" => "noop:" | |
"U+F745" => "noop:" | |
"U+F746" => "noop:" | |
"U+F747" => "noop:" | |
} |
you can strings /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit
for more(like selectParagraph:
, selectWord:
, pageUp:
!).
or better, symbols(1) it. see https://gist.github.com/hym3242/4ade5dbcabbe547f3d78687897b8ddfe
Recent macOS versions will require you to extract the AppKit binary from dyld_shared_cache.
insertNewline:
and insertNewlineIgnoringFieldEditor:
do not work in Chrome. It seems the only way to insert newline in Chrome is the big RETURN
ctrl+up/down to scrollpage(scroll,not moving cursor) , and capitalizeWord:
in textarea are also not possible in chrome.
selectWord:
and selectParagraph:
can extend selection when pressed repeatedly in chrome, but not in macos native apps.
deleteWordBackward:
etc in chrome pushes them into yank buffer, not in macos native. in native & chrome, use deleteToBeginningOfLine:
(default bound to cmd+del), deleteToBeginningOfParagraph:
, deleteToEndOfLine:
, deleteToEndOfParagraph:
to push selection to yank buffer.
not all methods are bindable of course... They must be on your textview's Responder Chain!
symbols /Volumes/Macintosh\ HD/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit | grep 'NSKeyBindingCommands'
better than strings(1)
here is my binding: explore for more yourself. See comment below for my current setup.
// ~/Library/KeyBindings/DefaultKeyBinding.dict (this path is hardcoded in AppKit)
{
"^~h" = "deleteWordBackward:"; //bash style...
"^~d" = "deleteWordForward:"; //ibid
"^u" = "deleteToBeginningOfParagraph:"; //unix tty line disc style kill
"^w" = "deleteWordBackward:"; //unix tty line disc style werase
"~a" = "selectParagraph:"; //cocoa paragraph ≈ unix line
"^m" = "insertNewline:"; //RETURN as in "Carriage Return"
"^j" = "insertNewlineIgnoringFieldEditor:"; //default bound to opt+return, alternate newline, bypasses some editor smart features
"~v" = "pageUp:"; //you know your emacs.
"~V" = "pageUpAndModifySelection:"; //shift+option+v
"~A" = "selectWord:";
"~c" = "capitalizeWord:"; //uppercaseWord: does not seem to work
"~t" = "convertToTraditionalChinese:"; //convert selection
"~s" = "convertToSimplifiedChinese:"; //ibid.
"^J" = "insertLineBreak:"; //ctrl+shift+j, linebreak is different from newline. default also bound to ctrl+return and shift+return
"^~\UF701" = (selectParagraph:, setMark:, deleteToMark:, moveToEndOfParagraph:, moveRight:, setMark:, yank:, moveLeft:, selectToMark:); //move line down
"^~\UF700" = (selectParagraph:, setMark:, deleteToMark:, moveLeft:, moveToBeginningOfParagraph:, yank:, moveLeft:, selectToMark:); //somehow bugged , movelineup
"~m" = (moveToBeginningOfParagraph:,moveWordRight:, moveWordLeft:); // Carriage Return (resembles ^M) to first non-blank char (does not work perfectly in all cases)
"^~n" = (moveForward:, moveToEndOfParagraph:); // like the default opt+down
"^~p" = (moveBackward:, moveToBeginningOfParagraph:); // like the default opt+up
// add these to your liking
// "~h" = "deleteWordBackward:";
// "~d" = "deleteWordForward:";
// "~b" = "moveWordBackward:";
// "~f" = "moveWordForward:";
}
currently using
{
"^~h" = "deleteWordBackward:";
"^~d" = "deleteWordForward:";
"^u" = "deleteToBeginningOfParagraph:";
"^w" = "deleteWordBackward:";
"~a" = "selectParagraph:";
"^m" = "insertNewline:";
"^j" = "insertNewlineIgnoringFieldEditor:";
"~v" = "pageUp:"; //inserts symbol if already at top in chrome
"~V" = "pageUpAndModifySelection:";
"~A" = "selectWord:";
"~c" = (capitalizeWord:, moveWordForward:, moveWordBackward:);
"~t" = "convertToTraditionalChinese:"; //a little unreliable
"~s" = "convertToSimplifiedChinese:"; //a little unreliable
"~h" = "deleteWordBackward:";
"~d" = "deleteWordForward:";
"~b" = "moveWordBackward:";
"~B" = "moveWordBackwardAndModifySelection:";
"~f" = "moveWordForward:";
"~F" = "moveWordForwardAndModifySelection:";
"^J" = "insertLineBreak:";
"^~\UF701" = (selectParagraph:, setMark:, deleteToMark:, moveToEndOfParagraph:, moveRight:, setMark:, yank:, moveLeft:, selectToMark:);
"^~\UF700" = (selectParagraph:, setMark:, deleteToMark:, moveLeft:, moveToBeginningOfParagraph:, yank:, moveLeft:, selectToMark:); //somehow bugged
"~m" = (moveToBeginningOfParagraph:,moveWordRight:, moveWordLeft:);
"^~n" = (moveForward:, moveToEndOfParagraph:);
"^~m" = (moveToEndOfParagraph:, moveForward:);//, moveToBeginningOfParagraph:);
"^~N" = "moveParagraphForwardAndModifySelection:";
"^~p" = (moveBackward:, moveToBeginningOfParagraph:);
"^~o" = (moveToBeginningOfParagraph:, moveBackward:);
"^~P" = "moveParagraphBackwardAndModifySelection:";
// "@/" = (moveToBeginningOfParagraph:, insertText:, "// ", moveToEndOfParagraph:);
"^U" = "deleteToBeginningOfLine:"; //"uppercaseWord:";
"^L" = "lowercaseWord:";
"^~u" = (uppercaseWord:, moveWordForward:, moveWordBackward:); //does not work in chrome
"^~l" = (lowercaseWord:, moveWordForward:, moveWordBackward:); //does not work in chrome
"^~a" = "moveToBeginningOfLine:";
"^~e" = "moveToEndOfLine:";
"^~w" = (moveWordForward: ,moveWordForward:,moveWordBackward:); //vi
"~w" = (moveWordForward: ,moveWordForward:,moveWordBackward:); //vi
"~U" = "uppercaseWord:"; //does not work in chrome
//"~l" = "centerSelectionInVisibleArea:"; //does not work in chrome...
"^K" = "deleteToEndOfLine:";
"~ " = "setMark:"; // works in chrome!
"^x" = "swapWithMark:"; //works in chrome, but flaky, unreliable, the "Mark" sometimes jump to your current position randomly
"^X" = "selectToMark:"; //does not work in chrome
"^H" = "deleteBackwardByDecomposingPreviousCharacter:"; // works regardless of whether the unichar is combined or precomposed!(apple unicode team is insane!). Sadly does not work in chrome.(man f*ck chrome...)
"^_" = "convertToHalfWidth:"; // affects punctrations, katakana, and alphanumerics. does not work in chrome.
"^+" = "convertToFullWidth:"; // ibid. does not work in chrome.
"^?" = "spotlight:"; //???
"^>" = (insertText:, "\U2192"); // inserts "→"
"^<" = (insertText:, "\U2190"); // inserts "←"
"^/" = "searchInNoteList:"; // Notes.app
"^[" = "superscript:"; // Does not work outside of Apple native
"^]" = "subscript:"; // Does not work outside of Apple native
"^-" = "strikethrough:"; // Does not work outside of Apple native
"~\UF700" = "moveSelectedListItemUp:"; // Notes.app
"~\UF701" = "moveSelectedListItemDown:"; // Notes.app
"^$\UF700" = "scrollPageUp:"; // does not work in chrome...
"^$\UF701" = "scrollPageDown:"; // does not work in chrome...
"^\UF700" = "scrollLineUp:"; // works in chrome's textarea!
"^\UF701" = "scrollLineDown:"; // works in chrome's textarea!
// "^t" = "transposeWords:"; // apple documentation has it, why doesn't it work?
// "^T" = "transpose:";
"^." = "quickLookPreviewItems:"; // you can use this to lookup word at current text insertion point! useful tip: use cmd+. to dismiss the lookup without using mouse/trackpad. does not work in chrome.
//"~e" = (moveWordBackward: ,moveWordBackward:,moveWordForward:); //does not work. see below.
//^~j is literal LF. works the same as "insertNewlineIgnoringFieldEditor:". in wikipedia codemirror this is the only way to input newline without using return.
//inserting line breaks does not create new paragraphs. Because "paragraphs" are seperated by NL, "lines" are seperated with U+2028 LINE SEPARATOR!
//in chrome yank buffer is page specific(hooray!).
//it seems only deletetobeginningofline/para & deletetoendofline/para push stuff to the yank buffer
//opt+v/b/t/... stop working in some keylayout other than US english ABC, their keylayout take higher precedence. but ctrl+q with them work as expected! the opt+numbers, cmd+opt+stuff as defined in keylayout work very weirdly.
//other notes on this text system: literal 0x12 FORM FEED ((ctrl+q) ctrl+opt+l)and literal 0x11 VERTICAL TAB ((ctrl+q) ctrl+opt+k) can have funny results.
}
don't forget defaults write -g NSRepeatCountBinding -string "^r"
for emacs style numeric argument! (forgot the source!)
see also "Keyboard Viewer" in your input source menu bar icon.
see also Ukelele.
The setMark:
and swapWithMark:
can be very useful, but the mark is a bit unstable, can sometimes unexpectedly change to your current cursor position. In some apps setMark also remembers selection.
The best thing about this DefaultKeyBinding.dict in context of AppKit, is that you can bind keys to any method you discover in the AppKit internal debug menu's "Record Actions" window!(Although I don't really know how it works) For example, in Notes.app you can bind a key to "searchInNoteList:"
and it will move key focus to the search field!!!(just like cmd+opt+f)
About the AppKit internal debug menu: defaults write -g NS🐞 -bool true
. It's worth mentioning that I discovered this entirely on my own... though I am far from the first. (But that did not spoil the fun!)
Also follow the main text view's responder chain, and statically search for some useful methods of those classes in your disassembler. Methods you discovered in "Record Actions" that belong to classes not in your responder chain will not be usable.
Notes.app cont'd:
Don't forget the subscript:
and superscript:
!!! OH MY GOD IS MACOS FUN AS FUCK TO HACK
…and the "moveSelectedListItemUp:"
and "moveSelectedListItemDown:"
…and even some crazy shit like show/hide the sidebar toggleFolderListHidden:
, and exportNoteAsPDF:
(Man, isn't this the pinnacle of the idea of object-oriented?)
Notes.app cont'd again:
You may also want to make use of Notes.app's URL scheme (CFBundleURLSchemes
in app Info.plist). e.g. notes://showNote?identifier=9AFFFFFF-FAFF-CAFE-BABE-8FFFFF2FEEF
to create clickable links to other notes!
see also: https://www.reddit.com/r/shortcuts/comments/aot272/get_url_of_note_copy_note_url_to_clipboard
see also: https://discourse.hookproductivity.com/t/using-the-built-in-notes-url-scheme/6071
Notes cont'd again again:
See also defaults write com.apple.Notes alexandria -bool YES
. It will enable the .notesarchive
export feature. This feature is already visible on iPad version of Notes (at least on Apple Store demo machines)
References and see alsos (normative references):
you can even ^q (NSQuotedKeystrokeBinding) (or without ^q, if it does not have a related binding) to do quoted-insert 0x01,0x02...etc (including stuff like 0x1b with ctrl+opt+[ oh my god) with ctrl+opt+KEY directly into any textarea (just like ctrl+v(lnext) then ctrl+KEY in tty canonical). To insert literal newline, use ctrl+opt+j (you know your ascii table) or ctrl+q then return. ^q can also insert the special char in keymap with Option&Shift even after you rebinded the opt+X to something else.
fuck close source! if they open sourced how they discovered them, this would not be so little known today! karabiner may not even need to exist!