Gentoo Wiki ArchivesGentoo Wiki

HOWTO_Microsoft_Natural_Ergonomic_Keyboard_4000


Warning: What explained below, while mostly valid, refers to code several months old and is in need of update.
Note: I am using sys-kernel/gentoo-sources-2.6.26-r1 and roughly xfce-4.4.2. Most, if not all extra keys work and are already preconfigured via XFCE keyboard shortcuts as long as you configure this keyboard to use evdev in xorg.conf. No other hacks or additions are needed (from this howto)! If you allow Xorg to automatically configure and recognize this keyboard, the extra zoom key may not be seen by xev. Take note Logitech. Keyboards should be as easily configured recognizing all keys and large enough for our hands to fit!


Contents

Introduction

The Microsoft Natural Ergonomic Keyboard 4000 is one of several similar computer keyboards that tilts the keys to make typing more comfortable. Some non-standard keys have been added. Also, an F-lock key toggles the function keys (F1, F2, F3, etc.) between standard functions and "enhanced" functions (i.e., the F-Lock key changes the key codes that are generated when the function keys are pressed).

This HOWTO attempts to provide a working configuration for the Microsoft Natural Ergonomic Keyboard 4000 under linux, from the console to X, enabling all the non-standard keys which it features.

Kernel Configuration

