Table of Contents

Microsoft Natural Ergonomic Keyboard 4000

I spend a lot of time in front of a computer, both at home and at work. As normal keyboards are smaller in width than my shoulders I find using them forces me to twist my hands to get my fingers on the base keys for touch-typing. Imagine putting your hands out in front of you, palms down, now pretend there is a pivot through the base of your thumb and rotate your hands outwards, i.e. your little fingers towards the forearm, this is the twisting I, and no doubt many others, have to do to get their fingers to align with the base-keys for touch-typing (i.e. ASDF for the left hand and JKL; for the right hand).

The solution, I discovered long ago, was to use an ergonomic keyboard as the base key are further apart and slightly angled so that when you put your hands in front of you the keys are in the natural position to fall under your fingers. There is the added bonus that most ergonomic keyboards have built-in wrist supports too.

Having tried a few over the years I was delighted when I was bought a Microsoft Natural Ergonomic Keyboard 4000 by my then new employers at my request for an ergonomic keyboard. This really is the most comfortable keyboard I've ever used. The key layout is superb, and there are lots of funky multi-media keys that can be configured to provide short-cuts.

At the time there were no drivers in the Linux kernel for this device. Fortunately someone (Liyu) had started working on writing the drivers and with 2.6.24 support was available in kernel.

Kernel Configuration

You will need kernel >=2.6.24. Select the following options (whether you compile them as modules or into the kernel is your choice, I opt for the later).

Device Drivers  --->
    Input Device Support  --->
        <*> Event Interface
    HID Devices  --->
        <*> USB Human Interface Device (full HID) support

Now compile, install your kernel and reboot.

Device Interface

With your kernel configured you should now find that plugging the keyboard in results in two /dev/input/event* devices being listed

dmesg | grep 'Microsoft'
# dmesg | grep 'Microsoft'
usb 3-2: Manufacturer: Microsoft
input: Microsoft Natural® Ergonomic Keyboard 4000 as /devices/pci0000:00/0000:00:10.1/usb3/3-2/3-2:1.0/input/input4
input,hidraw1: USB HID v1.11 Keyboard [Microsoft Natural® Ergonomic Keyboard 4000] on usb-0000:00:10.1-2
input: Microsoft Natural® Ergonomic Keyboard 4000 as /devices/pci0000:00/0000:00:10.1/usb3/3-2/3-2:1.1/input/input5
input,hidraw2: USB HID v1.11 Device [Microsoft Natural® Ergonomic Keyboard 4000] on usb-0000:00:10.1-2
# ls /dev/input/by-path/ -l
total 0
lrwxrwxrwx 1 root root 9 Dec 11 08:56 pci-0000:00:10.1-usb-0:1:1.0-event-mouse -> ../event3
lrwxrwxrwx 1 root root 9 Dec 11 08:56 pci-0000:00:10.1-usb-0:1:1.0-mouse -> ../mouse0
lrwxrwxrwx 1 root root 9 Dec 11 08:56 pci-0000:00:10.1-usb-0:2:1.0-event-kbd -> ../event4
lrwxrwxrwx 1 root root 9 Dec 11 08:56 pci-0000:00:10.1-usb-0:2:1.1-event- -> ../event5

Note the numbers at the end of each line as these are the devices that you need to configure (and yours may well differ if you have other USB devices to me). Further information on the device can be obtained using lsusb and looking for the relevant section.

# lsusb -v
 
Bus 003 Device 003: ID 045e:00db Microsoft Corp. Natural Ergonomic Keyboard 4000 V1.0
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x045e Microsoft Corp.
  idProduct          0x00db Natural Ergonomic Keyboard 4000 V1.0
  bcdDevice            1.73
  iManufacturer           1 Microsoft
  iProduct                2 Natural® Ergonomic Keyboard 4000
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           59
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      1 Keyboard
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.11
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      60
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              10
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.11
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      86
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              10
Device Status:     0x0000
  (Bus Powered)

Custom ''udev'' rules

You now need to write some custom ''udev'' rules so that the keyboard is correctly identified.

/etc/udev/rules.d/10-net4k.rules

