Replace PCB of generic keyboard including different key layout?

Status
Not open for further replies.

Nazo

Member
So I got curious to see if I could find a really cheap keyboard with the Dvorak layout -- something I could easily carry around in my car or whatever and use when diagnosing and repairing others' computers without having to change their keyboard layout in software. Not only is this inconvenient in general (especially since I must remember to change it back or problems ensue) but there are some things where it can be a real pain to try to change the layout such as special boot tools (partition managers just for instance.) Keyboards like the TypeMatrix (which I love at home) are just too expensive for such a purpose. In my searching around, I've run across a number of projects to build new keyboards from scratch (ErgoDox in particular really impressed me) as well as a few that take one very specific model of an old keyboard or part of a PC (such as the Apple IIc/e hardware.) Building from scratch is too expensive and kind of defeats the purpose (well, I guess if I could afford it I could just keep the TypeMatrix as the portable one, but if I could afford that I would have gotten another TypeMatrix already instead of searching all of this.) Those specific model ones obviously don't apply to just taking some generic keyboard and using it though either. Unfortunately, I can't use the build from scratch ideas because they use specific resistors or etc for their design which obviously won't match up even if it is resistance based (honestly I'm not 100% sure exactly what method these with the sheets use? I'm inclined to say that it is resistance based, but not 100% sure.) Still, obviously this is 100% within the realm of the Teensy's capabilities.