Enabling all the functionalities of this extended keyboard requires patches to the kernel in order to encompass the totality of its capabilities. Thankfully such code has been provided and posted to the linux-usb-devel list [1] by liyu[2], as you can see from this list[3]. (As you can see from the list there is also a different patch from John Zaitseff, which I haven't tried and cannot comment upon). A simpler approach is found in these patches from powerman [4], possibly derived from the one just mentioned above, which unfortunately remove the non-F-locked versions of the Function keys. This behaviour can be reproduced, in what I believe to a far more flexible way, binding, for each of those keys, the same keysym to both the Function key and its non-F-locked correspondent, as we describe later for the console and X.

Warning: liyu's implementation chooses to map some keys to the appropriate keycodes as found in /usr/include/linux/input.h, which unfortunately have values higher than 255, maximum value allowed by both X and the console, leading to several problems which will be described further on.

If you don't know how to apply the patches refer to Kernel/Patching.

The following are the required options to enable in the kernel, namely the evdev input module, the USB HID and what provived by the aforementioned patches.

Linux Kernel Configuration: Kernel Configuration (2.6.18 Example)
Device Drivers  --->
    Input Device Support  --->
        <M> Event Interface

    USB Support  --->
        <M> USB Human Interface Device (full HID) support
        [*] HID input layer support
        [*] HID simple driver interface
        <M>   Microsoft Natural Ergonomic Keyboard 4000 Driver


Note: Should evdev not be loaded automatically add it to /etc/modules.autoload.d/kernel-2.6

Device Interface

The unusual phenomenon one can notice upon plugging in the keyboard is the creation of not one but two /dev/input/event* devices associated with it.

See the following extracts:

File: /var/log/messages
input: Microsoft Natural Ergonomic Keyboard 4000 as /class/input/input29
input: USB HID v1.11 Keyboard [Microsoft Natural Ergonomic Keyboard 4000] on usb-0000:00:1d.7-3.2
input: Microsoft Natural Ergonomic Keyboard 4000 as /class/input/input30
input: USB HID v1.11 Device [Microsoft Natural Ergonomic Keyboard 4000] on usb-0000:00:1d.7-3.2
The simple HID driver 'Microsoft Natural Ergonomic Keyboard 4000' register.
The simple HID driver 'Microsoft Natural Ergonomic Keyboard 4000' attach on'Microsoft Natural Ergonomic Keyboard 4000'
The simple HID driver 'Microsoft Natural Ergonomic Keyboard 4000' attach on'Microsoft Natural Ergonomic Keyboard 4000'


Warning: It seems that sometimes, after plugging in and unplugging the keyboard, the simple HID driver does not attach to both devices. In this case unplug the keyboard, then
rmmod usbnek4k
and plug it back in.

A practical way to do it is something like this:

sleep 15s && rmmod usbnek4k


File: /proc/bus/input/devices
I: Bus=0003 Vendor=045e Product=00db Version=0173
N: Name="Microsoft Natural Ergonomic Keyboard 4000"
P: Phys=usb-0000:00:1d.7-3.2/input0
S: Sysfs=/class/input/input29
H: Handlers=kbd event20
B: EV=120003
B: KEY=10000 7 ff800000 7ff febeffdf f3cfffff ffffffff fffffffe
B: LED=7

I: Bus=0003 Vendor=045e Product=00db Version=0173
N: Name="Microsoft Natural Ergonomic Keyboard 4000"
P: Phys=usb-0000:00:1d.7-3.2/input1
S: Sysfs=/class/input/input30
H: Handlers=kbd event21
B: EV=10000f
B: KEY=7c0000 0 c0002 1400 0 0 1 10f80 287c407 ffff39fa d97157ff febeffdf ffefffff ffffffff fffffffe
B: REL=40
B: ABS=1 0


File: /proc/bus/usb/devices
T:  Bus=01 Lev=02 Prnt=08 Port=01 Cnt=02 Dev#= 20 Spd=1.5 MxCh= 0
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=045e ProdID=00db Rev= 1.73
S:  Manufacturer=Microsoft
S:  Product=Natural Ergonomic Keyboard 4000
C:* #Ifs= 2 Cfg#= 1 Atr=a0 MxPwr=100mA
I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=01 Driver=usbhid
E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=10ms
I:  If#= 1 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=00 Prot=00 Driver=usbhid
E:  Ad=82(I) Atr=03(Int.) MxPS=   8 Ivl=10ms


The reason for that is that the keyboard splits its functionalities in two different sections, so to speak (I lack a deep knowledge of USB terminology and technology, so forgive my imprecisions and correct them if possible).

The first device, which is the one listed first in each of the above files, and recognized as a "USB HID v1.11 Keyboard", is the device responsible for the standard keys events, with (parameters coming from the USB HID 1.11 specification) Interface Subclass having 1 as value (identifying it as a device implementing a Boot Protocol and therefore able to communicate with the BIOS at boot), and Interface Protocol set to 1 (identifying as a keyboard).

The second device, recognized as a "USB HID v1.11 Device", and with both Subclass and Protocol set to 0 (default values for every HID device not implementing any Boot Protocol, namely every device but keyboards and mice), is responsible for the "multimedia" keys events.

In fact, using evtest with the two /dev/input/event* related to the two devices, you will see how the events related to standard and "multimedia" keys are differentiated at the device level.

Console Configuration

The kernel driver provides keycodes for all the keys, (which can be discovered, as well as with evtest, as I said above, with the more traditional showkey -k), which are all below 256, apart from six of the multimedia keys:

As far as I know, and as far as the ouput of dumpkeys suggests to me, only keycodes up to 255 can actually be employed.

man 5 keymaps explains the syntax of the files under /usr/share/keymaps, allowing to bind these keycodes to keysyms, strings, etc...

X.org configuration

When it comes to X configuration of the keyboard we must differentiate among:

  1. the configuration of the InputDevice section of /etc/X11/xorg.conf
  2. the configuration of various XKB files which constitute the description of the keyboard layout and its functions
  3. the configuration of programs such as xbindkeys or xvkbd or of the various Window Managers you might employ, which allow to bind a key to an action, program, or command

Device Configuration

The first thing about configuring the keyboard in X is choosing which devices have to manage the keyboard. The choice is between 'keyboard' (or its replacement 'kbd') or 'evdev'.

Initially I employed the first alternative, but unfortunately it suffers from the same shortcomings affecting the console, namely the lack of recognition for the six keys mentioned above. Actually xev doesn't even report their keycodes, making them utterly invisible to X.

As far as I could see around the net that's pretty much the situation everyone is in. Fortunately, there is a remedy, which ensues from the considerations made above about the existance of TWO devices associated with the keyboard.

The solution is, quite simply, to create two InputDevice sections, each using the 'evdev' driver to read the events respectively from one of the two event devices present.

Warning: The interaction between liyu's implementation of the kernel driver and the workings of the X evdev driver has, as a result, that the Favorites key generates the same keycode of the Down Arrow key, and the Print(F12) key the same of the Big 1 key, making them undistinguishable, as far as X is concerned. Further informations in the "Evdev more in depth" section.

That said we need a means to distinguish the two devices we need. The contents of /proc/bus/input/devices give us what we need. You can see in the box above how the event devices names are listed at the "Handlers:" line.

We need now to make those device names permanent, thus they'll remain the same even if you reboot and regardless of the order in which you might plug in your input peripherals.

In order to obtain that we will create two custom udev rules.

Note:

In case you never remove your keyboard from the usual usb socket (not even to move it to an external usb hub) you can use a simpler method I'll explain below.

First we'll use udevinfo on each of the two devices /dev/input/event* reported in /proc/bus/input/devices to discover the modalias string that's unique to those devices.

# udevinfo -a -p `udevinfo -q path -n /dev/input/event20`|grep modalias|grep usb

SYSFS{modalias}=="usb:v045Ep00DBd0173dc00dsc00dp00ic03isc00ip00"
# udevinfo -a -p `udevinfo -q path -n /dev/input/event21`|grep modalias|grep usb

SYSFS{modalias}=="usb:v045Ep00DBd0173dc00dsc00dp00ic03isc01ip01"

As you can see the strings differ only for the values of the USB HID Interface Subclass (isc) and Interface Protocol (ip) aforementioned.

Now we can create our custom rules:

File: /etc/udev/rules.d/10-nek4k.rules
KERNEL=="event*",SYSFS{modalias}=="usb:v045Ep00DBd0173dc00dsc00dp00ic03isc00ip00", MODE="0644", NAME="input/event20"
KERNEL=="event*",SYSFS{modalias}=="usb:v045Ep00DBd0173dc00dsc00dp00ic03isc01ip01", MODE="0644", NAME="input/event21"

We could not use different custom names than event* because of restrictions of the X evdev driver, therefore a good solution is, as you can see above, to set the names to eventXX, where XX is a number high enough not to conflict with other already connected input devices.

Here is an example of xorg.conf configuration.

File: /etc/X11/xorg.conf
Section "InputDevice"

    Identifier  "Keyboard1"
    Driver      "evdev"
    Option      "Protocol"      "evdev"
    Option      "Device"        "/dev/input/event20"

    Option      "XkbModel"      "evdev"
    ...

EndSection

Section "InputDevice"

    Identifier  "Keyboard2"
    Driver      "evdev"
    Option      "Protocol"      "evdev"
    Option      "Device"        "/dev/input/event21"

    Option      "XkbModel"      "evdev"
    ...

EndSection

...

Section "ServerLayout"
    
    ...
    InputDevice "Keyboard1" "CoreKeyboard"
    InputDevice "Keyboard2" "SendCoreEvents"
    ...

EndSection

The Option "Device" "..." is discouraged by the man page of the evdev driver ( man 4x evdev ), but the only other way to distinguish between the devices is to use the Option "Phys" "string", where "string" is found again in the contents of /proc/bus/input/devices, as the value of the corresponding field. Unfortunately that value is "connected" to the usb port the keyboard is plugged into, therefore it changes if the keyboard is plugged in elsewhere and thus not consistent in such cases.

Evdev more in depth

We have stated before,talking about the console, that six keys yield keycodes higher than 255, causing problems because in both console and X, 255 is the maximum allowed keycode. The kernel evdev driver assigns as keycodes values from 1 up, but X allows only keycodes in the range 9-255, therefore the X evdev driver first add 8 to every received keycode before parsing them, then truncate the keycode to an 8 bits value. In brief:

X keycode = ((kernel keycode + 8) mod 256)

That may, and with liyu's implementation does, cause some keys to have different kernel keycodes and same X keycodes. For example the Down Arrow key has the kernel keycode 108, while the Favorites key 364 (108+256), and under X with the evdev driver they both have keycode 116. A dirty workaround to this problem (caused, in my opinion, by the use of single-byte keycodes in X rather than by the the implementation of the kernel driver) is to replace the strings KEY_FAVORITES and KEY_FN_F1 in /usr/src/linux/drivers/usb/input/usbnek4k.c with others from /usr/include/linux/input.h so that eventually their X keycodes do not overlap ones associated with other keys.

Replacing those two strings along with the other KEY_FN_F* with others whose keycodes are below 256 (and of course not already generated by other keys) also allow us to have the keyboard completely mapped also using the console.

Further considerations and workarounds here. Talk:HOWTO Microsoft Natural Ergonomic Keyboard 4000

XKB Configuration

In order to map the supplementary keys we need to alter some of the xkb files under /usr/share/X11/xkb tree (it could also be /usr/lib/X11/xkb).

# ls -1 /usr/share/X11/xkb/

compat/
compat.dir
compiled@
geometry/
geometry.dir
keycodes/
keycodes.dir
keymap/
keymap.dir
rules/
semantics/
semantics.dir
symbols/
symbols.dir
types/
types.dir

The compat and types files are advanced configurations whose purposes are outside the scope of this howto; semantics files are collections of the previous two, while keymap files are deprecated. Our interest is the remaining four categories: rules, geometry, symbols, keycodes.

keycodes files map numeric keycodes to symbolic names.
symbols files map those symbolic names to keysyms, which are what we all use, from the alphanumeric characters to control characters, etc...
geometry files create descriptions of the physical layout of the keys, which can then be used to create a graphical representation of the keyboard with xkbcomp and xkbprint.
rules files define combinations of all the other types of files.
All the *.dir files list all the items within the files of the corresponding type, along with some flags.
Now we can begin:


File: geometry/microsoft
....
    }; // End of "Keypad" section

    alias <AC00> = <CAPS>;
    alias <AA00> = <LCTL>;
};

