Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Please help me with keyboard remapping 2

Status
Not open for further replies.

dotnetprogrammer

Programmer
Aug 17, 2000
77
US
I need a program that will remap a PC keyboard.
In a nutshell, this is what it has to do.
When I will type:

(a) The character 'a', followed by a + (plus key), and a period, another + (plus key), and another period (i.e., a+.+.), it will fetch 'ä ' (Alt 0228) to the screen.

(b) Similarly, when I will type a + e, the program will display 'æ' on the screen.

I am thinking that, SETWindowsHOOKEX will need to intercept my keystrokes and change the output depending upon a text-template's remapping data... (get the idea?). I need the keyboard hook, thus no matter which Windows app I am using, the remapper or translator will continue to work, transparently.

I do not know anything about Windows Hook and do not know how to write the code for it. Any help will be appreciated!
Fred
 
Lets start with a few questions . . .
First off, are you familiar with how the Windows Event Queue works? Secondly, are you comfortable with C++? In order to hook all applications, the callback MUST reside in a DLL . . . unfortunatly, this can not be a VB ActiveX DLL, but don't worry, the code is not too bad. You are correct in your assumption that the API that you will want to use is the SetWindowsHookEx API. - Jeff Marler B-)
 
Hi fh!

It's really easy, I wrote it a few weeks ago, because I needed it aswell. The code you have to make in C++ is this:


exports.def
EXPORTS
SetKeyHook
KeyProc

SECTIONS
.shared READ WRITE SHARED

main.ccp
#include "mian.h"

#pragma data_seg(".shared") 'global variables

HWND m_hHwndKey = 0;
HHOOK m_hHookKey = 0;

#pragma data_seg()

void WINAPI SetKeyHook(HWND hWnd, HHOOK hk) { 'here you set the hook

m_hHwndKey = hWnd;
m_hHookKey = hk;
}

LRESULT CALLBACK KeyProc( int nCode, WPARAM wParam, LPARAM lParam ) { 'this is where the hook is processed
if (nCode < 0) {
return CallNextHookEx(m_hHookKey, nCode, wParam, lParam);
}

if (nCode == HC_ACTION) { 'on (keyboard) event

if (lParam & 0x80000000) { 'check last bit, 0 for keydown, 1 for keyup
PostMessage(m_hHwndKey, WM_KEYUP, wParam, lParam);
} else {
PostMessage(m_hHwndKey, WM_KEYDOWN, wParam, lParam);
}
}
return 0;
}

'and the rest is just for the dll
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID) {
if (fdwReason == DLL_PROCESS_ATTACH) {
DisableThreadLibraryCalls(hinstDLL);
}
return TRUE;
}

extern &quot;C&quot; BOOL __stdcall _DllMainCRTStartup( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
return DllMain( hinstDLL, fdwReason, lpvReserved );
}

mian.h
#include &quot;windows.h&quot;

void WINAPI SetKeyHook(HWND hWnd, HHOOK hk);


Ok, thats the Visual C++ part. If you go to Visual Basic now then you have to write this:


Option Explicit

Private Declare Sub SetKeyHook Lib &quot;hooks.dll&quot; (ByVal hWnd As Long, ByVal hHook As Long)