Actually, I saw one of those flexible keyboards that can be rolled up on clearance for dirt cheap locally ($4.98, so even if I hate it or destroy it in the process I'm not going to be upset) and cut out the PCB just to see if it's at all possible. The design is a very simple one and, in fact, it turns out that they made the sheets connect in via a slide in type connector, so it wouldn't even require desoldering or anything. I actually don't think I could imagine anything easier to do this with assuming I can actually do it. I've attached an image of the keyboard with the PCB exposed. I'll have to add a glue or something to protect the sheets later, but I'm not terribly worried about keeping it spill resistant or anything.

There is another problem though. I don't really know any programming at all. I was hoping I could just upload code from an existing project, but, like I said, so far all I've seen use either very specific models or build one from scratch and thus already know exactly what to expect from the hardware. Is there anything generic out there that can be very easily adapted to work with a more generic keyboard? I also have no clue how I would actually connect it to the Teensy (I'm thinking Teensy 2.0 makes the most sense. It's cheap, already being used for these sorts of projects, and it's nice and small too.) I'm no stranger to soldering, but not electronics savvy enough to have done much with these sorts of direct interface devices. (Mostly I've just put together basic things like CMoys where everything was basically already provided and I've modified the living daylights out of various things such as connecting an optical DAC to CMoy and powering both via lithium ion batteries for instance.)
 

Attachments

  • InsideFlexibleKeyboard.jpg
    InsideFlexibleKeyboard.jpg
    72.1 KB · Views: 1,184
Last edited:
Most keyboards use a matrix layout where each key corresponds to a column+row location. At the top level to scan for keys pressed, you test whether a particular column and row combination have been shorted together (key is pressed if they're shorted). To scan the whole keyboard, you'd step through each column and test each row's connection through that column. It's actually a lot simpler than additive resistances/etc, and thus the actual process of reading the matrix is pretty easy to replace.

Problems reading the matrix can occur when handling more than one key pressed at a time on the matrix. Depending on how the matrix itself has been wired, certain key combinations may not be able to be uniquely identified (a process termed ghosting, because fake/ghost keypresses can be accidentally reported) - Microsoft's anti-ghosting explained page has a lot of detail about how the matrices work, and what the problems you can run into with them. Really "good" keyboards have diodes on each key of the matrix so that holding pairs of keys don't cause other keys to be accidentally shown as pressed when they are not.

If you're replacing the entire controller on the keyboard with a teensy, you'd look at connecting the column/row lines from the keyboard matrix to pins on the teensy and scanning the column/row pairs in the matrix to determine which locations were currently shorted together. You'd then map those row/column pairs to a particular keycode for each shorted location. Have a look at the teensyduino Keypad library, particularly the "File > Examples > Keypad > MultiKey" example - this library actually handles the scanning of rows/columns, and with an appropriate "keys[ROWS][COLS]" matrix that maps the keylocations in your matrix to your desired keycode values it will probably do pretty much everything you need to scan the matrix and convert the pressed keys to usb keycodes that you can then send to the PC. You'd send the list of the pressed key's keycodes to the PC using the Keyboard.set_key1(keycode1) ... Keyboard.set_key6(keycode6) + Keyboard.send_now() functions (note: there's a limit of 6 normal keys + 8 modifier keys pressed at any one time - that's built in to the default USB keyboard bios-compatible code, but most keyboards have trouble distinguishing more than 2 normal keys at a time for some key combinations anyway). In the above, "keycode" would be something like "KEY_A" from the list here: http://www.pjrc.com/teensy/td_keyboard.html. When the list of keys on the matrix changes, you'd resend with the new list. If a key wasn't pressed (or there were less than 6 keys pressed), for the "extra" presses you'd set the keycode to 0 (i.e. Keyboard.set_key6(0), not KEY_0).

You'll need to test which keys actually map to which column/row locations because the columns don't always match what you see looking at the keycaps (they may try to make a particular key combination work better by shifting the ghosting issues to a different part of the keyboard). But once you've done that, it should be pretty easy to create your own lookup table to translate the key location to the keycode you want to that location to send.
 
Instead of reinventing the keyboard, interposing a teensy between a keyboard and the computer as a PS2 Dvorak to USB keyboard translator might be easier, particularly if you get a keyboard with keycaps you can pop swap around to Dvorak.

You are going to have to do a look up table in both approaches, but with the box-in-the-middle approach you can spend most of your time on the software part, starting with the working code discussed here:

http://forum.pjrc.com/threads/24933...board-mouse-filter?highlight=ps2+usb+keyboard

And...you might accidentally end up with a product or something.
 
If you're interested in learning to program, this is a great starter project. It's not the easiest because you'll need to deal with the hardware connection to the PS2 and the general notion of reacting to events external to the microprocessor, but the Teensies handle the USB part and the logic is straight forward:

when key received is 'a', then transmit 'a',
when key received is 's', then transmit 'o', etc.

(This is just an informal description of the logic, not actual code.)

Good luck with this and let us know how it goes!
 
It might be a good starter project, but certainly I don't want to take all the time and effort to learn it just to modify a cheap keyboard. So far I haven't been able to think of a good project outside of this scope that would actually be helpful for me (I typically want something that's less small scale tasks and more an actual system like a Raspberry Pi for instance.) That said, besides learning the process itself and all, this is partially a look into feasibility in whether or not I really even could do more serious things with devices like these.

Anyway, I'd rather replace the PCB if I could because adding layers of extra complication make it bulkier and with more that could go wrong or slow it down or etc. But also, I liked the idea of being able to connect it to embedded devices with USB host such as my Android phone and tablet and in such cases power usage must be minimalized for fairly obvious reasons. Having two separate boards drawing power could add up. I know neither is exactly power hungry, but the point is when using such devices that you should minimize so they last as long as possible. (Especially with that phone as it can eat batteries for breakfast when the screen is on.) It also looks like the best bet there would require the Teensy 3.0 and I'm trying to absolutely minimize costs since this is most likely something that will just sit in my car all the time.

Anyway, I figured I'd probably have to scan for keycodes, but I surely can't just wire the matrix straight into the Teensy randomly, right? Anyway, I assumed getting the keycodes probably wouldn't be too hard, but nothing goes into serious detail on the actual process. Even once I have them though, then what? I saw that thing about the keycodes, but nothing about any obvious signs of ready-made stuff to actually act as a keyboard. I have no clue how to modify those programs that were made for specific keyboard models to work with a different one (especially since it works differently from their mechanical switch sets.)
 
Certainly you'd have to get power and ground correct for your keyboard to generate meaningful signals, but you might be able to wire the signal lines to inputs on the Teensy arbitrarily and then figure out by experimentation which input pattern on the Teensy corresponds to which key on the keyboard. Push the A key. Notice which Teensy inputs are HIGH and which are LOW using the serial monitor in the Arduino IDE. Push the B key. Etc.

However none of this will help you if you don't want to do any programming at all. You'd at least need to be able to understand code like this:

Code:
usb_init();
Serial.print("Pin 1 = ");
Serial.println(digitalRead(pin1));
// etc.
if (digitalRead(pin1) && digital(pin2) && !digitalPin(pin3)) {;
    usb_keyboard_press(KEY_A, KEY_SHIFT);
}
// etc.

I'm sure you've looked at http://www.pjrc.com/teensy/usb_keyboard.html.

Maybe if I understood your background better I might be able to suggest something more helpful.

Best regards,
John
 
Ok. Your options are:
1. Wire the keyboard matrix directly to your teensy, replacing the entire controller for that keyboard (which is what I thought you were asking about initially, so what my first response was about). Yes, this was about directly connecting the matrix to the teensy (though there may need to be some current limiting protection added). The teensy would then be a permanent part of that keyboard, and you'd need to take your modified keyboard with you.
2. Make an adaptor box that can plug an unmodified keyboard into it, and then plug your adaptor into the computer's usb ports
2.a) As a PS/2 keyboard -> USB converter.
2.b) As a USB keyboard -> USB converter.

For a PS/2->USB converter, there are prewritten converter codes available - I don't think any of the ones I've seen include the dvorak layout by default, so you'd need to at least create a dvorak layout to add into them. These can be (and frequently have been) written to be used on teensy 2/2++s - one sample set of code is on github at https://github.com/tmk/tmk_keyboard, and you'd be looking at the PS/2-usb converter section with the pjrc (teensy) protocol. Reading the instructions, I believe all you'd need to do to add the dvorak layout to that code is to copy the file "keymap_plain.c" in the converter section to a new file named something like "keymap_dvorak.c", and edit the "KEYMAP(" values matching the changed keys for qwerty->dvorak in that file so that it matched a dvorak layout (the KEYMAP has been spaced to match the ascii art above for where the keys on a keyboard are normally located, so you should be able to compare the keys directly and just edit the values to apply to that key location). Then when compiling, you'd need to set "KEYMAP=dvorak" during compiling for your new keymap file to be used instead of the standard one (the KEYMAP=<name> maps to using the "keymap_<name>.c" file for keys). There's some documentation in the ps2_usb section about doing exactly that: https://github.com/tmk/tmk_keyboard/tree/master/converter/ps2_usb. That option should be minimal coding required - all you'd need to do is create the keymap via copyfile-edit and then compile with the right options. But...not everyone still has a PS/2 keyboard available, so you may need to carry one around with you. Technically, you may be able to use the PS/2 converter version *with* a USB keyboard if you got one of the small USB->PS/2 converter dongles (like these) that are often supplied with usb keyboards (or at least, they used to be), because many USB keyboards are capable of talking PS/2 as well. This would allow you to use the teensy 2/2++ prewritten converter code instead of having to read/understand the USB Reports through a USB Host. That's not guaranteed though.

For USB->USB, it's a bit more complex. You'd need a USB Host adaptor that you could plug the keyboard into and to wire that adaptor up to the teensy. You'd then need to have the teensy read the USB report to retrieve the list of keys currently pressed (i.e. it'd give you a list of "Ctrl + c"), and when copying those to Keyboard.set_keyx() you'd translate the normal querty keypress to the dvorak one you want (i.e. you'd setup Keyboard to report "Ctrl + j"). That'd be simply a lookup table conversion for querty->dvorak, so you set the output from the teensy to the converted value. There's at least one library available to read/understand the USB Reports that claims compatibility with the Teensy 3/3.1, but you'd still have to add that lookup table conversion to go from what it reported to what you wanted the keypresses to be modified to. Try this thread as a start point for libraries to look at if you're interested in going with this option.
 