// The following is the section to add

xkb_geometry "nek4k" {

    // Approximate layout for a Microsoft Natural Keyboard
    description= "Microsoft Natural Ergonomic Keyboard 4000";
    width= 500;
    height= 260;

    shape.cornerRadius= 1;
    shape "ZOOM" { { [ 16,15] } };
    shape "MUL1" { { [ 22,10] } };
    shape "MUL2" { { [ 20,10] } };
    shape "MUL3" { { [ 26,10] } };
    shape "DIR"  { { [ 17,15] } };
    shape "LDEF" { { [ 18,18] }, { [2,1], [15,16] } };
    shape "FUNC" { { [ 18,15] }, { [3,1], [15,10] } };
    shape "TABK" { { [ 36,18] }, { [3,1], [34,16] } };
    shape "CAPS" { { [ 37,18] }, { [3,1], [33,16] } };
    shape "LFSH" { { [ 23,18] }, { [3,1], [21,16] } };
    shape "KEY~" { { [ 28,18] }, { [3,1], [25,15] } };
    shape "KEY6" { { [ 20,18] }, { [2,1], [16,16] } };
    shape "KEYB" { { [ 19,18] }, { [2,1], [15,16] } };
    shape "KEYT" { { [ 30,18] }, { [2,1], [26,16] } };
    shape "KEYG" { { [ 26,18] }, { [2,1], [22,16] } };
    shape "LCTL" {
        approx= { [ 33, 21 ] },
        { [  0, 0], [ 33, 0 ], [ 33, 25 ], [ 0, 18 ] },
        { [  2, 1], [ 30, 1 ], [ 30, 20 ], [ 2, 15 ] }
    };
    shape "LWIN" {
        approx= { [ 26, 26 ] },
        { [  0, 0], [ 26, 0 ], [ 26, 28 ], [ 0, 25 ] },
        { [  2, 1], [ 23, 1 ], [ 23, 23 ], [ 2, 21 ] }
    };
    shape "LALT" {
        approx= { [ 27, 29 ] },
        { [  0, 0], [ 27, 0 ], [ 27, 30 ], [ 0, 28 ] },
        { [  2, 1], [ 24, 1 ], [ 24, 26 ], [ 2, 24 ] }
    };
    shape "RDEF" { { [ 18,18 ] }, { [3,1], [15,16] } };
    shape "KEY7" { { [ 30,18 ] }, { [4,1], [27,16] } };
    shape "KEYY" { { [ 21,18 ] }, { [4,1], [18,16] } };
    shape "KEYH" { { [ 27,18 ] }, { [4,1], [24,16] } };
    shape "KEYN" { { [ 37,18 ] }, { [4,1], [34,16] } };
    shape "BKSP" { { [ 37,18 ] }, { [3,1], [34,16] } };
    shape "BKSL" { { [ 16,18 ] }, { [3,1], [13,16] } };
    shape "RTRN" { { [ 0,0 ], [ 23,0 ], [ 23,37], [ 7,37 ], [ 7,18 ], [ 0, 18 ] }, { [ 3,1 ], [ 20,1 ], [ 20,34 ], [ 10,34 ], [ 10,15], [3,15] } };
    shape "RTSH" { { [ 40,18 ] }, { [  3, 1], [37, 16] } };
    shape "RALT" {
        approx= { [ 35, 30 ] },
        { [  0, 0], [ 35, 0 ], [ 35, 28 ], [ 0, 31 ] },
        { [  3, 1], [ 32, 1 ], [ 32, 25 ], [ 3, 27 ] }
    };
    shape "MENU" {
        approx= { [ 35, 27 ] },
        { [  0, 0], [ 35, 0 ], [ 35, 25 ], [ 0, 28 ] },
        { [  3, 1], [ 32, 1 ], [ 32, 22 ], [ 3, 24 ] }
    };
    shape "RCTL" {
        approx= { [ 34, 24 ] },
        { [  0, 0], [ 34, 0 ], [ 34, 20 ], [ 0, 25 ] },
        { [  3, 1], [ 31, 1 ], [ 31, 17 ], [ 3, 21 ] }
    };
    shape "KPAD" { { [ 18, 37 ] },      { [ 3, 1 ], [ 16, 34 ] } };
    shape "KP0"  { { [ 37, 18 ] },      { [ 3, 1 ], [ 35, 15 ] } };
    shape "SPCE" {
        { [  14, 2.5], [57,10], [60, 15], [86, 15], [89,9.5], [133, 1.5],
          [138.5,32.5], [94,38], [52,38], [ 8.5,32.5] },
        { [  16, 3.5], [52,10], [58, 20], [88, 20], [94,9.5], [131, 2.5],
          [135.5,29.5], [94,35], [52,35], [ 11.5,29.5] }
    };

    shape "EDGE" {
        cornerRadius= 2,
        { [  25,   0 ], [ 500,   0 ],
          [ 500, 220 ],  [ 390, 225 ],  [ 170, 260 ], [   0, 230 ] }
    };
    outline "Edges" {
        top= 0;
        left= 0;
        shape= "EDGE";
    };

    row.left= 1;
    key.gap=  1;
    key.shape= "FUNC";
    section "LeftFunction" {
        top= 25;
        left= 30;
        angle= 10;
        row {
            top= 1;

            keys {  <ESC>, { <FK01>, 15 }, <FK02>, <FK03>, <FK04>, <FK05> };
        };
    }; // End of "LeftFunction" section

    key.shape= "LDEF";
    section "LeftAlpha" {
        top= 47;
        left= 30;
        angle= 10;
        row {
            top= 1;
            left= -5;
            keys {      { <AE00>, "KEY~" }, <AE01>, <AE02>, <AE03>, <AE04>,
                        <AE05>, { <AE06>, "KEY6" }
            };
        };
        row {
            top= 20;
            left= -4;
            keys {      { <TAB>, "TABK" },
                        <AD01>, <AD02>, <AD03>, <AD04>, { <AD05>, "KEYT" }
            };
        };
        row {
            top= 39;
            left= -1;
            keys {      { <CAPS>, "CAPS" },
                        <AC01>, <AC02>, <AC03>, <AC04>, { <AC05>, "KEYG" }
            };
        };
        row {
            top= 58;
            keys {      { <LFSH>, "LFSH" },
                        <AB01>, <AB02>, <AB03>, <AB04>, <AB05>, { <AB06>, "KEYB" }
            };
        };
        row {
            top= 77;
            left= 7;
            keys {  { <LCTL>, "LCTL" }, { <LWIN>, "LWIN" }, { <LALT>, "LALT" } };
        };
    }; // End of "LeftAlpha" section

    key.shape= "FUNC";
    section "RightFunction" {
        top= 47;
        left= 185;
        angle= -10;
        row {
            top= 1;
            left= 1;
            keys {  <FK06>, <FK07>, <FK08>, <FK09>, <FK10>, <FK11>, <FK12>, <FLCK> };
        };
    }; // End of "RightFunction" section

    key.shape= "RDEF";
    section "RightAlpha" {
        top= 71;
        left= 172;
        angle= -10;
        row.left= 1;
        row {
            top= 1;
            keys {      { <AE07>, "KEY7" },
                        <AE08>, <AE09>, <AE10>, <AE11>, <AE12>,
                        { <BKSP>, "BKSP" }
            };
        };
        row {
            top= 20;
            keys {
                { <AD06>, "KEYY" }, <AD07>, <AD08>, <AD09>, <AD10>, <AD11>, <AD12>,
                { <RTRN>, "RTRN" }
            };
        };
        row {
            top= 39;
            keys {      { <AC06>, "KEYH" },
                        <AC07>, <AC08>, <AC09>, <AC10>, <AC11>,{ <BKSL>, "BKSL" }
            };
        };
        row {
            top= 58;
            keys {      { <AB07>, "KEYN" },
                        <AB08>, <AB09>, <AB10>, <AB11>,
                        { <RTSH>, "RTSH" }
            };
        };
        row {
            top= 77;
            left= 46;
            keys {      { <RALT>, "RALT" }, { <MENU>, "MENU" }, { <RCTL>, "RCTL" }
            };
        };
    }; // End of "RightAlpha" section

    section "SpaceBar" {
        top= 137;
        left= 96;
        key.shape= "SPCE";
        row { keys { <SPCE> }; };
    };

    section "Editing" {
        top= 20;
        left= 350;
        row {
            top= 1;
            key.shape= "FUNC";
            keys { <PRSC>, <SCLK>, <PAUS> };
        };
        row {
            top= 22;
            keys { <INS>, <HOME>, <PGUP> };
        };
        row {
            top= 42;
            keys { <DELE>, <END>, <PGDN> };
        };
        row {
            top= 80;
            left= 20;
            keys { <UP> };
        };
        row {
            top= 99;
            keys { <LEFT>, <DOWN>, <RGHT> };
        };
    }; // End of "Editing" section

    shape "LED"  {
        cornerRadius= 0,
        { [  3,  1 ] }
    };
    indicator.onColor= "green";
    indicator.offColor= "green30";
    indicator.left= 170;
    indicator.shape= "LED";
    indicator "Num Lock"     { top= 215; };
    indicator "Caps Lock"    { top= 225; };
    indicator "Scroll Lock"  { top= 235; };
    indicator "Function Lock"  { top= 245; };

    section "Keypad" {
        top= 42;
        left= 414;
        row {
            top= 1;
            keys { <NMLK>, <KPDV>, <KPMU>, <KPSU> };
        };
        row {
            top= 20;
            keys { <KP7>, <KP8>, <KP9>, { <KPAD>, "KPAD" } };
        };
        row {
            top= 39;
            keys { <KP4>, <KP5>, <KP6> };
        };
        row {
            top= 58;
            keys { <KP1>, <KP2>, <KP3>, { <KPEN>, "KPAD" } };
        };
        row {
            top= 77;
            keys { { <KP0>, "KP0" }, <KPDL> };
        };
    }; // End of "Keypad" section

    section "ExtKeypad" {
        top= 20;
        left= 414;
        key.shape= "FUNC";
        row {
            top= 1;
            keys { <EQUL>, <PARO>, <PARC>, <BKSP> };
        };
    }; // End of "ExtKeypad" section

    section "Multimedia1" {
        top= 4;
        left= 30;
        row {
            top= 1;
            key.shape= "MUL1";
            key.gap=0;
            keys { <WEB>, <FIND>, <MAIL>,{ <VOLD>, 175 }, <VOLU> };
        };
    };

    section "Multimedia2" {
        top= 4;
        left= 35;
        row {
            top= 1;
            key.shape= "MUL2";
            key.gap=0;
            keys { { <MUTE>, 210}, { <PLAY>, 55}, { <CALC>, 29 } };
        };
        row {
            top= 26;
            key.shape= "MUL2";
            keys { { <BKMK>, 125} };
        };
    };

    section "Multimedia3" {
        top= 4;
        left= 105;
        row {
            key.gap=0;
            top= 1;
            key.shape= "MUL3";
            keys { <ONE>, <TWO>, <THRE>, <FOUR>, <FIVE> };
        };
    };

    section "Zoom" {
        top= 111;
        left= 162;
        row {
            top= 1;
            key.gap=0;
            key.shape= "ZOOM";
            keys { <ZMUP> };
        };
        row {
            top= 17;
            key.gap=0;
            key.shape= "ZOOM";
            keys { <ZMDN> };
        };
    };

    section "Navigation" {
        top= 190;
        left= 153;
        row {
            key.gap=0;
            top= 1;
            key.shape= "DIR";
            keys { <PREV>, <SUCC> };
        };
    };

    alias <AC00> = <CAPS>;
    alias <AA00> = <LCTL>;
};