Private Declare Function SetWindowsHookEx Lib &quot;user32&quot; Alias &quot;SetWindowsHookExA&quot; (ByVal idHook As Long, ByVal lpfn As Long, ByVal hMod As Long, ByVal dwThreadId As Long) As Long
Private Declare Function UnhookWindowsHookEx Lib &quot;user32&quot; (ByVal hHook As Long) As Long
Private Declare Function LoadLibrary Lib &quot;kernel32&quot; Alias &quot;LoadLibraryA&quot; (ByVal lpLibFileName As String) As Long
Private Declare Function GetProcAddress Lib &quot;kernel32&quot; (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function FreeLibrary Lib &quot;kernel32&quot; (ByVal hLibModule As Long) As Long

Private Const WH_KEYBOARD = 2

Private m_hHookKey As Long
Private m_hMod As Long

Private Sub Form_Load()
Dim lpProcKey As Long

m_hMod = LoadLibrary(App.Path & &quot;\hooks.dll&quot;) 'check if dll is right...
If m_hMod = 0 Then
MsgBox &quot;Unable to load dll! Please reinstall.&quot;, vbOKOnly + vbCritical, &quot;Error&quot;
End
End If

lpProcKey = GetProcAddress(m_hMod, &quot;KeyProc&quot;)
If lpProcKey = 0 Then 'check if entries are in the dll
MsgBox &quot;Invalid dll! Please reinstall.&quot;, vbOKOnly + vbCritical, &quot;Error&quot;
End
End If

m_hHookKey = SetWindowsHookEx(WH_KEYBOARD, lpProcKey, m_hMod, 0)

SetKeyHook pctHook.hWnd, m_hHookKey 'note that pctHook is a picturebox, so you can use the picturebox events later on
End Sub

Private Sub Form_Unload(Cancel As Integer)
UnhookWindowsHookEx m_hHookKey

FreeLibrary m_hMod
End Sub

Private Sub pctHook_KeyDown(KeyCode As Integer, Shift As Integer)
'do with it what you want
End Sub

Private Sub pctHook_KeyPress(KeyAscii As Integer)
'do with it what you want
End Sub

Private Sub pctHook_KeyUp(KeyCode As Integer, Shift As Integer)
'do with it what you want
End Sub
 
Starting with JMarler:
I am a VB Programmer, but I do not know anything about &quot;Windows Event Queue.&quot; Is that something like DoEvents or Message Queue? I am familiar with C and C++ (DOS platform). Never had a &quot;Good Luck&quot; (pl. read as never succeeded) compiling Windows Platform. I have VC++. I can try compiling again.

To LuckyLuke:
Thanks for Code I will read and follow...
Fred
 
LuckyLuke,
(1) What is SetKeyHook? Is that a built-in function in Hooks.Dll?
(2) Where can I find Hooks.Dll?
(3) What is PctHook? Is that a PictureBox?
Thanks,
Fred
 
The event queue is a message queue that the OS uses to pass on events/messages (remember that Windows GUI applications are by nature event driven) to all of the running applications. Every Window (and each control is just a special instance of a Window) gets its own Event queue, but there is also a mastrer event queue that ALL eents go through before being passed onto the appropriate Window Queue. It is this global queue that you want to hook into and to do that, the code MUST be in C++ (there has been a lot of discussion up here on this matter and so far, no one has come up with a way to do this in pure VB . . . sorry I don't make the rules. I just play the game :)). The code the LuckyLuke provided is the correct code to hook into the event queue and retrieve the messages, however, you will still need to extract the Key information from lParam and wParam and then manipulate/remap them as needed and then pass them onto the appropriate Window message queue.
Let me look up the data structure that is being returned and I post it. Also, I would change one thing that LuckyLuke is doing (although what he is doing is also correct). I would use a callback function rather than raising all events to a picturebox. - Jeff Marler B-)
 
Here is the data structure being passed back in the lParam . . .

Code:
    lParam Bit Mask 
        Bit 00-15 :: The Repeat Count.
        Bit 16-23 :: The Scan Code.
        Bit 24    :: Extended key. Set to 1 if the 
                     key is an extended key;
                     otherwise, it is 0.
        Bit 25-28 :: Reserved
        Bit 29    :: The Context code. Set to 1 if
                     the ALT key is down;
                     otherwise, it is 0.
        Bit 30    :: The Previous Key State. Set to
                     1 if the key was down before
                     the message is sent;
                     otherwise, it is 0 if the key 
                     is up.
        Bit 31    :: The transistion state. Set to
                     0 if the key is being pressed
                     and 1 if it is being released.

- Jeff Marler B-)
 
Well thats quite easy for key events i think but it can be done another way indeed...

fh,

1) This is a function I wrote in hooks.dll (hooks.dll is the C++ code)
2) The code for hooks.dll is in my previous message ;-)
3) pctHook is a picturebox indeed. You need to provide the hwnd of the picturebox to the hook. As soon as hooks.dll detects a keypress, it will send the event to pctHook. That way you can use the normal keydown, keyup and keypress event in Visual Basic and I thought that was easy. The only drawback of this is that if you have data you want to send to Visual Basic, it can't go through an event (I think). This can be done to C++ though, I think I'll have to learn C++ some more :)

Basicly JMarler is right. My code works, but it can be done better. But if you just need to detect keypresses and their keycodes/ascii, then its working great!

LuCkY
 
Thanks a lot for your response to both of you. I need a program that will give total control of the keyboard to the user, to remap the entire keyboard layout.
VB is not the optimum programming language to do that, huh?
Well, I guess, I need to delve into C++ again. Only problem is I had bought some practice books (like ...21 days) on C++. None of the book I tried was clear how to compile C++ code for windows. But, to make my keyboard layout work, I will try my luck again!

