MT6253 KEYBOARDS REVERSE ENGINEERING ==================================== This is one of the most difficult hacks to perform, but the reward can be high as the look and lay-out of the keyboards can be completely customised, and made actually usable. The keyboards consist of two separate parts: a background image which is stored as a bitmap, and a table of coordinates, sizes, and key values. The bitmap is stored in a proprietary binary format. On older phones this is a simple 4-bit raw bitmap whose header starts with the hex codes 28 01, on more recent phones it is run-length encoded (RLE) and starts with 34 01. It is entirely possible that some firmwares use something else. What follows are actual notes I made while reverse-engineering these two data structures for the MQ668 (based on MT6253). It may be a bit messy, but all the information is in here. To start out, you need to find the positions inside the binary firmware dump you downloaded with FlashTool, where the keyboard data is stored. This on its own is already extremely difficult. Your best bet is to look for anything that looks like keyboards, e.g. look for hex codes 00 71 00 77 00 65 00 72 00 74 00 79 (qwerty with zeros in between). For the bitmaps, look for regular-looking structures that start out with the hex codes 28 01 or 34 01, at an offset that is a multiple of 4 bytes. If you're lucky, they are in the neighbourhood of the keyboard tables. It is actually possible to relocate data, as you will read below in these notes. This should only be attempted if you know what you're doing, but that goes for this entire hack anyhow. KEYBOARD KEY LAYOUTS ==================== ===20130423=== All indices in this document are aligned with the first apparent chars in the table: 01 00 02 00 07 00 03 The keyboards are obviously grouped in two halves, as was already evident from the split between "qwertyu" and "iop". The left half is: Q W E R T Y U A S D F G H J Z X C V B N M The right half is: I O P Col K L . Bks Sh Space Sym In practice the keyboard is defined as a regular grid (left half) and extra keys. The catch is that the regular grid can only contain regular keys with characters. Special keys must be in the extra section. 0x00 and 0x02 are the horizontal, respectively vertical offset of the grid. 0x04 and 0x06 are the number of columns, respectively rows, in the grid: 7, 3 for ABC (it seems illogical that they stuck with 7, but I believe it has to do with the fact that the shift key is at column 8 and cannot be inside the grid). 0x08 and 0x0A are the width and height of the grid. Changing this has no effect on positioning, only on the active area of the entire keyboard. 0x0C and 0x0E are the width and height of ALL keys in the grid. The actual width of the clickable area is this value minus 2. 0x10 and 0x12 are the horizontal and vertical spacing between all keys in the grid. Due to the 1-pixel unclickable border around each key, add 2 pixels for the actual gap. 0x14 and next (to 0x6B) define the rectangles of the extra keys (iop, collapse, kl., backspace, shift, space, symbols). Each key is a group of 4 words (8 bytes): horizontal and vertical position (relative to the left,top of the entire keyboard area) and width,height. HERE IS THE ACTUAL ENTRY POINT FOR THE KEYBOARD DATA. This is the location pointed at in the memory tables. When taking the previous data as a reference, it is at an offset of 0x14+8*[num_extra_keys]. 0x6C is the width of the entire keyboard. Changing this to something smaller will cause the keyboard to be centered with gaps to the left and right. 0x6E is the height of the entire keyboard. Changing this has the desired effect on the entire rest of the interface, this is a very important parameter if I want to enlarge the keyboard! 0x70 (value 0x01) is probably the number of grid definitions. 0x72 (0x0B) is the number of extra keys. 0x74 (dword) is the address (prepended by 08) of index 0x00 (grid size). 0x78 (dword) is the address (prepended by 08) of index 0x14 (extra keys sizes). 0x7C-7D is unknown. 7D is always 38. 0x82 and 0x84 are a repetition of 0x70 and 0x72 (#grids, extra keys). At 0x86 starts the definition of the grid keys. The next row starts at 0xA6 etc, therefore the maximum number of columns is 16. At 0x126 starts the definitions of the other keys (only the regular ones, the specials are all 0x00). 0x162: this is a table (2 bytes per key) that defines the symbols that are _drawn_ on the special keys. This has no effect on what the keys actually do. Values: 00 00: normal key C3 38: collapse C4 38: expand C7 38: backspace C8 38: shift C9 38: space CA 38: symbols CC 38: return CD 38: brackets () At 0x1A0 is a table that defines the type of each key in the non-grid section, 4 bytes per key. There are entries nn 00 01 00 for each key, with nn = 02 for regular keys 03 for collapse 04 for expand 05 for shift 06 for space 07 for backspace 08 for symbols 09 for brackets () 0A for return Remember, this only defines the _function_ of those keys. The symbol that is displayed is set in the table at 0x162. At 0x21A begins the uppercase keyboard, same structure as starting from 0x82. At 0x3B2 begins the Chinese symbols keyboard. All right, I should know enough to build my very own keyboard! PROPOSAL: Q W E R T Y U I O A S D F G H J K L Z X C V B N M P . Sh, Spa Bks CoSym This would make each key 26 pixels wide instead of 20! Backspace is actually optional, because there is always a "Clear" button with the same function. I could remove it from all keyboards, although there is plenty of space and it may actually be handy on the ABC keyboard. This is good news for the PIN keyboard which would otherwise be messy to enlarge: I can just drop the backspace key. I could also go for 10 columns, 24 pixels wide, and some extra keys: Q W E R T Y U I O P A S D F G H J K L - Z X C V B N M , . ? Shi Spa Bks Col Sym <- these keys will be 48-hGap wide I like this a lot, so I'll go for this. This could be achieved by shoving all alphabet keys into the grid, and using the extra keys for the fourth row. Parameters for new ABC 4-row keyboard: 00,02 = 00 01 grid offset -> I might consider shaving 1 horizontal pixel off each key and leave a 5px gap left & right to avoid the unreliable touch screen response at the edges, but it seems OK like this. 04,06 = 0A 03 grid columns, rows 08,0A = F0 48 grid width, height 0C,0E = 18 18 keyWidth, height 10,12 = 00 00 gapH, gapV 14+ = 00 49 30 18 30 49 30 18 60 49 30 18 90 49 30 18 C0 49 30 18, or in paste-able form: 00 00 49 00 30 00 18 00 30 00 49 00 30 00 18 00 60 00 49 00 30 00 18 00 90 00 49 00 30 00 18 00 C0 00 49 00 30 00 18 00 6C,6E = F0 62 width, height 70,72 and 82,84 = 01 05 grids, extras -> This works great! Look at the bottom of this file for more examples of customised layouts, and updates. The biggest challenge will be to adapt the background, I will need to figure out how the RLE works, and create something that fits in the same memory despite having more pixels. I believe there is some invisible variation in the current designs that may perhaps give the needed margin for expansion when optimised. 20130426: IDEA: if anything else fails, move the biggest image to the end of the firmware, and update the address in the tables. I believe there is a usable gap there, before the FAT stuff begins. Then there is leeway to resize the other images (their addresses must also be adjusted). Let's try this! Putting the original collapsed keyboard bitmap at 0xDEBEB0 and replacing its address 0x7DC624 with this. If this works, the phone should not explode and display the old ugly keyboard. -> This WORKS! Now the floodgates are open for bigger hacks. ===20130427=== There is no way around it, I must reverse engineer the entire RLE format. It looked baffling at first and I wasted a lot of my sweet time, until I realised that this is a true 4-bit format. RLE IMAGE FORMAT ================ The image starts with magic number 0x34 0x01 and then the usual 16-bit file size minus 8. The value in 0x04-05 is unsure. Hypothesis: it is the number of 16-bit words in the rest of the header, this value included? This only fits with the 1-row keyboard image however. Ignore unless it proves important. The width of the image is specified at 0x08 as a _12 bit_ value!!! This means the rightmost 4 bits of 0x09 are the MSBs of this value! Whoever designed this was really skimpy on bits. The height of the image is specified in the leftmost 4 bits of 0x09 and the whole of 0x0A. These are _not_ the width and height of the actual bitmap: to obtain those, subtract the following padding values. 0x0B is left padding, 0x0C top, 0x0D right, and 0x0E bottom. In the original images, H padding is 1 and V padding is 2. Color table crap is somewhere between 0x0F and 0x31. Without any doubt, it is also sub-byte ordered but I have not yet cracked it. It has caused me enough headaches, so I'l leave it alone. What this means is that there is no way yet to choose the colours used in the background, you'll have to do with what is available in the original. The actual image data starts at 0x32. It consists of a sequence of data blocks. Each block starts with an 8-bit value Nn: If Nn < 0x80, the block is RLE encoded and NN+1 pixels will be drawn in the color value given in the next 4 bits. If Nn >= 0x80, the block is a series of raw pixel values: (Nn-128)+1 4-bit color values will follow. The catch is that the 4-bit values are grouped in an awkward sequence, which was why it took me many excruciating hours to figure out this scheme despite its simplicity. If Nn is within a regular 8-bit alignment, it can be read as-is. If Nn is spread across two bytes, it is as follows: xn yN. Consecutive raw 4-bit groups are also in reverse order within one byte: xy means "pixel with color y, pixel with color x". In other words, if the image starts with a run of 17 pixels of color x and then 3 raw pixels a,b,c, the bitstream looks like this: 10 2x a8 cb Or, 17 pixels of color x alternating with 2 pixels of color y: 10 1x y0 10 1x y0 ... Now all I need to do is write a decoder and encoder. -> I made a simple encoder/decoder as a Perl script mtk_rle_coder.pl. It is very primitive, only handles the actual bitmap data, and can only work on hex codes, not binary data. Some copy-pasting between a hex editor will be necessary. But it works. Look inside the file for instructions. Image created, uploaded. The result is a massive improvement over the original keyboard. ===20130428=== I will also fix the single-row keyboard (collapsed & PIN entry). To keep it single-row, I will need to drop the wide key, which is backspace in the PIN entry, and "expand" in the collapsed keyboard. Obviously, I want to keep that function, so I will need to drop another key in that case. Since I cannot even remember ever typing ';' on my phone, I will drop this and keep Backspace. 1-row keyboard definition at 0x5A0C48 The current sequence of keys is: ? , : . ; () RET Spc Bks Ext Exp Turn this into: ? , : . () RET Spc Bks Ext Exp For PIN, simply drop the backspace, move '4' into extra keys. There is one other keyboard defined that has a '.' instead of backspace, I have never seen it. Might be intended for IP addresses? I'll just ignore it. If I ever see "IsThisUsed" in the interface, it is used after all. Parameters for 1-row keyboard: 00,02 = 00 01 grid offset 04,06 = 04 01 grid columns, rows 08,0A = 60 18 grid width, height 0C,0E = 18 18 keyWidth, height 10,12 = 00 00 gapH, gapV 14+ = 60 01 18 18 78 01 18 18 90 01 18 18 A8 01 18 18 C0 01 18 18 D8 01 18 18, or in paste-able form: 60 00 01 00 18 00 18 00 78 00 01 00 18 00 18 00 90 00 01 00 18 00 18 00 A8 00 01 00 18 00 18 00 C0 00 01 00 18 00 18 00 D8 00 01 00 18 00 18 00 44,46 = F0 1A width, height 48,4A and 5A,5C = 01 06 grids, extras Same for the 2-row numbers keyboard: at 0x5A0730 I could opt to make this 3-row and add some keys, but I prefer to keep it 2-row, dropping Backspace and shrinking the other keys to keep everything. Current keyboard is: 0 1 2 3 4 5 6 7 8 9 Col * / + - . % $ = Spc Bks 2-row design: 0 1 2 3 4 5 6 7 8 9 * / + - . % $ = Sp Co Phone number entry also uses this keyboard: 0 1 2 3 4 5 6 7 8 9 Col * # + - p w ( ) Spc Bks But - ( ) Col Spc are all disabled. I cannot think of a situation when they would be enabled. Therefore I can simply drop any of these. New design: 0 1 2 3 4 5 6 7 8 9 * # + - p w ( ) Sp Bks There is another similar keyboard with a '?', never seen it. Parameters for 2-row keyboard: 00,02 = 00 01 grid offset 04,06 = 08 02 grid columns, rows 08,0A = C0 30 grid width, height 0C,0E = 18 18 keyWidth, height 10,12 = 00 00 gapH, gapV 14+ = C0 01 18 18 D8 01 18 18 C0 19 18 18 D8 19 18 18, or in paste-able form: C0 00 01 00 18 00 18 00 D8 00 01 00 18 00 18 00 C0 00 19 00 18 00 18 00 D8 00 19 00 18 00 18 00 3C,3E = F0 32 width, height 40,42 and 52,54 = 01 04 grids, extras For the symbols, I would keep the current design. I would not make it 5 rows and I do not want to drop keys. I can of course make the keys higher. Or, I could shrink the rightmost keys, but that won't gain much. Keep this for when I'm really bored. 20130501: Ok, I am sufficiently bored. -> Symbols: make regular keys 21px wide, shrink rightmost keys to 28px. Set height to 24px. Keep the original 2x2 pix horizontal margin because of the smaller keys. Because I'm not wasting a pixel in the bitmap this time, it will only be 236px wide and 94px high. No fiddling with the keys here! Parameters for 4-row symbols keyboard: 00,02 = 01 01 grid offset 04,06 = 08 04 grid columns, rows 08,0A = A8 60 grid width, height 0C,0E = 15 18 keyWidth, height 10,12 = 00 00 gapH, gapV 14+ = A9 01 15 18 BE 01 15 18 D3 01 1C 18 A9 19 15 18 BE 19 15 18 D3 19 1C 18 A9 31 15 18 BE 31 15 18 D3 31 1C 18 A9 49 23 18 CC 49 23 18, or in paste-able form: A9 00 01 00 15 00 18 00 BE 00 01 00 15 00 18 00 D3 00 01 00 1C 00 18 00 A9 00 19 00 15 00 18 00 BE 00 19 00 15 00 18 00 D3 00 19 00 1C 00 18 00 A9 00 31 00 15 00 18 00 BE 00 31 00 15 00 18 00 D3 00 31 00 1C 00 18 00 A9 00 49 00 23 00 18 00 CC 00 49 00 23 00 18 00 6C,6E = F0 62 width, height 70,72 and 82,84 = 01 0B grids, extras ===20130611=== HACK VERSION 2: * Make alphabet rows in ABC keyboard 2 pixels higher each * Make 1-row keyboard 4 pixels higher * Make alphabet rows in 2-row keyboard 2 pixels higher each ABC new 4-row keyboard v2: 00,02 = 00 01 grid offset 04,06 = 0A 03 grid columns, rows 08,0A = F0 4E grid width, height 0C,0E = 18 1A keyWidth, height 10,12 = 00 00 gapH, gapV 14+ = 00 4F 30 18 30 4F 30 18 60 4F 30 18 90 4F 30 18 C0 4F 30 18, or in paste-able form: 00 00 4F 00 30 00 18 00 30 00 4F 00 30 00 18 00 60 00 4F 00 30 00 18 00 90 00 4F 00 30 00 18 00 C0 00 4F 00 30 00 18 00 6C,6E = F0 68 width, height 70,72 and 82,84 = 01 05 grids, extras New layout for 4th row: Shi Col Spa Bks Sym Parameters for 1-row keyboard v2: 00,02 = 00 01 grid offset 04,06 = 04 01 grid columns, rows 08,0A = 60 1C grid width, height 0C,0E = 18 1C keyWidth, height 10,12 = 00 00 gapH, gapV 14+ = 60 01 18 1C 78 01 18 1C 90 01 18 1C A8 01 18 1C C0 01 18 1C D8 01 18 1C, or in paste-able form: 60 00 01 00 18 00 1C 00 78 00 01 00 18 00 1C 00 90 00 01 00 18 00 1C 00 A8 00 01 00 18 00 1C 00 C0 00 01 00 18 00 1C 00 D8 00 01 00 18 00 1C 00 44,46 = F0 1E width, height 48,4A and 5A,5C = 01 06 grids, extras Parameters for 2-row keyboard v2: 00,02 = 00 01 grid offset 04,06 = 08 02 grid columns, rows 08,0A = C0 34 grid width, height 0C,0E = 18 1A keyWidth, height 10,12 = 00 00 gapH, gapV 14+ = C0 01 18 1A D8 01 18 1A C0 1B 18 1A D8 1B 18 1A, or in paste-able form: C0 00 01 00 18 00 1A 00 D8 00 01 00 18 00 1A 00 C0 00 1B 00 18 00 1A 00 D8 00 1B 00 18 00 1A 00 3C,3E = F0 36 width, height 40,42 and 52,54 = 01 04 grids, extras ===20130825=== Also add 2 vertical pixels to all rows of symbols keyboard, for marginally better comfort. New parameters for 4-row symbols keyboard: 00,02 = 01 01 grid offset 04,06 = 08 04 grid columns, rows 08,0A = A8 68 grid width, height 0C,0E = 15 1A keyWidth, height 10,12 = 00 00 gapH, gapV 14+ = A9 01 15 1A BE 01 15 1A D3 01 1C 1A A9 1B 15 1A BE 1B 15 1A D3 1B 1C 1A A9 35 15 1A BE 35 15 1A D3 35 1C 1A A9 4F 23 1A CC 4F 23 1A, or in paste-able form: A9 00 01 00 15 00 1A 00 BE 00 01 00 15 00 1A 00 D3 00 01 00 1C 00 1A 00 A9 00 1B 00 15 00 1A 00 BE 00 1B 00 15 00 1A 00 D3 00 1B 00 1C 00 1A 00 A9 00 35 00 15 00 1A 00 BE 00 35 00 15 00 1A 00 D3 00 35 00 1C 00 1A 00 A9 00 4F 00 23 00 1A 00 CC 00 4F 00 23 00 1A 00 6C,6E = F0 6A width, height 70,72 and 82,84 = 01 0B grids, extras