File: geometry.dir
...
-d------ -------- northgate(omnikey101)
-d------ -------- microsoft(natural)
// Insert the following line and not this one
-d------ -------- microsoft(nek4k)
-d------ -------- hp(pc101)
...



File: keycodes/nek4k
default xkb_keycodes "nek4k" {

        <WEB>   =       180;
        <FIND>  =       225;
        <MAIL>  =       223;

        <ZMUP>  =       191;
        <ZMDN>  =       192;

        <PREV>  =       166;
        <SUCC>  =       167;

        <EQUL>  =       125;
        <PARO>  =       187;
        <PARC>  =       188;

        <MUTE>  =       121;
        <VOLD>  =       122;
        <VOLU>  =       123;
        <PLAY>  =       172;

        <CALC>  =       148;

alias   <BKMK>  =       <DOWN>;

        <ONE>   =       218;
        <TWO>   =       219;
        <THRE>  =       220;
        <FOUR>  =       221;
        <FIVE>  =       222;

        <HELP>  =       146;
        <UNDO>  =       139;
        <REDO>  =       190;
        <NEW>   =       189;
        <OPEN>  =       142;

        <CLOS>  =       214;
        <REPL>  =       240;
        <FWD>   =       241;
        <SEND>  =       239;
        <SPLL>  =       193;
        <SAVE>  =       242;
alias   <PRNT>  =       <ONE>;
};



