Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I don't have <em>any</em> prior experience with Windows driver programming, so if anyone notices something wrong, please correct me.</p> <p>However I am using the NEO layout (or the AdNW variant to be precise) and was curious, so I downloaded the DDK to see what I can learn from the documentation. I don't really have a solution for you and I think you may already know some of this stuff, but I thought that writing down what I have found may still be of some use, if only to clear things up a bit.</p> <h2>Overview</h2> <p>As far as I can tell, there are two paths that keyboard data can originate from. There are PS/2 devices and then there are USB keyboards. Both take a different path (USB data has its source in the HID infrastructure and PS/2 data is produced by the I8042prt driver), but end up at the so-called “Keyboard class driver”.</p> <p>From there on the data is either passed to DirectInput or the user32 legacy interface. It is not entirely clear, where the layout comes into play, but I think it is implemented on top of the Keyboard class driver.</p> <h2>Layout</h2> <p>Keyboard layouts basically seem to be a bunch of data structures, conforming to the <code>KBDTABLES</code> structure defined in kbd.h. Basically the low-level drivers produce a ScanCode and interpretation of these codes is done with this structure.</p> <p>The first important ones are <code>pusVSCtoVK</code>, <code>pVSCtoVK_E0</code> and <code>pVSCtoVK_E1</code>, which map the raw scan codes (and extended scan codes) of the driver to the hardware-independent virtual key codes. These key codes describe the <em>key</em>. The character mapping comes later. So the left cursor key produces <code>VK_LEFT</code>, and the S key produces <code>VK_S</code>, even if the layout turns this to something else later.</p> <p>Next there is <code>pCharModifiers</code>, which specifies which virtual keys are modifiers and what combinations produce the different shift states.</p> <p>Lastly there is <code>pVkToWcharTable</code> which maps all the virtual keys to a Unicode character, depending on the shift state. This is where most of the actual layout resides. There are some special values for dead keys and ligatures, but let's take that aside for now.</p> <h2>Applications</h2> <p>Now what do applications get at the end? Obviously they can obtain the virtual key code and the scan code from the usual window messages, such as <code>WM_INPUT</code>, <code>WM_KEYDOWN</code>, …. They can also query the layout for a Unicode character, using functions such as <code>ToUnicodeEx</code>. The virtual key codes and the Unicode characters are provided by the layout.</p> <p>For usual characters, everything is fine. The application will receive the input event, ask the layout for a character and there you go. The cursor keys are different though, because the mapping from virtual key to character is neither needed, nor meaningful. The application cares for the key, but not for a character. So it will base the action on the virtual key code. If it is <code>VK_LEFT</code>, it moves the cursor left. If it is <code>VK_RIGHT</code>, the cursor moves right and so on.</p> <p>This leaves us with a dilemma: if we want to make ModX + S move the cursor left, the modifier-aware <code>pVkToWcharTable</code> won't help us, because the applications never ask for a character, but for a key. And clearly S is not the same key as the left key. Producing a control character (that doesn't exist as far as I can tell) will most likely don't help either, because the applications wouldn't ask for it and don't interpret it.</p> <p>So what you actually want is for the S key to produce a different virtual key code if the proper modifier key is pressed, but the data structure for a layout won't allow such a mapping. It is not executing code after all, only a data structure.</p> <h2>What about Numpad?</h2> <p>Numpad seems to do what is required. The scan code of the keys stay the same, but depending on the Numlock state they produce different virtual key codes. I think, however, that windows does some special handling here. Those keys have the <code>KBDNUMPAD</code> flag set in <code>pusVSCtoVK</code>. It seems that windows will detect that and exchange the virtual keys depending on the Numlock state.</p> <p>I have at least found some evidence for that. Try searching for “xxxNumpadCursor” in Google. It turns up with some seemingly leaked windows code. There is a check for <code>KBDNUMPAD</code> and the code that seems to replace the virtual key, depending on Shift and Numlock. I doubt that this can be exploited for this purpose.</p> <h2>Is it even possible?</h2> <p>So if the layout can't do this, who can? Obviously some lower-level driver that produces raw scan codes. There is a sample for a so-called filter driver in the DDK, which is called “kbfiltr”. Basically it seems that such a filter driver can hook up on top of the existing drivers and rewrite the data that comes from the driver, so it should be possible to rewrite the scan code of the S key to Left, if another key is pressed.</p> <p>Note however that this would be a driver, not a layout. I'm not sure if that is a practical solution. It is as far as I can see unaware of the selected layout, so the changes would apply for all layouts. (It might be possible though to implement the whole layout here, complete with a key to toggle it off.) I'm also not sure how complex installation of such a driver would be and if you need to sign the driver, which would make things worse.</p> <p>I don't really have enough experience with driver programming (which is to say no experience at all), to recommend for or against this approach. It might be worth some experimenting (I would prefer a virtual machine here), but it seems a lot more challenging than the simple layout replacement that is currently done. The Autohotkey solution is probably still the best solution (with the drawback that it doesn't work for all applications).</p> <h2>Update</h2> <p>I did some more research. I think it is possible to do this with a filter driver. This driver would basically reside between the HID infrastructure or I8042prt driver and the Keyboard class driver. It can then modify the data before it arrives at the class driver and replace/remove/add key events before they arrive there. In the end you would have to use a special layout (for the additional unicode characters) as well as the driver, which can be installed for an individual keyboard via the device manager. This solution should then work for all applications.</p> <p>The problem here is the driver signature. As a kernel-mode driver it has to be signed in order to load it without ugly hacks in 64 Bit Vista/Win7. And its not cheap to sign a driver, so you're basically out of luck with that approach. I thought that one could avoid that by writing a user-mode driver (which isn't required to be signed), but the problem is, that the filter must be installed below the Keyboard class driver. Sadly it seems, that a user-mode filter driver can't have a kernel-mode driver above it. So this is not an option.</p> <p>So I think you're basically stuck with AutoHotkey. Unless you are willing and able to write a kernel-mode driver and live with the signing problem.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload