[How To] WM Dialer moding (tapres.dll.0xxx.mui) - Upgrading, Modifying and Unlocking
Tuto: Modification of a Dialer
Hello everyone,
This Tuto allowing to intervene directly on the resources of your dialer. Ie DLL.
Advantages: No additional resource, only those origins. So, not one gram of fat added. A Dialer 0%
The items made available or examples are from the rom of my LG KS20 QVGA (Rom KisS20 of Spocky), you've got to bring such changes to your devices.
1) Resources (DLL)
First you must know that your dialer is mainly used two resources:
The first is by "default" of WM. It tapres.dll.0xxx.mui nome. XXX is the language ID (FR = 040C -> tapres.dll.040C.mui).
The second is usually the manufacturer. It is here to provide additional functionality (type video calls), and / or skin.
The name of this DLL can be found here ->
[HKEY_LOCAL_MACHINE\Security\Phone\Skin] [HKEY_LOCAL_MACHINE \ Security \ Phone \ Skin]
"Enabled" = dword: 00000000
"ext" = "\ windows \ Your DLL.dll"
To activate one or the other DLLs just go "Enabled" = dword: 0000000 0 (DLL by default) to 1 (DLL constructor).
Every two are in the Windows directory on your PPC.
2) Images
Your default dialer is composed of the following images:
dlrback_land.png--------->Background dialer
dlrback_port.png
dlrbtndef_dwn_land.gif--> buttons for the functions call, speed dial, etc.
dlrbtndef_dwn_port.gif
dlrbtndef_up_land.gif
dlrbtndef_up_port.gif
dlrbtnend_up_land.gif----> button "Done"
dlrbtnend_up_port.gif
dlrbtntalk_up_land.gif----> button "Call"
dlrbtntalk_up_port.gif
dlrbtn_dwn_land.gif------> other keys (numbers / letters)
dlrbtn_dwn_port.gif
dlrbtn_up_land.gif
dlrbtn_up_port.gif
"Port" for the portrait, "Land" for landscape mode. "Up" for keys not pressed, "dwn" for keys pressed.
Note: The images used for the buttons' functions are identical to the keys "call status".
3) Tools
A resource editor (Restorator, Resource Tuner etc)
Unsigned MSigner and to sign your DLL amended
Drawing software (Photoshop and others)
The notepad ...
4) Modification of resources (DLL)
With the help of your editor and open your DLL go to the directory Dialog.
Resources 22500 (dialer, landscape mode), 22507 (call status landscape mode), 22509 (dialer, portrait mode) and 22510 (call status portrait) define your dialer.
Change the size and location of images of different elements. The keyboard, calling area, the SmartDial ....
Example using 0 to 9
CONTROL "", 23041, "MS_PHONE_BUTTON", 1, 122, 52, 36 ----> Size
CONTROL "", 23042, "MS_PHONE_BUTTON", 54, 122, 52, 36 ----> Implantation
CONTROL "", 23041, "MS_PHONE_BUTTON", 1 , 122 , 52 , 36 CONTROL "", 23041, "MS_PHONE_BUTTON", 1, 122, 52, 36
The first 2 values Y = X and X is the location left / right and Y up / down
Les 2 autres = taille de l'image, longueur / largeur The other 2 = image size, length / width
Save your new DLL, sign here and test.
5) Edit pictures
Nothing special ...
In my previous example the size of my images is increased to 52x36. So I created new images to this size. They replace the original (dlrbtndef_dwn_port.gif, dlrbtndef_up_land.gif, dlrbtndef_up_port.gif ...).
Open a simple image viewer, Edit -> resize -> Save 52x36
Go to the experts Edit -> change color -> Save.
6) Putting
I change my DLL tapres.dll.040C.mui as follows:
Dialog 22509
..... .....
CONTROL "", 23041, "MS_PHONE_BUTTON", 1, 122, 52, 36
CONTROL "", 23042, "MS_PHONE_BUTTON", 54, 122, 52, 36
CONTROL "", 23043, "MS_PHONE_BUTTON", 107, 122, 52, 36
CONTROL "", 23044, "MS_PHONE_BUTTON", 1, 159, 52, 36
CONTROL "", 23045, "MS_PHONE_BUTTON", 54, 159, 52, 36
CONTROL "", 23046, "MS_PHONE_BUTTON", 107, 159, 52, 36
CONTROL "", 23047, "MS_PHONE_BUTTON", 1, 196, 52, 36
CONTROL "", 23048, "MS_PHONE_BUTTON", 54, 196, 52, 36
CONTROL "", 23049, "MS_PHONE_BUTTON", 107, 196, 52, 36
CONTROL "", 23051, "MS_PHONE_BUTTON", 1, 233, 52, 36
CONTROL "", 23050, "MS_PHONE_BUTTON", 54, 233, 52, 36
CONTROL "", 23052, "MS_PHONE_BUTTON", 107, 233, 52, 36
CONTROL "", 23001, "MS_PHONE_BUTTON", 160, 122, 79, 36
CONTROL "", 23012, "MS_PHONE_BUTTON", 160, 159, 79, 36
CONTROL "", 23011, "MS_PHONE_BUTTON", 160, 196, 79, 36
CONTROL "", 23014, "MS_PHONE_BUTTON", 160, 233, 79, 36
..... .....
I also modified the original image and I let [HKEY_LOCAL_MACHINE \ Security \ Phone \ Skin]
"Enabled" = dword: 0000000 0 for do not call for anything else (DLL or manufacturer, or a skin external).
Here is the result
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
7) The base registry
From the registry you can almost touch any settings for your Skin, images, text, color etc..
In the example above you can see that the text is centered, the figures are white, the letters are gray. Here's how to proceed.
"Enabled" = dword: 0000000 1 ---> Skin Active
[HKEY_LOCAL_MACHINE\Security\Phone\Skin\Dialer\Landscape\dialbutton]
"MajorFlags" = dword: 00000005 -------> centered position of Figures dialer
"MinorFlags" = dword: 00000005 -------> centered position of Letters from the dialer
"MajorColor" = dword: 00ffffff -------> Color numbers (00ffffff = white)
"MinorColor" = dword: 00cccccc -------> Color Letters (00cccccc = gray)
[HKEY_LOCAL_MACHINE\Security\Phone\Skin\Dialer\Portrait\dialbutton]
"MinorFlags" = dword: 00000005
"MajorFlags" = dword: 00000005
"MajorColor" = dword: 00ffffff
"MinorColor" = dword: 00cccccc
It can also affect the style MajorRCMLStyle ...
For the "textFlags" position is defined as:
dword 0 : top left
dword 1 : top center
dword 2 : top right
dword 4 : middle left
dword 5 : middle center (default value)
dword 6 : middle right
dword 8 : bottom left
dword 9 : bottom center
dword A : bottom right
In my case I have 5, one centering vertically and horizontally (almost perfect because the numbers and letters are struggling a bit them secret ) )
"textLayoutFlags" : "textLayoutFlags":
dword 0: Numbers, then Letters
dword 1: Letters, Numbers then
dword 2: just numbers (no letters)
In my case I have 0 ...
Here are the keys to BDR that you can learn:
HKLM\Security\Phone\Skin\ =This is the main key for phone skins
DIALER = This is the main dial pad that you dial phone numbers on
LANDSCAPE and PORTRAIT = The orientation or the dialpad phone you should change the same key in both orientation to stay consistant
text = Text in the "Information Window" The one that shows last number dialed, contact info, etc.
textColor = Color of the text in the information window
dialbutton = Button that displays the numbers you dial
MajorColor = Color of the dial button digits
MinorColor = Color of the dial button text (abc, def)
MajorRCMLStyle = Size of the dial button digit, HEX values are smaller for the 1 through 20 for the largest (1a, 1b, 1c, etc.)
MinorRCMLStyle = Size of the dial button text, HEX values are smaller for the 1 through 20 for the largest (1a, 1b, 1c, etc.)
MajorFlags = Position of the number on the dial button, values are 1-13 (decimal), IE, Upperleft, bottomright, center, etc. (Hex 400 makes the text invisible)
MinorFlags = Position of the text on the dial button, values are 1-13 (decimal), IE, Upperleft, bottomright, center, etc. (Hex 400 makes the text invisible)
bmpNormal = Path to the Bitmap you see when you are not touching the keys
bmpPressed = Path to the Bitmap you see when you press a dial key
bmpFlags = Adjusts the alignment of the bitmap on the key, not commonly used
bmpTransparency = Transparency of the bitmap and ability to show through backgound image
bmpDisabled = Bitmap that displays if the button goes disabled, like "Hold" is disabled if you are not in call
erasebutton = Button that erases digits you typed (Usually the back arrow)
bmpNormal = Path to the Bitmap you see when you are not touching the keys
bmpPressed = Path to the Bitmap you see when you press a dial key
bmpFlags = Adjusts the alignment of the bitmap on the key, not commonly used
bmpTransparency = Transparency of the bitmap and ability to show through backgound image
bmpDisabled = Bitmap that displays if the button goes disabled, like "Hold" is disabled if you are not in call
VerbButton = Button (f0f0f special value will make the text invisible on the textFlags key)
textColor = Color of the "Call History" text
textRCMLStyle = Size of the "Call History" text, HEX values are smaller for the 1 through 20 for the largest (1a, 1b, 1c, etc.)
textFlags = Position of the "Call History" button on the text, values are 1-13 (decimal), IE, Upperleft, bottomright, center, etc.
bmpNormal = Path to the Bitmap you see when you are not touching the keys
bmpPressed = Path to the Bitmap you see when you press a dial key
bmpFlags = Adjusts the alignment of the bitmap on the key, not commonly used
bmpTransparency = Transparency of the bitmap and ability to show through backgound image
bmpDisabled = Bitmap that displays if the button goes disabled, like "Hold" is disabled if you are not in call
textDisabledColor = text of the disabled in the event a button goes disabled
other = Only used to define the page background
bmpNormal = Path to the image used in the background
TalkEndButton = The setting for the combined talk / end button
bmpDisabledEnd = Bitmap that displays when the End button goes disabled
bmpDisabledTalk = Bitmap that displays when the Talk button goes disabled
bmpFlagsEnd = Adjusts the alignment of the bitmap on the key, not commonly used
bmpFlagsTalk = Adjusts the alignment of the bitmap on the key, not commonly used
bmpNormalEnd = Path to the Bitmap you see when End is active
bmpNormalTalk = Path to the Bitmap you see when Talk is active
bmpPressedEnd = Path to the Bitmap you see when End is pressed
bmpPressedTalk = Path to the Bitmap you see when Talk is pressed
bmpTransparencyEnd = End of the bitmap and ability to show through backgound image
bmpTransparencyTalk = Transparency of the Talk bitmap and ability to show through backgound image Transparency
PROGRESS = This is the "In Call" page you see when on a call
VerbButton = Call History Button (special value f0f0f will make the text invisible on the textFlags key)
textColor = Color of the "Call History" text
textRCMLStyle = Size of the "Call History" text, values are HEX 1a for the smaller through 20 for the largest (1a,1b,1c, etc)
textFlags = Position of the "Call History" text on the button, values are 1-13 (decimal), IE, Upperleft, bottomright, center,etc
bmpNormal = Path to the Bitmap you see when you are not touching the keys
bmpPressed = Path to the Bitmap you see when you press a dial key
bmpFlags = Adjusts the alignment of the bitmap on the key, not commonly used
bmpTransparency = Transparency of the bitmap and ability to show through backgound image
bmpDisabled = Bitmap that displays if the button goes disabled, like "Hold" is disabled if you are not in call
other =Only used to define the background page
bmpNormal = Path to the image used in the background
TalkEndButton = The setting for the combined talk/end button
bmpDisabledEnd = Bitmap that displays when the End button goes disabled
bmpDisabledTalk = Bitmap that displays when the Talk button goes disabled
bmpFlagsEnd = Adjusts the alignment of the bitmap on the key, not commonly used
bmpFlagsTalk = Adjusts the alignment of the bitmap on the key, not commonly used
bmpNormalEnd = Path to the Bitmap you see when End is active
bmpNormalTalk = Path to the Bitmap you see when Talk is active
bmpPressedEnd = Path to the Bitmap you see when End is pressed
bmpPressedTalk = Path to the Bitmap you see when Talk is pressed
bmpTransparencyEnd = Transparency of the End bitmap and ability to show through backgound image
bmpTransparencyTalk = Transparency of the Talk bitmap and ability to show through backgound image
text =Text in the "Information Window" The one that shows last number dialed, contact info, etc
textColor = Color of the text in the information window
8) Problems
For those who have already installed a dialer skin you must delete all keys added to the registry.
HKEY_LOCAL_MACHINE \ Security \ Phone \ Skin \ DIALER (entire directory)
HKEY_LOCAL_MACHINE \ Security \ Phone \ Skin \ PROGRESS (entire directory)
For HTC but also look here, if problems in displaying and / or color persisted.
[HKEY_LOCAL_MACHINE\Software\HTC\PHONE]
[HKEY_LOCAL_MACHINE\SOFTWARE\HTC\SmartDialing]
You have to play.
Thank you to Mat for the Tuto clarification and all those involved in its improvement.
Rickou26 (Or Arthemus).
My File
@+ Rickou26
very nice tutorial
thanks a lot
Thank you sheennick123456.
Hi,
A new screnn
Thanks rickou26 , I'm gonna give it a try and make my own.
Hi,
Good, we look forward to the result
By.
tested the value for size of caracters for history call
not working on touch pro wm6.1
Hi,
Update new build 23028 or newer and VideoDialer for LG KS20.
To remove the scroll bar just to make the following change -> HKLM \ System \ GWE \ cxVScr = 0
By.
Hello,
For KS20 user :
change only this key to swap Videodialer/WmDialer
[HKEY_LOCAL_MACHINE\Security\Phone\Skin] [HKEY_LOCAL_MACHINE \ Security\ Phone\ Skin]
"ext" = "" -> Wm Dialer
"ext" = "\windows\LgePhoneExt.dll" Video Dialer
By
Good Tutorial but I have a little problem with DLL: I couldn't copy it on PC to change button size (I tried with Resco Explorer and PC Explorer).
I have a Touch HD with WM6.5 (see signature to specific ROM)
Thanks a lot ^^
D'rath
Hi,
The simplest is to retrieve the DLL directly in the source files of the ROM (OEM or SYS). WM files are identical regardless of the PPC so you can use packetages filed by Da_G.
For your problem is simply that these DLLs are identified as belonging to the ROM which sometimes blocks their copy ...
By.
Hello,
build 23420 update to MediaFire.
By.
Thank you for this tutorial, awesome work!
rickou26 said:
Hello,
build 23420 update to MediaFire.
By.
Click to expand...
Click to collapse
Your dialer is nice and slick with latest pureblack theme compatible with COM3/4 branch. Great combo
Great tuto!! I have been through this many times and have yet to have success! It seems though this tuto is pre WM6.5 so I'm wondering if the .dll that the dialer calls on has changed in WM6.5? Or maybe the .dll I need to edit is different as I have a Samsung Omnia. I made all of the changes in tapres.dll.0409.mui and changed the image sizes accordingly but the dialer does not change! Any help?? I noticed the dialog header is 0,0,320,240, in the resource, does this mean it is only for that resolution? Thanks.
Hi,
totalcommander (or resco explorer) used to copy the dll into windows and overwrite the original.
@+
rickou26 said:
Hi,
totalcommander (or resco explorer) used to copy the dll into windows and overwrite the original.
@+
Click to expand...
Click to collapse
I forgot to mention, I am a chef and I am just editing the .dll and then cooking it in. Maybe there is something I am missing there so I will try just adding the edited .dll to the windows directory. Thanks!
If the keyboard appears unchanged is that the original has not been replaced. No keyboard only appears if it is a problem signing the DLL. Also your kitchen must include this signature certificate ;-)
@ +
Related
Javascript coder wanted for help in the kitchen...
I (or rather, all of us...) need some code, and I've never really done any Javascript. Could someone please code: - Enable all controls on form 0 of a document. - Walk through all the controls in order. For each control: - Make a temporary string that holds the name of the control - add a slash and the value of the control if it is a checkbox - Walk through all the controls again - Disable any controls: - whose name is longer, but starts with the temp string above - which are radiobuttons whose name is the temp-string - done This would disable any controls that do not apply when the user deselects a higher-level checkbox or radio-button, which would look much cleaner and cooler. I would have to spend most of today on this learning enough Javascript and fixing stupid beginner-bugs, and I would be disapointed if we don't have at least a few people here who can code this in 10 minutes. Code can be tested by copying the form from the kitchen locally and creating a function to replace the submit placed at every checkbox or radiobutton control.
ok, consider this a beta i did not follow your design in whole but still i hope the functionality is the same email me to [email protected] for any needed changes my local time is 2:31 after midnight uh uaah, good night Code: <html> <head> <script> function setupDisable() { var myForm = document.getElementById('myForm'); // enable all of them for(var i=0; i<myForm.elements.length; i++) { myForm.elements[i].disabled = false; } // foreach assign a tmpName for(var i=0; i<myForm.elements.length; i++) { var tmpName = myForm.elements[i].name; if (myForm.elements[i].type == 'checkbox') { // IMHO this is not needed and will break the functionality // and this fact renders this whole cycle useless :) // you can just use the name // property in fuiction doDisable... //tmpName += '/' + myForm.elements[i].value; } myForm.elements[i].tmpName = tmpName; } } function doDisable(root) { // disable all children var myName = root.tmpName; var myForm = document.getElementById('myForm'); if (!root.checked) { alert('went off'); for(var i=0; i<myForm.elements.length; i++) { var actName = myForm.elements[i].name; if (actName.indexOf(myName) == 0 && actName != myName) { myForm.elements[i].disabled = true; } } } else { alert('went on'); for(var i=0; i<myForm.elements.length; i++) { var actName = myForm.elements[i].name; if (actName.indexOf(myName) == 0 && actName != myName) { myForm.elements[i].disabled = false; } } } } </script> </head> <body onload="setupDisable()"> <form id="myForm"> <INPUT TYPE="checkbox" name="in1" onclick="doDisable(this)">in1 <INPUT TYPE="checkbox" name="in2" onclick="doDisable(this)">in2 <INPUT TYPE="radio" name="in2/1" value="1" onclick="doDisable(this)">in2/1 <INPUT TYPE="radio" name="in2/1" value="2" onclick="doDisable(this)">in2/1 <INPUT TYPE="radio" name="in2/1" value="3" onclick="doDisable(this)">in2/1 </form> </body> </html>
[HELP!] - RIL_SetRLPOptions, Radio Link Protocol problem.
Hi! Does anybody know how to set parameters of RLP GSM 9600 data connection using RIL/TAPI? I'm using v.110 gsm data connection but would like to change parameters to lower down latency. Thanks. Mirko
Code: typedef struct rilrlpinfo_tag { DWORD cbSize; // structure size in bytes DWORD dwParams; // indicates valid parameters DWORD dwIWS; // IWF-to-MS window size DWORD dwMWS; // MS-to-IWF window size DWORD dwAckTimer; // acknowledgement timer in 10s of milliseconds (T1) DWORD dwRetransmissionAttempts; // number of retransmission attempts (N2) DWORD dwVersion; // RLP version number DWORD dwResequencingPeriod; // resequencing period (T4) } RILRLPINFO, *LPRILRLPINFO; #define RIL_PARAM_RLPI_IWS (0x00000001) #define RIL_PARAM_RLPI_MWS (0x00000002) #define RIL_PARAM_RLPI_ACKTIMER (0x00000004) #define RIL_PARAM_RLPI_RETRANSMISSIONATTEMPTS (0x00000008) #define RIL_PARAM_RLPI_VERSION (0x00000010) #define RIL_PARAM_RPLI_RESEQUENCINGPERIOD (0x00000020) #define RIL_PARAM_RPLI_ALL (0x0000003f)
OpenGL ES HTC TP2
I've been beating my head against the wall on this, so it's time to ask for help. I've ported my game engine from iPhone to Windows CE (it actually started out many years ago as a WinCE engine, so I've developed it with portability in mind). I've also maintained a Windows build (full windows) all along for development. I'm having problems initializing OpenGL ES on the HTC Touch Pro 2. Now what is maddening is that one of the builds worked fine, but I can't reproduce that success. For starters, I'm linking to the Vincent OGLES implementation. If I use the Vincent libGLES_CM.DLL on a Dell x50v then it renders fine using software (so it's very slow - I haven't begun to see about using the GLES lite hardware implementation on that device yet). So is using the Vincent implementation without the software renderer DLL the correct method on a device like the TP2? I tried this OpenGL ES SDK: http://www.khronos.org/message_boards/viewtopic.php?f=11&t=1433 But it crashes on the first call to any OGLES API (eglGetDisplay). So I assume the linker lib is not mapping correctly to the TP2's DLL. With Vincent it is failing at eglCreateContext, which returns EGL_BAD_ATTRIBUTE. If I do not specify an attribute list (which I see is how many other implementations call that routine) then it crashes. If I send an attribute array just containing EGL_NONE then it also crashes. It has to have at least one actual attribute to not crash. I'm using attributes that are valid, and have tried many, many combinations, but it still returns EGL_BAD_ATTRIBUTE. Any suggestions would be greatly appreciated.
Here's the code. I've tried calling eglCreateContext before and after eglCreateWindowSurface, because I've seen implementations do it both ways, but it made no difference. Code: g_hMainDC = GetDC(hWnd); EGLConfig* configs = NULL; const EGLint configAttribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6, EGL_BLUE_SIZE, 5, EGL_ALPHA_SIZE, EGL_DONT_CARE, EGL_DEPTH_SIZE, 16, EGL_STENCIL_SIZE, EGL_DONT_CARE, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; glesDisplay = eglGetDisplay(g_hMainDC); if (!glesDisplay) { return false; } if (!eglInitialize(glesDisplay, NULL, NULL)) { return false; } EGLint num_configs = 0; if (!eglGetConfigs(glesDisplay, NULL, 0, &num_configs)) { return false; } if (num_configs==0) { return false; } configs = new EGLConfig[num_configs]; eglGetConfigs(glesDisplay,configs,sizeof(EGLConfig),&num_configs); EGLConfig config = NULL; if (!eglChooseConfig(glesDisplay, configAttribs, &config, 1, &num_configs)) { return false; } if (num_configs==0) { return false; } if (config==NULL) { return false; } // Let’s create our rendering context glesContext=eglCreateContext(glesDisplay, config, EGL_NO_CONTEXT, configAttribs); if(!glesContext) { return false; } glesSurface = eglCreateWindowSurface(glesDisplay, config, hWnd, NULL); if (!glesSurface) { return false; }
Okay. Finally got a handle on this. You can't pass attributes to eglCreateContext or eglCreateWindowSurface or it will always return EGL_BAD_ATTRIBUTE. It has to be an empty array or a NULL pointer. My app was running out of memory on the stack, and it would fail in eglCreateContext. I increased the stack size in the link settings and that fixed it. I had played around with the stack size earlier, and reverted my settings because it did not appear that had anything to do with the OGL ES initialization problems I was having.
Try to google the Xperia SDK which come with workable OpenGL ES samples.
[Q] Catch HTC key presses
Hey all, Is there someone who knows how I can disable the HTC back-key, the start-menu key and the Home-key? Those keys aren't applicationkey's like I'd expected and so I can't disable them using UnregisterFunc1() (extern void of coredll.dll). Anyone who knows how I can disable this keys in C#? Thanks, MadMatt
Does SetWindowHookEx work for you? .h: Code: #define WH_KEYBOARD_LL 20 extern "C" { typedef LRESULT (CALLBACK* HOOKPROC)(int code, WPARAM wParam, LPARAM lParam); typedef struct tagKBDLLHOOKSTRUCT { DWORD vkCode; // virtual key code DWORD scanCode; // scan code DWORD flags; // flags DWORD flags; // unused DWORD time; // time stamp for this message DWORD dwExtraInfo; // extra info from the driver or keybd_event } KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT; HHOOK WINAPI SetWindowsHookExW( int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId); #define SetWindowsHookEx SetWindowsHookExW BOOL WINAPI UnhookWindowsHookEx( HHOOK hhk); LRESULT WINAPI CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam); } #endif Usage is well-written on MSDN. Though, it won't work if keypad driver doesn't send this button to the system. Then, better way, but it will need some investigation. Not sure if it works for these keys, but last HTC devices have keypad.dll with global key hook feature. You can use it like this: Code: HANDLE kbd = CreateFileW(L"KBD1:", 0xC0000000, 0, 0, 3, 0, 0); DWORD returned; DeviceIoControl(kbd, 0xB2028, <<unique ID of hook>>, 4, 0, 0, &returned, 0); Then your application should wait for "GetFromKeyEvent_<<ID>>" event. GetEventData will return keycode. After that you should use SetEvent for "SendBackToKeyEvent_<<ID>>" event with the same data. Not sure if it is fully correct description - I can't check it since my driver doesn't have this feature. That's they way how HTCVolumeControl gets info about pressed volume keys.
Thanks! I'll take a look at this! I think my device should support this feature, as it is released in May 2010, isn't it? If it doesn't work, I'll post again
My solution to long press volume button
For some reason, my MTCD unit with Malaysk Rom did not allow me to set long press function to a steering wheel button set for volume. Not sure if it is Malaysk rom or factory rom, or MCU not is causing this issue. So, in order to fix this problem, I used an Arduino to interpret steering wheel button inputs and send different signal for short press and long press to the head unit. Also, my car does not have steering wheel radio buttons, so I utilized cruise control buttons. I'm sure it would be possible to do the same in the head unit's firmware it self, but I did not know where to begin, so I chose the path I know will work. I check long press for buttons I will be using for volume only (Up and down) and other buttons are just passed to reflect actual button status. { "lightbox_close": "Close", "lightbox_next": "Next", "lightbox_previous": "Previous", "lightbox_error": "The requested content cannot be loaded. Please try again later.", "lightbox_start_slideshow": "Start slideshow", "lightbox_stop_slideshow": "Stop slideshow", "lightbox_full_screen": "Full screen", "lightbox_thumbnails": "Thumbnails", "lightbox_download": "Download", "lightbox_share": "Share", "lightbox_zoom": "Zoom", "lightbox_new_window": "New window", "lightbox_toggle_sidebar": "Toggle sidebar" } This is the circuit I have built. Very simple circuit with a digital potentiometer to send different resistance for each button press. This is the after soldering parts. Ignore wires at the bottom. I didn't realized copied version of Arduino pro mini did not come with bootloader preloaded, so I had to tap into some pins to program the chip directly first using avr programmer. Added a 100 ohm resistor to a relay in order to protect it from higher voltage normally present in an automobile. The absolute maximum voltage of the relay I used was 15V and normal operating voltage is 12V. I did not want risk breaking it. This button allows me to select between cruise control and remote control. This is what controls the relay in the circuit. Hook up everything, and it is good to go. I used ACC power to power the circuit, since there is no reason to keep it running when radio is not on. Up -> Volume Up Long Up (1 sec) -> Previous 2+ Sec Up -> Repeat Long Up every sec Down -> Volume Down Long Down (1 sec) -> Next 2+ Sec Down -> Repeat Long Down every sec Pull -> Play/Pause Push -> Mode Long Push -> Home (Using head unit's built in long press button assignment). Following is my code. I'm sure it is not the best code, but it works. Code: // Car Steering Wheel Rmote w/ Cruise Control Buttons // lambition // 10/31/2016 // Using SPI controlled Microchip MCP41100 100K Digital Potentiometer for Output. // Resistance Value calculated // Termianl W => Ground, Terminal A => Head Unit Key Input, Terminal B => Leave open // R_WA: Resistance between Wiper and terminal A. // R_AB: Resistance between terminal A and B. (100k) // R_W: Wiper resistance. 125 for 100k chip. // R_WA(D_n) = ((R_AB * (256-D_n))/256+R_W // 390.6 ohms per step (100k/256). // Pin connections // CS(1) -> 10 (CS) // SCK(2) -> 13 (SCK) // SI(3) -> 11 (MOSI) // Vss (4) -> GND // PA (5) -> Head Unit Key 1 // PW (6) -> GND // PB (7) -> Open // Vdd (8) -> 5V // First byte is command, Second byte is data. MSB first. // Command Byte // X X C1 C0 X X P1 P0 // C1,C0 = 0,1: Write Data, 1,0: Shutdown, Ignore others. // P1,P0 = 0,1: Select Pot 0, 1,0: Select Pot 1, 1,1: Select Both (P1 is don't care bit for MCP41xxx) #define CMD_B 0b00010001 // Write Data, Select Pot0. Don't need any other commands. // Map I/O Pins #define KEYIN A0 // Key Input #define CS 10 // Chip select // Hold time for each button press except pull and push #define button_hold_ms 500 /* Input Key Resistance Values in Ohms. Toyota Highalnder Cruise Control Switches. UP 240 DOWN 630 PULL 1540 PUSH 0 */ // Input Key Voltages with 1k pull up resistor // Change these values to what ever your switch is giving. #define KEYUP_V 1 #define KEYDOWN_V 2 #define KEYPULL_V 3 #define KEYPUSH_V 0 #define VAL_PER_V 204.6 #define TOLERANCE_V 0.35 #define OFFSET 0.05 // Calculate minimum and maximum ADC values #define MIN_KEYUP_VAL (int)((KEYUP_V+OFFSET-TOLERANCE_V)*VAL_PER_V) #define MAX_KEYUP_VAL (int)((KEYUP_V+OFFSET+TOLERANCE_V)*VAL_PER_V) #define MIN_KEYDOWN_VAL (int)((KEYDOWN_V+OFFSET-TOLERANCE_V)*VAL_PER_V) #define MAX_KEYDOWN_VAL (int)((KEYDOWN_V+OFFSET+TOLERANCE_V)*VAL_PER_V) #define MIN_KEYPULL_VAL (int)((KEYPULL_V+OFFSET-TOLERANCE_V)*VAL_PER_V) #define MAX_KEYPULL_VAL (int)((KEYPULL_V+OFFSET+TOLERANCE_V)*VAL_PER_V) #define MIN_KEYPUSH_VAL (int)((KEYPUSH_V+OFFSET-TOLERANCE_V)*VAL_PER_V) #define MAX_KEYPUSH_VAL (int)((KEYPUSH_V+OFFSET+TOLERANCE_V)*VAL_PER_V) // Digital Potentiometer Values #define KEYUP_POT 255 #define KEYDOWN_POT 230 #define KEYLONGUP_POT 200 #define KEYLONGDOWN_POT 160 #define KEYPUSH_POT 120 #define KEYPULL_POT 0 #include <SPI.h> enum KeyType { OPEN, KEYUP, KEYDOWN, KEYLONGUP, KEYLONGDOWN, KEYPUSH, KEYPULL }; bool pot_off; void setup() { // put your setup code here, to run once: // Configure Pins pinMode(KEYIN, INPUT); pinMode(CS, OUTPUT); digitalWrite(CS, HIGH); // SPI Initialization SPI.begin(); DigitalPot_Shutdown(); // Start with Pot off } void loop() { // put your main code here, to run repeatedly: static KeyType current_button_state = OPEN; static KeyType prev_button_state = OPEN; static KeyType tmp_prev_button_state = OPEN; static unsigned long button_pressed = 0; static unsigned long millis_button_held; static long keyInputValue; static bool over_sec_processed = true; static bool prev_long_press = false; keyInputValue = analogRead(KEYIN); // Read Analog Input KeyType tmp_button_state ; // Decode Key Inputs if ( (keyInputValue <= MAX_KEYUP_VAL) && (keyInputValue >= MIN_KEYUP_VAL)) // Key Up Detected { tmp_button_state = KEYUP; } else if ( (keyInputValue <= MAX_KEYDOWN_VAL) && (keyInputValue >= MIN_KEYDOWN_VAL)) // Key Down Detected { tmp_button_state = KEYDOWN; } else if ( (keyInputValue <= MAX_KEYPULL_VAL) && (keyInputValue >= MIN_KEYPULL_VAL)) // Key Pull Detected { tmp_button_state = KEYPULL; } else if ( (keyInputValue <= MAX_KEYPUSH_VAL) && (keyInputValue >= MIN_KEYPUSH_VAL)) // Key Push Detected { tmp_button_state = KEYPUSH; } else { tmp_button_state = OPEN; // Mark key not pressed and Ignore out of spec values. } // Input State Changes if (tmp_button_state != tmp_prev_button_state) { button_pressed = millis(); over_sec_processed = false; } if ((millis() - button_pressed) > 10) // 10 ms debounce delay { current_button_state = tmp_button_state; } tmp_prev_button_state = tmp_button_state; if ( (current_button_state != OPEN) && (current_button_state == prev_button_state) ) // Button Held { millis_button_held = millis() - button_pressed; } if ( (current_button_state == OPEN)) // Key released { if ((millis_button_held < 1000) && (!prev_long_press)) // Key was pressed less than 1 second and previous button was not a long press. { if (prev_button_state == KEYUP) // If last button pressed was Keyup send keyup { DigitalPot_Write(KEYUP_POT); delay(button_hold_ms); DigitalPot_Shutdown(); } else if (prev_button_state == KEYDOWN) // If last button pressed was Keydown send keydown. { DigitalPot_Write(KEYDOWN_POT); delay(button_hold_ms); DigitalPot_Shutdown(); } else if (!pot_off) // For all other keys, shutoff pot upon releasing button, unless already off. { DigitalPot_Shutdown(); } } prev_long_press = false; } else if ( (current_button_state == KEYUP) || (current_button_state == KEYDOWN) ) // Key up or down { if ( (millis_button_held >= 1000) && (!over_sec_processed) ) // Over 1 second { if (prev_button_state == KEYUP) { DigitalPot_Write(KEYLONGUP_POT); delay(button_hold_ms); DigitalPot_Shutdown(); } else if (prev_button_state == KEYDOWN) { DigitalPot_Write(KEYLONGDOWN_POT); delay(button_hold_ms); DigitalPot_Shutdown(); } over_sec_processed = true; prev_long_press = true; } if (millis_button_held >= 2000) // Over 2 seconds { delay(1000); // Wait 1 sec between signal over_sec_processed = false; // Send } } else if ( current_button_state == KEYPULL ) { if (pot_off) // Write to Pot only once { DigitalPot_Write(KEYPULL_POT); } prev_long_press = false; } else if ( current_button_state == KEYPUSH ) { if (pot_off) // Write to Pot only once { DigitalPot_Write(KEYPUSH_POT); } prev_long_press = false; } prev_button_state = current_button_state; } void DigitalPot_Write(const byte data) { SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)); //10MHz, MSB First, Ouput on rising edge. digitalWrite(CS, LOW); SPI.transfer(CMD_B); // Send Command SPI.transfer(data); // send Data digitalWrite(CS, HIGH); SPI.endTransaction(); pot_off = false; } void DigitalPot_Shutdown() { SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)); //10MHz, MSB First, Ouput on rising edge. digitalWrite(CS, LOW); SPI.transfer(0b00100001); //Shutdown Command SPI.transfer(0); // Dummy data digitalWrite(CS, HIGH); SPI.endTransaction(); pot_off = true; }
Dude... That is f** awesome!! But I hardly doubt that anyone will be willing to go through the same just to get the long-press function =)) I ll keep waiting for the software solution
Kudos!! Awesome job and very simple - but you just have to come up with the idea. Respect!
Mighty_X said: Dude... That is f** awesome!! But I hardly doubt that anyone will be willing to go through the same just to get the long-press function =)) I ll keep waiting for the software solution Click to expand... Click to collapse It is actually quiet simple. Whole thing cost me about $6 to make because I already had switches and relay. Chinese copy version of Arduino pro mini is only around $3 or less. Digital potentiometer is around $3 as well, but this can be replaced with resistor array and using 5 digital IO pins. Digital potentiometer just makes it easier to change resistance values. Henkdrenth said: Kudos!! Awesome job and very simple - but you just have to come up with the idea. Respect! Click to expand... Click to collapse I wish someone cracks MCU of our device. Our device have great potential, but software is made to just barely functioning.
Hi guys i would ask your help. I have an Alfa Romeo Giulietta, Installed in the dash a nexus 7 2013 and I want use the steering wheel buttons. The car use the protocol is 15765-4 29bit and I have on Bluetooth obd reader. Can you please help me out? Thanks in advance. Inviato dal mio FRD-L09 utilizzando Tapatalk
valk791 said: Hi guys i would ask your help. I have an Alfa Romeo Giulietta, Installed in the dash a nexus 7 2013 and I want use the steering wheel buttons. The car use the protocol is 15765-4 29bit and I have on Bluetooth obd reader. Can you please help me out? Thanks in advance. Inviato dal mio FRD-L09 utilizzando Tapatalk Click to expand... Click to collapse You might receive suggestions posting in the appropriate forum or opening a new thread. To post here is isnt appropriate.
Amazing work.... Many thanks
Wow a nice, clean, elegant and simple solution. I've done it little bit different (Old Style) as my car model didn't had factory Steering wheel, so I made steering wheel upgrade that left me with 6 Wires to play with (3 for 6 Media Commands and 3 for 4 Cruise control). So I ended up with dismantle steering wheel commands setting up each command different by 20kOhm in parallel to outputs So I have 6 Main commands and any combination of two+ keys simultaneously for additional commands as I get 1/2 of sum Ohm of the commands pressed. and o the other side 4 Cruise control commands (do not have cruise control in Car) both commands Directly connected GND+KEY1 for Media Controls and GND+KEY2 for cruise control. Now I only need to think how to emulate keyboard commands so that I can navigate Home Screen and emulate Swipe. FYI I have not seen any ROM to allow Vol +/- long press as it is reserved for Vol Repeat mode
Works great for me, just so others may also take advantage of this code, I used the below for a Honda Jazz/Fit 2010 with a Kenwood Android Auto Head Unit, I only used the CH+/- and MODE for long press as I did not want to mess with volume triggers and 8 total controls is enough for me (just), not sure if anyone else had an issue but for me the lower resistance (higher potentiometer values) were the only ones that would work with my head unit. Code: // Car Steering Wheel Rmote w/ Cruise Control Buttons // lambition // 10/31/2016 // Using SPI controlled Microchip MCP41100 100K Digital Potentiometer for Output. // Resistance Value calculated // Termianl W => Ground, Terminal A => Head Unit Key Input, Terminal B => Leave open // R_WA: Resistance between Wiper and terminal A. // R_AB: Resistance between terminal A and B. (100k) // R_W: Wiper resistance. 125 for 100k chip. // R_WA(D_n) = ((R_AB * (256-D_n))/256+R_W // 390.6 ohms per step (100k/256). // Pin connections // CS(1) -> 10 (CS) // SCK(2) -> 13 (SCK) // SI(3) -> 11 (MOSI) // Vss (4) -> GND // PA (5) -> Head Unit Key 1 // PW (6) -> GND // PB (7) -> Open // Vdd (8) -> 5V // First byte is command, Second byte is data. MSB first. // Command Byte // X X C1 C0 X X P1 P0 // C1,C0 = 0,1: Write Data, 1,0: Shutdown, Ignore others. // P1,P0 = 0,1: Select Pot 0, 1,0: Select Pot 1, 1,1: Select Both (P1 is don't care bit for MCP41xxx) #define CMD_B 0b00010001 // Write Data, Select Pot0. Don't need any other commands. // Map I/O Pins #define KEYIN A0 // Key Input #define CS 10 // Chip select // Hold time for each button press except pull and push #define button_hold_ms 500 //Just for programming head unit //#define button_hold_ms 3000 // Input Key Voltages with 1k pull up resistor // Change these values to what ever your switch is giving. #define INPUT_KEYUP_V 315 #define INPUT_KEYDOWN_V 115 #define INPUT_KEYUP_CH 691 #define INPUT_KEYDOWN_CH 501 #define INPUT_KEY_MODE 839 #define TOLERANCE_V 20 #define OFFSET 0.05 // Calculate minimum and maximum ADC values #define MIN_KEYUP_V_VAL (int)(INPUT_KEYUP_V+OFFSET-TOLERANCE_V) #define MAX_KEYUP_V_VAL (int)(INPUT_KEYUP_V+OFFSET+TOLERANCE_V) #define MIN_KEYDOWN_V_VAL (int)(INPUT_KEYDOWN_V+OFFSET-TOLERANCE_V) #define MAX_KEYDOWN_V_VAL (int)(INPUT_KEYDOWN_V+OFFSET+TOLERANCE_V) #define MIN_KEYUP_CH_VAL (int)(INPUT_KEYUP_CH+OFFSET-TOLERANCE_V) #define MAX_KEYUP_CH_VAL (int)(INPUT_KEYUP_CH+OFFSET+TOLERANCE_V) #define MIN_KEYDOWN_CH_VAL (int)(INPUT_KEYDOWN_CH+OFFSET-TOLERANCE_V) #define MAX_KEYDOWN_CH_VAL (int)(INPUT_KEYDOWN_CH+OFFSET+TOLERANCE_V) #define MIN_KEY_MODE_VAL (int)(INPUT_KEY_MODE+OFFSET-TOLERANCE_V) #define MAX_KEY_MODE_VAL (int)(INPUT_KEY_MODE+OFFSET+TOLERANCE_V) // Digital Potentiometer Values #define KEYUP_V_POT 255 #define KEYDOWN_V_POT 254 #define KEYUP_CH_POT 250 #define KEYDOWN_CH_POT 243 #define KEYUPLONG_CH_POT 239 #define KEYDOWNLONG_CH_POT 246 #define KEY_MODE_POT 94 #define KEYLONG_MODE_POT 200 #include <SPI.h> enum KeyType { OPEN, KEYUP_V, KEYDOWN_V, KEYUP_CH, KEYDOWN_CH, KEYLONGUP_CH, KEYLONGDOWN_CH, KEY_MODE, KEYLONG_MODE }; bool pot_off; bool debug = false; void setup() { // put your setup code here, to run once: Serial.begin(115200); if (debug) { while (!Serial) { } } debugMessage("BOOT: Serial initialized"); // Configure Pins pinMode(KEYIN, INPUT); pinMode(CS, OUTPUT); digitalWrite(CS, HIGH); // SPI Initialization SPI.begin(); DigitalPot_Shutdown(); // Start with Pot off debugMessage("BOOT: Booted"); } void loop() { // put your main code here, to run repeatedly: static KeyType current_button_state = OPEN; static KeyType prev_button_state = OPEN; static KeyType tmp_prev_button_state = OPEN; static unsigned long button_pressed = 0; static unsigned long millis_button_held; static long keyInputValue; static bool over_sec_processed = true; static bool prev_long_press = false; keyInputValue = analogRead(KEYIN); // Read Analog Input //debugMessage((String)keyInputValue); KeyType tmp_button_state ; // Decode Key Inputs if ( (keyInputValue <= MAX_KEYUP_V_VAL) && (keyInputValue >= MIN_KEYUP_V_VAL)) // Key Up Detected { tmp_button_state = KEYUP_V; } else if ( (keyInputValue <= MAX_KEYDOWN_V_VAL) && (keyInputValue >= MIN_KEYDOWN_V_VAL)) // Key Down Detected { tmp_button_state = KEYDOWN_V; } else if ( (keyInputValue <= MAX_KEYUP_CH_VAL) && (keyInputValue >= MIN_KEYUP_CH_VAL)) // Key Pull Detected { tmp_button_state = KEYUP_CH; } else if ( (keyInputValue <= MAX_KEYDOWN_CH_VAL) && (keyInputValue >= MIN_KEYDOWN_CH_VAL)) // Key Push Detected { tmp_button_state = KEYDOWN_CH; } else if ( (keyInputValue <= MAX_KEY_MODE_VAL) && (keyInputValue >= MIN_KEY_MODE_VAL)) // Key Push Detected { tmp_button_state = KEY_MODE; } else { tmp_button_state = OPEN; // Mark key not pressed and Ignore out of spec values. } // Input State Changes if (tmp_button_state != tmp_prev_button_state) { button_pressed = millis(); over_sec_processed = false; } if ((millis() - button_pressed) > 10) // 10 ms debounce delay { current_button_state = tmp_button_state; } tmp_prev_button_state = tmp_button_state; if ( (current_button_state != OPEN) && (current_button_state == prev_button_state) ) // Button Held { millis_button_held = millis() - button_pressed; } //Button is now in open if ( (current_button_state == OPEN)) // Key released { //debugMessage("STATE: OPEN"); if ((millis_button_held < 1000) && (!prev_long_press)) // Key was pressed less than 1 second and previous button was not a long press. { if (prev_button_state == KEYUP_CH) // If last button pressed was Keyup send keyup { debugMessage("ACTION: SHORT KEYUP_CH"); DigitalPot_Write(KEYUP_CH_POT); delay(button_hold_ms); DigitalPot_Shutdown(); } else if (prev_button_state == KEYDOWN_CH) // If last button pressed was Keydown send keydown. { debugMessage("ACTION: SHORT KEYDOWN_CH"); DigitalPot_Write(KEYDOWN_CH_POT); delay(button_hold_ms); DigitalPot_Shutdown(); } else if (prev_button_state == KEY_MODE) // If last button pressed was Keydown send keydown. { debugMessage("ACTION: SHORT KEYMODE"); DigitalPot_Write(KEY_MODE_POT); delay(button_hold_ms); DigitalPot_Shutdown(); } else if (!pot_off) // For all other keys, shutoff pot upon releasing button, unless already off. { DigitalPot_Shutdown(); } } prev_long_press = false; } else if ( (current_button_state == KEYUP_CH) || (current_button_state == KEYDOWN_CH) || (current_button_state == KEY_MODE) ) // Key up or down { if ( (millis_button_held >= 1000) && (!over_sec_processed) ) // Over 1 second { if (prev_button_state == KEYUP_CH) { debugMessage("ACTION: LONG KEYUP_CH"); DigitalPot_Write(KEYUPLONG_CH_POT); delay(button_hold_ms); DigitalPot_Shutdown(); } else if (prev_button_state == KEYDOWN_CH) { debugMessage("ACTION: LONG KEYDOWN_CH"); DigitalPot_Write(KEYDOWNLONG_CH_POT); delay(button_hold_ms); DigitalPot_Shutdown(); } else if (prev_button_state == KEY_MODE) { debugMessage("ACTION: LONG KEYMODE"); DigitalPot_Write(KEYLONG_MODE_POT); delay(button_hold_ms); DigitalPot_Shutdown(); } over_sec_processed = true; prev_long_press = true; } if (millis_button_held >= 2000) // Over 2 seconds { delay(1000); // Wait 1 sec between signal over_sec_processed = false; // Send } } else if ( current_button_state == KEYUP_V ) { if (pot_off) // Write to Pot only once { debugMessage("ACTION: SHORT KEYUP_V"); DigitalPot_Write(KEYUP_V_POT); } prev_long_press = false; } else if ( current_button_state == KEYDOWN_V ) { if (pot_off) // Write to Pot only once { debugMessage("ACTION: SHORT KEYDOWN_V"); DigitalPot_Write(KEYDOWN_V_POT); } prev_long_press = false; } prev_button_state = current_button_state; } void DigitalPot_Write(const byte data) { SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)); //10MHz, MSB First, Ouput on rising edge. digitalWrite(CS, LOW); SPI.transfer(CMD_B); // Send Command SPI.transfer(data); // send Data digitalWrite(CS, HIGH); SPI.endTransaction(); pot_off = false; } void DigitalPot_Shutdown() { SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)); //10MHz, MSB First, Ouput on rising edge. digitalWrite(CS, LOW); SPI.transfer(0b00100001); //Shutdown Command SPI.transfer(0); // Dummy data digitalWrite(CS, HIGH); SPI.endTransaction(); pot_off = true; } void debugMessage(String message) { if (debug) { Serial.println(message); } }
My car is hyundai santafe 2010 with steering wheel button, I measure the Resistance Value between button and ground by pressing each button, the result are: - Mode: 2.10 K ohm - Up: 434 ohm - Down: 1.12 K ohm - Volume Up: 4.60 K ohm - Volume Down: 6.81 K ohm - Map: 10.72 K ohm - Phone On: 41.00 K ohm - Phone Off: 18.99 K ohm I replace the other head unit (10" monitor of Suzuki XL7), so I want to use the steering wheel control of my Santafe to control the Suzuki XL7 head unit The Suzuki XL7 head unit use Resistance Value for each steering wheel button are: - Mute: 56 +- 0.6 Ohm - Volume +: 131 +- 1.3 Ohm - Volume -: 241 +- 2.4 Ohm - Next: 1571 +- 15.7 Ohm - Prev: 751 +- 7.5 Ohm - Mode: 421 +- 4.2 Ohm I read this thread many times and prepare - Arduino Nano. - resistor: 1K ohm - MCP41100 - Converter 12v to 5V. but I still not understand some code and parameter. sparky3387, lambitioncan you explain more detail for me the diagram of MCP41100 to Arduino and head unit key? // MCP41100 8 Pin connections // CS(1) -> D10 (Arduino) // SCK(2) -> D13 (Arduino) // SI(3) -> D11 (Arduino) // Vss (4) -> GND // PA (5) -> Head Unit Key 1 // PW (6) -> GND // PB (7) -> Open // Vdd (8) -> 5V The value of INPUT_KEY is voltage or Resistance Value // Input Key Voltages with 1k pull up resistor // Change these values to what ever your switch is giving. #define INPUT_KEYUP_V 315 #define INPUT_KEYDOWN_V 115 #define INPUT_KEYUP_CH 691 #define INPUT_KEYDOWN_CH 501 #define INPUT_KEY_MODE 839 Do I must change the value: #define TOLERANCE_V 20 #define OFFSET 0.05 Can you add code to measure the value ò INPUT_KEY like this link: Resistor Ladder Steering Wheel Control Interpreter Using Arduino I’m currently busy creating an Arduino steering wheel adapter between my ’05 Pontiac GTO steering wheel controls and the Parrot Asteroid Smart Android-powered head unit. Doing this beca… atomic-cactus.com How do I do, please help me. Thank you.