File: keycodes.dir
...
-d------ -------- nek4k(nek4k)




File: symbols/inet
...
//   Control Section -- Far Right 
//   F-Locked Function keys 
//   Internet Section -- Right Side 
//   Multimedia Section -- Centre 
//   My Computer Section -- Left Side 
}; 

//Insert the following section

// Microsoft Natural Ergonomic Keyboard 4000
partial alphanumeric_keys
xkb_symbols "microsoftnek4k" {
	
    key <WEB>   {       [ XF86WWW ]       }; 
    key <FIND>   {       [ XF86Documents ]       }; 
    key <MAIL>   {       [ XF86Documents ]       }; 
    key <ZMUP>   {       [ XF86Documents ]       }; 
    key <ZMDN>   {       [ XF86Documents ]       }; 
    key <PREV>   {       [ XF86Documents ]       }; 
    key <SUCC>   {       [ XF86Documents ]       }; 
    key <EQUL>   {       [ XF86Documents ]       }; 
    key <PARO>   {       [ XF86Documents ]       }; 
    key <PARC>   {       [ XF86Documents ]       }; 
    key <MUTE>   {       [ XF86Documents ]       }; 
    key <VOLU>   {       [ XF86Documents ]       }; 
    key <VOLD>   {       [ XF86Documents ]       }; 
    key <PLAY>   {       [ XF86Documents ]       }; 
    key <CALC>   {       [ XF86Documents ]       }; 
    key <ONE>   {       [ XF86Documents ]       }; 
    key <TWO>   {       [ XF86Documents ]       }; 
    key <THRE>   {       [ XF86Documents ]       }; 
    key <FOUR>   {       [ XF86Documents ]       }; 
    key <FIVE>   {       [ XF86Documents ]       }; 
    key <HELP>   {       [ XF86Documents ]       }; 
    key <UNDO>   {       [ XF86Documents ]       }; 
    key <REDO>   {       [ XF86Documents ]       }; 
    key <NEW>   {       [ XF86Documents ]       }; 
    key <OPEN>   {       [ XF86Documents ]       }; 
    key <CLOS>   {       [ XF86Documents ]       }; 
    key <REPL>   {       [ XF86Documents ]       }; 
    key <FWD>   {       [ XF86Documents ]       }; 
    key <SEND>   {       [ XF86Documents ]       }; 
    key <SPLL>   {       [ XF86Documents ]       }; 
    key <SAVE>   {       [ XF86Documents ]       }; 

};