KERNEL=="event*",SYSFS{modalias}=="usb:v045Ep00DBd0173dc00dsc00dp00ic03isc01ip01", MODE="0644", NAME="input/event4"
KERNEL=="event*",SYSFS{modalias}=="usb:v045Ep00DBd0173dc00dsc00dp00ic03isc00ip00", MODE="0644", NAME="input/event5"

Xorg Configuration

In order to get your keyboard working properly under Xorg you need to utilise both device interfaces.

Section "InputDevice"
    Identifier     "Keyboard1"
    Driver         "evdev"
    Option         "Protocol" "evdev"
    Option         "Device" "/dev/input/event4"
    Option         "XkbModel" "microsoftnek4k"
    Option         "XkbLayout" "gb"
    Option         "XkbRules" "xorg"
EndSection
Section "InputDevice"
    Identifier     "Keyboard2"
    Driver         "evdev"
    Option         "Protocol" "evdev"
    Option         "Device" "/dev/input/event5"
    Option         "XkbModel" "microsoftnek4k"
    Option         "XkbLayout" "gb"
    Option         "XkbRules" "xorg"
EndSection
Section "ServerLayout"    
    ...
    InputDevice "Keyboard1" "CoreKeyboard"
    InputDevice "Keyboard2" "SendCoreEvents"
    ...
EndSection

Mapping Multimedia Keys

UPDATE This section used to contain detailed information on configuring X11 to generate keycodes but this is now redundant as the keyboards work 'out of the box' with each key illiciting keycodes when pressed, however the zoom slider gives keycodes > 255 which Xorg can not handle. The simplest solution is to use udev to capture/remap these and then bind them.

Configuring udev

Pretty simple, just add the following line to /lib/udev/rules.d/95-keymap.rules

ENV{ID_VENDOR}=="Microsoft", ENV{ID_MODEL_ID}=="00db", RUN+="keymap $name 0xc022d zoomin 0xc022e zoomout"

Testing & Configuring

You can now use showkey (part of sys-apps/kbd) to test the keyboard and should find that each key illicits an X keycode. Emerge sys-apps/kbd if needed…

emerge -av sys-apps/kbd

The keycodes I got are…

# Web/Home
keycode 172 press
keycode 172 release

# Search
keycode 217 press
keycode 217 release

# Mail
keycode 155 press
keycode 155 release

# Favourites 1
keycode 184 press
keycode 184 release

# Favourites 2
keycode 185 press
keycode 185 release

# Favourites 3
keycode 186 press
keycode 186 release

# Favourites 4
keycode 187 press
keycode 187 release

# Favourites 5
keycode 188 press
keycode 188 release

# Volume Down
keycode 114 press
keycode 114 release

# Volume Up
keycode 115 press
keycode 115 release

# Play/Pause
keycode 164 press
keycode 164 release

# Calculator
keycode 140 press
keycode 140 release

# Favourite
keycode 156 press
keycode 156 release

# Back
keycode 158 press
keycode 158 release

# Forward
keycode 159 press
keycode 159 release

# Zoom Up
keycode 418 press
keycode 418 release

# Zoom Down
keycode 419 press
keycode 419 release

# F1 (Without F-Lock)
keycode 138 press
keycode 138 release

# F2 (Without F-Lock)
keycode 131 press
keycode 131 release

# F3 (Without F-Lock)
keycode 182 press
keycode 182 release

# F4 (Without F-Lock)
keycode 181 press
keycode 181 release

# F5 (Without F-Lock)
keycode 134 press
keycode 134 release

# F6 (Without F-Lock)
keycode 206 press
keycode 206 release

# F7 (Without F-Lock)
keycode 232 press
keycode 232 release

# F8 (Without F-Lock)
keycode 233 press
keycode 233 release

# F9 (Without F-Lock)
keycode 231 press
keycode 231 release

# F10 (Without F-Lock)
keycode 432 press
keycode 432 release

# F11 (Without F-Lock)
keycode 234 press
keycode 234 release

# F12 (Without F-Lock)
keycode 210 press
keycode 210 release

Binding Multimedia Keys

You can bind actions to pretty much any key(/combination), again the Gentoo Wiki : Multimedia Keys is the best reference, although its a little dated now, so heres what I've done using the above keycodes.

xmodmap

Troubleshooting

I used to lose keymaps, but this is now pretty much redundant thanks to the obsolescence of HAL.

gentoo linux keyboard hardware howto