To LuckyLuke,
I tried your VB Code part. I am a VB guy. That is why, I skipped the C++ code earlier. I apologize for my error! I do not know how to compile VC++ DLL though. I will try that after I re-install VC++ on my machine, very soon.

To Jmarler,
What is that lParam Bit Mask about? I think, I need to go with C++. What should I try? Any suggestion? I like to try both yours and LuckyLuke's code. I may learn VC++ after all; because, I need to learn how to program that keyboard.
Thanks,
fred
 
The lParam is part of the data (the other would wParam) used in the OS Event Queue. When monitoring keystrokes, these 2 variables will contain all of the data describing the keys pressed. The VB equivalents is a variable of Type Long, but the data is stored on the bit level, so you need to use bit masks to extract the relavent information regarding keypresses.
And yes, for what you want to do, you will need to use C++ and you will need to look at the SetWindowsHookEx API. - Jeff Marler B-)
 
LuckyLuke,
I have tried to use your C++ code but to no avail, (I am using Borland C++ builder 3). I can complie the dll but the VB function LoadLibrary fails no matter what I try.
I can't reference the dll in vb.

Could you send me the dll that you are using perhaps?
Also is there anything in particular you need to do to use the dll in vb?

Cheers
Jas
darkman010@hotmail.com
 
Since the DLL is not a COM/ActiveX/ATL DLL, you will not be able to reference it in VB. In is simply an export API that you are after. What is the error that you are getting when you try to load the DDLL (i.e. LoadLibrary). Also, check err.lastDLLError for more error info when you called the loadlibrary API. - Jeff Marler B-)
 
I was searching for a similar thing that I got into this place, searching over. I am new this but with VC++ in hand just tried to compile the hooks.dll, I have created a new workspace with a win32/dll project called hooks. The source files are exports.def, main.cpp, and the header file is mian.h, As I compile, the project adds a external dependency to file basetsd.h, But..it doesn't compile, it gives these errors.
===========
Compiling...
main.cpp
Linking...
Creating library Debug/hooks.lib and object Debug/hooks.exp
LIBCMTD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Debug/hooks.dll : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

hooks.dll - 2 error(s), 0 warning(s)
===========
In project settings it is default, not using MFC, could somebody please list the proper steps...

Regards

Arijit
 
How to retrive video data from video card and display it. How to see the video from other computer that connected to LAN
 
Arijit
This thread is old and I do not know if experts such as Jeff Marler and Lucky Luke are still monitoring this thread. If you do not hear from them within next few days, you may re-post your message as a new thread. BTW, I would like to know the result also.
fred
 
Thanks fh for the tip, it seems that yours and mine objective in designing a keyboard remapper is same to the pinpoint, and both of us are not 'great' at vc++.

Regards
Arijit
 
arijit,
Regarding your problem, your code is fine since it did compile. The problem that you are having is the fact that you can not link the compiled code modules. This is caused by your library references. To correct this, select the project option on the toolbar and then select Settings. On the form that appears, select the Link tab and where it shows the Object/Library Modules, you will need to add your module (LIBCMTD.lib). That should take care of your problem. - Jeff Marler B-)
 
Thanks JMarler,

For the tip, I tried this one but did not help, I tried in the net over and in different places there are different solutions. None worked. However one try helped. I changed Build->active config to win32-release and compiled and hooks.dll compiled without any error. Don't know whether it is correct though.

Now from VB project it can load and I tested with just simple msgbox chk from the VB code in this thread.

Private Sub pctHook_KeyUp(KeyCode As Integer, Shift As Integer)
If KeyCode = 65 Then
msgbox &quot;hello&quot;
End If
End Sub

And this one worked, and so the dll must have been loaded correct from VB. I then made an .exe and run it, I checked in 2-3 applications the wok is system wide. There are some issues and queries though -

1) I found the Capslock goig tizzy, With Wordpad running and the keyboard.exe in background, as I pressd Capslock it was functioing but CapsLock light started flickering....I am using HP Brio PIII500 / 128 MB RAM.

2) The alt keys were not functiong, for example Alt+0202 produced no results, This I checked with NumLock of or on..

3) I was wondering after succesful operation how can the replacement be returned. For example in my example if I would like to produce letter P when I type A, how would I replace teh keycoade, Also as for fh's original query how can queded replacement be made, that is a sequence of A+E monitored and the ascii 198 is produced Æ or the lower one æ depending on whether shift was pressed or not..

4) Instead of the background app popping up here and there how can it be made to run in Taskbar as a TSR application. I know this is big but if some resource is available.

Regards

Arijit
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top