// Oretec

// Oretec MCK-800 MM/Internet keyboard
...


Note:

The sample XF86* Keys can be substituted with others of your liking from /usr/share/X11/XKeysymDB. The various keysyms X uses are listed in /usr/include/X11/keysymdef.h , without the leading XK_.



File: symbols.dir
...
--p----- a------- inet(microsoftoffice)
--p----- a------- inet(microsoftmult)
//Insert only the following line
--p----- a------- inet(microsoftnek4k)
--p----- a------- inet(oretec)
--p----- a------- inet(propeller)
...


The position where we inserted our additions in the previous files is, of course, of no consequence.


File: rules/base
...
! $inetkbds = a4techKB21 a4techKBS8 acer_tm_800 acpi airkey azonaRF2300 \
...
              microsoftoffice microsoftmult \
//Insert the following line
              microsoftnek4k \
              oretec \
...
! model         =       keycodes
...
  evdev         =       evdev
//Insert the following line
  microsoftnek4k =      evdev+nek4k(nek4k)
  *             =       xfree86
...
! model         =       geometry
...
  microsoftprose =      microsoft(natural)
//Insert the following line
  microsoftnek4k =      microsoft(nek4k)
  dell101       =       dell(dell101)
...


Then we alter again /etc/X11/xorg.conf