So something easy to carry that doesn't require programming skills, so basically this:
http://www.keyghost.com/qido/
Rofl! For that price why wouldn't I just get another keyboard? Besides, it has been established that the Teensy already has an existing code that could do this task (for quite a lot less... Actually, I'm not sure one of the even cheaper models couldn't do it for that matter. I'm not sure what goes into the host adapter, but I may even be able to just build my own? I forget what it said was required as far as Teensy models go, but I think the $16 2.0 was one of the ones they said could do it.) Anyway, for the reason I mentioned when someone suggested an external dongle before, I still don't want to do that regardless, but if I do it will definitely be with something cheaper like the Teensy instead of that horribly overpriced thing.

However none of this will help you if you don't want to do any programming at all.
Ok, to be more accurate, I know just a little bit of programming, but have forgotten almost everything. While I don't mind messing with code a little bit in this process, overall I can't do much and don't want to spend a lot of time and effort learning anything extensive just to make a custom keyboard. That said, I've worked with several BASICs, Java, and C++ in the past, just it has been so long I've forgotten nearly everything.

I saw it. As far as I can tell it's also like those custom keyboard designs where, rather than taking a "standard" keyboard and modifying it you're building one with already known values. I wouldn't know how to modify it to work with this.

1. Wire the keyboard matrix directly to your teensy, replacing the entire controller for that keyboard (which is what I thought you were asking about initially, so what my first response was about). Yes, this was about directly connecting the matrix to the teensy (though there may need to be some current limiting protection added). The teensy would then be a permanent part of that keyboard, and you'd need to take your modified keyboard with you.
This is my intent, yes. Remember, this modified setup will work even with embedded devices if it works correctly. If it works out I'd have the option to be able to modify others this way in the future as well even.

2. Make an adaptor box that can plug an unmodified keyboard into it, and then plug your adaptor into the computer's usb ports
2.a) As a PS/2 keyboard -> USB converter.
2.b) As a USB keyboard -> USB converter.
If all else fails, yes this is an option and I might give it a shot. Like I said earlier, it's not really ideal, but it would at least have the advantage of working with any keyboard. (On the other hand, I like the idea of being able to customize keyboards and maybe even someday would like to try a project like that ErgoDox as it would be just amazing.) I don't really want to deal with PS/2 though. If I have to go that way I'm sticking with USB...
 
