# NSTableView vim keys

DevFeed: [NSTableView vim keys](<https://devfeed.tech/articles/nstableview-vim-keys-25382.md>)

Original publisher: [Read original article](<https://smileykeith.com/2013/01/08/nstableview-vim-keys/>)

Author: Keith Smiley

Published: 2013-01-09T00:19:00Z

Content type: tutorial

Language: en

Sources: [Keith Smiley](<https://devfeed.tech/sources/keith-smiley.md>)

Topics: [Vim](<https://devfeed.tech/topics/vim.md>), [Code](<https://devfeed.tech/topics/code.md>), [App](<https://devfeed.tech/topics/app.md>), [data](<https://devfeed.tech/topics/data.md>), [Quartz](<https://devfeed.tech/topics/quartz.md>), [Stack Overflow](<https://devfeed.tech/topics/stackoverflow.md>)

Tags: [apis](<https://devfeed.tech/tags/apis.md>), [app](<https://devfeed.tech/tags/app.md>), [code](<https://devfeed.tech/tags/code.md>), [data](<https://devfeed.tech/tags/data.md>), [how-to](<https://devfeed.tech/tags/how-to.md>), [quartz](<https://devfeed.tech/tags/quartz.md>), [vim](<https://devfeed.tech/tags/vim.md>)

## AI overview

This article explains how to add Vim-style j and k navigation to an NSTableView in an OS X application. It describes attempts involving manual selection handling and Quartz Event Services, then presents an approach that works in a sandboxed application while preserving expected selection behavior.

## Source excerpt

I'm currently working on a OS X application that uses a few different NSTableViews to display user data. I was testing them out a bit to make sure multiple deletions worked correctly from my database and I found myself pressing 'j' and 'k' to try and move down and up. I decided it would be pretty cool to implement those two vim shortcuts into my table view just in case anyone else thinks like me. This functionality already exists in The Hit List an awesome GTD app that has a lot of baggage with me, and I'm sure it exists in other applications as well. In my NSTableView subclass' keyDown: method I tried a few things. Attempt 1: First I tried to re implement the functionality myself. In retrospect this doesn't make any sense but at first it was pretty simple. It looked something like this. NSUInteger flags = [theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask; NSNumber *shiftPressed = (flags & NSShiftKeyMask); if ([theEvent keyCode] == 38) { // j NSUInteger index = [[self selectedRowIndexes] lastIndex] + 1; if ([shiftPressed boolValue]) { [self selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:YES]; } else { [self selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO]; } } else if ([theEvent keyCode] == 40) { // k NSUInteger index = [[self selectedRowIndexes] lastIndex] - 1; if ([shiftPressed boolValue]) { [self selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:YES]; } else { [self selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO]; } } The issue with this is the way NSTableView typically expands it's selection. I think of it as a pivot point where you start. Then you go up and down relative to that point. So if you start at index 2 and go down till index 4, you should have 2 rows selected. Then when you go back up you should deselect the rows and indexes 3 and 4 and select the rows and index 1 and 0. At this point I realized it was more difficult than I r