File: /etc/X11/xorg.conf
Section "InputDevice"

    Identifier  "Keyboard1"
    Driver      "evdev"
    Option      "Protocol"      "evdev"
    Option      "Device"        "/dev/input/event20"

#    Remove the following line
#    Option      "XkbModel"      "evdev"
     Option      "XkbModel"      "microsoftnek4k"
     Option      "XkbLayout"     "us"
     Option      "XkbRules"      "xorg"

EndSection

Section "InputDevice"

    Identifier  "Keyboard2"
    Driver      "evdev"
    Option      "Protocol"      "evdev"
    Option      "Device"        "/dev/input/event21"

#    Remove the following line
#    Option      "XkbModel"      "evdev"
     Option      "XkbModel"      "microsoftnek4k"
     Option      "XkbLayout"     "us"
     Option      "XkbRules"      "xorg"

EndSection

...

Section "ServerLayout"
    
    ...
    InputDevice "Keyboard1" "CoreKeyboard"
    InputDevice "Keyboard2" "SendCoreEvents"
    ...

EndSection

Action Bindings

TODO

Here's a relatively easy way to bind your special keys to certain actions/commands in KDE: http://dev-loki.blogspot.com/2006/04/mapping-unsupported-keys-with-xmodmap.html


< Perhaps the steps in this blog post should be detailed here with due credit given? >

Modern Way of doing things

Recent (2.6.24) versions of Linux have fully functional Microsoft Natural 4000 support. You do not need to patch kernel really much now.

Kernel

Code: Get a bleeding edge version of Linux kernel
emerge git-sources

Due to limitations of X11 protocol (no keycodes outside 9—255 range are allowed), some kernel keycode bindings should be fixed in order to make zoom throttle and «Spellcheck» key work under X. Apply the following patch to include/linux/input.h file of kernel sources (only 3 lines are changed):

File:
--- /usr/src/linux/include/linux/input.h.orig       2007-12-31 12:36:02.000000000 +0300
+++ /usr/src/linux/include/linux/input.h    2007-12-30 18:37:19.000000000 +0300
@@ -510,8 +510,8 @@
 #define KEY_TWEN           0x19f
 #define KEY_VIDEOPHONE     0x1a0   /* Media Select Video Phone */
 #define KEY_GAMES          0x1a1   /* Media Select Games */
-#define KEY_ZOOMIN         0x1a2   /* AC Zoom In */
-#define KEY_ZOOMOUT        0x1a3   /* AC Zoom Out */
+#define KEY_ZOOMIN         246     /* AC Zoom In */
+#define KEY_ZOOMOUT        247     /* AC Zoom Out */
 #define KEY_ZOOMRESET      0x1a4   /* AC Zoom */
 #define KEY_WORDPROCESSOR  0x1a5   /* AL Word Processor */
 #define KEY_EDITOR         0x1a6   /* AL Text Editor */