Last edited:
I saw it. As far as I can tell it's also like those custom keyboard designs where, rather than taking a "standard" keyboard and modifying it you're building one with already known values. I wouldn't know how to modify it to work with this.

Ah - no, this is how you actually send your remapped-to-dvorak keypresses to the pc - you'd use this for ALL of the options, regardless of whether you were doing interpretation of another keyboard or were reading the key matrix yourself or had your own set of buttons that were pretending to be a keyboard. It sends what a pc would recognise as a normal usb keyboard's set of active keys back out through the usb port, which will mean that the keyboard would then work with any device that can use a normal usb keyboard.

This is my intent, yes. Remember, this modified setup will work even with embedded devices if it works correctly. If it works out I'd have the option to be able to modify others this way in the future as well even.

It breaks down into a few stages.
1. Scan the key matrix to determine which keys are pressed. [e.g. with the Keypad library - you need to get the list of "pressed" locations].
2. Apply a USB keycode for each key pressed. [e.g. this is your keymap]
3. Send that list of keycodes for the pressed keys to the PC using the Keyboard library. [use the USB Keyboard stuff]. Send updates no more frequently than once per millisecond.

That's all - it's surprisingly less complex than you'd expect. Your main issue will be handling key bounce - but the Keypad library for scanning a matrix of keys should handle that for you too, provided you've set the bounce time properly (prevents sending "pressed, not pressed, pressed, not pressed, pressed" for what should be a single keypress).
 
Last edited:
It breaks down into a few stages.
1. Scan the key matrix to determine which keys are pressed. [e.g. with the Keypad library - you need to get the list of "pressed" locations].
2. Apply a USB keycode for each key pressed. [e.g. this is your keymap]
3. Send that list of keycodes for the pressed keys to the PC using the Keyboard library. [use the USB Keyboard stuff]. Send updates no more frequently than once per millisecond.
Well, I assumed that this would be the basis, but the part I'm having the most trouble with is how to actually go about doing that. It's not like there's a simple program I can load to scan keycodes followed by another I can put on it and just edit a key code list, right? I'm still not sure how to actually hook the matrix up to the Teensy for that matter since it was previously stated that it might require some form of current limiting? If I could just wire it on there without having to worry about which pin is which, that would be great, but I have no idea how to do current limiting without something much more complex.
 
Well, I assumed that this would be the basis, but the part I'm having the most trouble with is how to actually go about doing that. It's not like there's a simple program I can load to scan keycodes followed by another I can put on it and just edit a key code list, right? I'm still not sure how to actually hook the matrix up to the Teensy for that matter since it was previously stated that it might require some form of current limiting? If I could just wire it on there without having to worry about which pin is which, that would be great, but I have no idea how to do current limiting without something much more complex.

For current limiting, it'd be using a resistor between the matrix wire and the teensy pin. That said, I've looked further at the Keypad library at the arduino site, and they say:
You won't need external resistors or diodes because the library uses the internal pullup resistors and additionally ensures that all unused column pins are high-impedance.
Based on that, you shouldn't need to add anything - just connect the matrix directly to whatever pins you want on your teensy.

For the code - I've attached an example that combines the Keypad library with USB Keyboard to report the keys to the PC - pretty much doing everything you need. To make it work with your keyboard, you'd need to modify the values for const byte ROWS, const byte COLS, the char keys[ROWS][COLS], byte rowPins[ROWS], and byte colPins[COLS]. The pins that you select go in the rowPins or colPins arrays (one value for each row/column - you'll have more than 3/4, I'd expect something like 5/13). The keys[ROWS][COLS] is your keymap - you need to manually test which key on your keyboard is detected by each row/column pin, and put the USB keycode value you want applied for that key in the corresponding place in the keys array.

Not having a keyboard I want to sacrifice to test this, I can't be 100% sure - but you shouldn't need to change anything inside the loop at all. You may need to adjust the bounce time in the setup() bit if you're getting doubled keypresses - it's set appropriate for a mechanical cherry-keyswitch keyboard, but it may need to be increased for other keyboards.
 

Attachments

  • KeyboardMatrixExample.ino
    4.1 KB · Views: 239
Ok, thanks for the help. I'll be trying to order a Teensy 2.0 as soon as I can and hopefully will be able to figure all this out then. If not, I guess at the very worst it will be interesting to try and I'm sure I'll be able to find a use for it besides this anyway.
 
Status
Not open for further replies.
Back
Top