diff --git a/site_test/css/main.scss b/site_test/css/main.scss index 0ae6f74..16ca010 100644 --- a/site_test/css/main.scss +++ b/site_test/css/main.scss @@ -189,10 +189,6 @@ header { text-wrap: pretty; } -.read-more { - font-style: italic; -} - .header-anchor { text-decoration: none; font-size: 1rem; diff --git a/site_test/index.html b/site_test/index.html index 68cd602..23a8bfd 100644 --- a/site_test/index.html +++ b/site_test/index.html @@ -42,7 +42,7 @@ {% if latest_post.excerpt %} {{ latest_post.excerpt }}

- Read more… + Read more…

{% else %} {{ latest_post_content }} diff --git a/site_test/posts/2021/2021-09-02-scrollswitcher.md b/site_test/posts/2021/2021-09-02-scrollswitcher.md index 0143e79..f692884 100644 --- a/site_test/posts/2021/2021-09-02-scrollswitcher.md +++ b/site_test/posts/2021/2021-09-02-scrollswitcher.md @@ -130,13 +130,13 @@ I knew the name of the notification I needed to fire, but not what to do with it Looking at the disassembly, we can see exactly what it's doing: -
Hopper showing the disassembly for -[MouseController awakeFromNib]
+Hopper showing the disassembly for -[MouseController awakeFromNib] It's adding an observer to `NSDistributedNotificationCenter`'s `defaultCenter` for the `SwipeScrollDirectionDidChangeNotification`—the notification name I saw earlier in the Console. The other place it's referenced from (`[MTMouseScrollGesture initWithDictionary:andReadPreferences:]`) is doing the same thing: adding an observer. So, it looks like this notification isn't what triggers the actual change to the actual scroll input handling deep in the guts of the system. If that were the case, I'd expect to see the preference pane _send_ the notification, not just receive it. But, it still may be useful. Looking at the implementation of the `_swipeScrollDirectionDidChangeNotification:` method it's setting as the callback for the action, we can see that it's probably updating the checkbox value. That `setState:` call sure seems like it's on the `NSButton` used for the natural scrolling checkbox. -
Hopper showing the disassembly for -[MouseController _swipeScrollDirectionDidChangeNotification:]
+Hopper showing the disassembly for -[MouseController _swipeScrollDirectionDidChangeNotification:] [`NSDistributedNotificationCenter`](https://developer.apple.com/documentation/foundation/nsdistributednotificationcenter) is described as being like the regular notification center but for inter-process communication, which sounds like what we want. It has pretty much the same API as the regular one, so we can just send that notification when we change the scroll mode. @@ -166,7 +166,7 @@ With that in place, clicking the menu bar item both sets the default and causes That's all well and good, but clicking the menu item still doesn't actually change what happens when you move two fingers on the trackpad. It clearly works when clicking the checkbox in System Preferences, so there must be something else it's doing that we're not. Internally, this feature seems to be consistently referred to as the "swipe scroll direction" (even though it affects non-swipe scrolling), so, back in Hopper, we can search for procedures named like that. There's one that immediately looks promising `setSwipeScrollDirection`, that just delegates to an externally implemented `_setSwipeScrollDirection`. -
Hopper showing the assembly for setSwipeScrollDirection
+Hopper showing the assembly for setSwipeScrollDirection Looking at the references to the function, I saw it was called by the `-[MouseController scrollingBehavior:]` setter. That seems like the function that I wanted, but since it was implemented elsewhere, I had no idea what parameters it took. So, where's it implemented? @@ -185,9 +185,9 @@ Actually getting the framework binaries is a bit tricky, since, starting with ma $ dyld_shared_cache_util -extract ~/Desktop/Libraries/ /System/Library/dyld/dyld_shared_cache_x86_64 ``` -It took a couple guesses, but I found that the `_setSwipeScrollingDirection` function is defined in `PreferencePanesSupport.framework`. +It took a couple guesses, but I found that the `_setSwipeScrollingDirection` function is defined in `PreferencePanesSupport.framework`. -
Hopper showing the disassembly for _setSwipeScrollDirection in PreferencePanesSupport
+Hopper showing the disassembly for _setSwipeScrollDirection in PreferencePanesSupport Hopper thinks it takes an int, but we can clearly see the parameter's being used as a bool. `rcx` is initialized to `kCFBooleanFalse` and set to `kCFBooleanTrue` if the parameter is true, and that's the value being passed to `CFPreferencesSetValue`. Perfect. @@ -218,4 +218,3 @@ I can't really take a screen recording of that, so you'll have to take my word t If you're interested in the complete code, it can be found [here](https://git.shadowfacts.net/shadowfacts/ScrollSwitcher). It's not currently packaged for distribution, but you can build and run it yourself. Because it needs the sandbox disabled, it won't ever been in the App Store, but at some point I might slap an app icon on it and published a notarized, built version. So, if anyone's interested, let me know. As it currently exists, the app—which I'm calling ScrollSwitcher—covers 90% of my needs. I don't generally dock/undock more than a one or twice a day, so just being able to click a menu bar item is plenty fast. That said, I may still extend it for "fun". One obvious improvement would be automatically changing the state when an external mouse is connected/disconnected. That shouldn't be too hard, right? Right? - diff --git a/site_test/posts/2022/2022-06-13-clarus.md b/site_test/posts/2022/2022-06-13-clarus.md index 2913173..eca6b10 100644 --- a/site_test/posts/2022/2022-06-13-clarus.md +++ b/site_test/posts/2022/2022-06-13-clarus.md @@ -29,15 +29,14 @@ The next step, then—having been thoroughly nerd-sniped by this—was to figure The first stop was [`NSPageLayout`](https://developer.apple.com/documentation/appkit/nspagelayout), the panel object that is responsible for displaying the panel. It was unlikely that the class would actually contain the implementation of the panel, but it was at least a starting point. -In order to actually look at the disassembled implementation of this AppKit class, I needed the actual AppKit framework binary. Since macOS Big Sur, all system framework binaries are stored merged in the `dyld` shared cache, rather than in separate files. But, I need them as separate files in order to actually inspect them. +In order to actually look at the disassembled implementation of this AppKit class, I needed the actual AppKit framework binary. Since macOS Big Sur, all system framework binaries are stored merged in the `dyld` shared cache, rather than in separate files. But, I need them as separate files in order to actually inspect them. Since the [last time](/2021/scrollswitcher/) I wrote about this, a couple things have changed. Before, I built the Apple `dyld_shared_cache_util` from one of the periodic `dyld` source dumps. This is annoying because you have to make a bunch of changes to the source code to get it to compile outside of an Apple-internal environment. It also may break whenever there's an OS update. So, I've switched to using [this utility](https://github.com/keith/dyld-shared-cache-extractor) which uses the `dyld_extractor.bundle` that ships with Xcode. The other difference since before is a minor one: the dyld shared cache has moved. Wheras before it was in `/System/Library/dyld/`, in the Ventura beta it's moved to `/System/Cryptexes/OS/System/Library/dyld/` (the Cryptex seems to be part of the [Rapid Security Response](https://threedots.ovh/blog/2022/06/a-quick-look-at-macos-rapid-security-response/) feature Apple announced). With the shared cache extracted, I could load the AppKit binary into Hopper (I had to disable the Objective-C analysis, otherwise the app crashed when trying to load the binary) and start poking around. I searched for the `NSPageLayout` class that I'm interested in, and looked at the `runModalWithPrintInfo:` method, since that sounded like a good candidate for something that would lead to the bulk of the implementation. And, indeed, it was. The method appears to be a fairly simple wrapper around the `PMPrepare...` function that sounds like it lives in a separate private framework. -
- Hopper window with AppKit showing the runModalWithPrintInfo: method -
+Hopper window with AppKit showing the runModalWithPrintInfo: method +