@@ -524,7 +524,7 @@
 #define KEY_ADDRESSBOOK    0x1ad   /* AL Contacts/Address Book */
 #define KEY_MESSENGER      0x1ae   /* AL Instant Messaging */
 #define KEY_DISPLAYTOGGLE  0x1af   /* Turn display (LCD) on and off */
-#define KEY_SPELLCHECK     0x1b0   /* AL Spell Check */
+#define KEY_SPELLCHECK     235     /* AL Spell Check */
 #define KEY_LOGOFF         0x1b1   /* AL Logoff */

 #define KEY_DOLLAR         0x1b2

In kernel config, make sure the following options are enabled:

Linux Kernel Configuration: 2.6.24-rc6
Device Drivers --->
    HID Devices --->
        <*> USB Human Interface Device (full HID) support
    Input Device Support --->
        <*> Event interface

Compile and install the new kernel. Reboot your system.

By now, showkey should react to all keys on your keyboard, including zoom!

X

If you're using an old version of X Window System and are not willing to change the existing configuration, you may skip this section; xev should react to all keys on your keyboard by now, so using xmodmap and any keybinding utility like xbindkeys you may make use of all keys on your fancy Microsoft keyboard!

The followiing configuration method requires at least hal-0.5.9.1 and xorg-server-1.4.0.9:

Code: Unmask recent version of driver
echo "=x11-drivers/xf86-input-evdev-1.2.0 **" >> /etc/portage/package.keywords
Code: Get X server and event driver
INPUT_DEVICES="evdev" USE="hal" emerge xorg-server xf86-input-evdev

Modern X (X11R7.3) versions allow input device hotplugging using HAL. Now you may wipe InputDevice sections away from your /etc/xorg.conf file, as well as references to them in ServerLayout section, example:

File: /etc/xorg.conf
Section "ServerLayout"
    Identifier  "Main Layout"
    Screen      "Screen1"
EndSection
Note: If you have non-standard multibutton mouse, you may wish not to use the evdev driver for it. Described configuration has been tested for usual 3-button & wheel Logitech mouse.

Add AllowEmptyInput option to ServerFlags section, example:

File: /etc/xorg.conf
Section "ServerFlags"
    Option      "blank time" "10"
    Option      "standby time" "20"
    Option      "suspend time" "30"
    Option      "off time" "60"
    Option      "AllowEmptyInput"
EndSection

Now make HAL assign special properties to your input devices to make them discoverable by X server. Create the following file:

File: /etc/hal/fdi/policy/x11-input.fdi
<?xml version="1.0" encoding="UTF-8"?>
<deviceinfo version="0.2">
  <device>
    <match key="info.capabilities" contains="input.mouse">
      <merge key="input.x11_driver" type="string">evdev</merge>
    </match>
    
    <match key="info.product" contains="Microsoft Natural">
      <merge key="input.x11_driver" type="string">evdev</merge>
      <merge key="input.xkb.model" type="string">evdev</merge>
      <merge key="input.xkb.variant" type="string">,winkeys</merge>
      <merge key="input.xkb.layout" type="string">us,ru</merge>
      <merge key="input.xkb.options" type="strlist">grp:caps_toggle</merge>
      <append key="input.xkb.options" type="strlist">grp_led:caps</append>
      <append key="input.xkb.options" type="strlist">compose:ralt</append>
    </match>
  </device>
</deviceinfo>
Note: Obviously, you will have to change the values of XKB layout, variant and options assigned by HAL to fit your needs. Do not change driver and model options.

Make sure hald and dbus-daemon scripts get loaded. Add them to an appropriate runlevel otherwise:

Code:
rc-update add hald default
rc-update add dbus default

Feel free to reboot X server with /etc/init.d/xdm restart now. Your keyboard and mouse should work. In case of glitches see /var/log/Xorg.0.log for relevant error messages.

Now you can use xev to test your keyboard. All keys should generate an X event. Now you may wish to bind lots of additional keys on this keyboard using xbindkeys or similar tool provided by your desktop environment.

Links

TODO

For now these about the configuration:

Gentoo Forums:

Thread with contributions by powerman: [6]
Thread with contributions by truc: [7]

Ubuntu Forums:

Thread with contributions by liyu: [8]

Recent Updates:

Recent updates of the patches by liyu: [9]

Retrieved from "http://www.gentoo-wiki.info/HOWTO_Microsoft_Natural_Ergonomic_Keyboard_4000"

Last modified: Wed, 08 Oct 2008 06:24:00 +1100 Hits: 37,894

Created by NickStallman.net, Luxury Homes Australia
Real estate agents should list their apartments, townhouses and units in Australia.