#define _WIN32_WINNT 0x500 #include #include //#define NXDEBUG #ifdef NXDEBUG #include #endif TCHAR g_prog_dir[MAX_PATH*2]; DWORD g_prog_dir_len; HHOOK g_khook; HANDLE g_hEvent; int mode_3s = 0; static void cswSetLayoutRot(HWND hWnd, int isCtrl) { if (isCtrl) PostMessage(hWnd,WM_INPUTLANGCHANGEREQUEST,0,(LPARAM)HKL_PREV); else PostMessage(hWnd,WM_INPUTLANGCHANGEREQUEST,0,(LPARAM)HKL_NEXT); } static void cswSetLayout(HWND hWnd, int isCtrl) { if (!mode_3s) return cswSetLayoutRot(hWnd, isCtrl); HKL layouts[3]; int r = GetKeyboardLayoutList(3, layouts); if (r != 3) return cswSetLayoutRot(hWnd, isCtrl); HKL current = GetKeyboardLayout(GetWindowThreadProcessId(hWnd, NULL)); #ifdef NXDEBUG char buf[1000]; _snprintf(buf, sizeof(buf), "current=%lx, layouts[0]=%lx, layouts[1]=%lx, layouts[2]=%lx\n", (long)current, (long)layouts[0], (long)layouts[1], (long)layouts[2]); OutputDebugStringA(buf); #endif if (current == layouts[0]) { PostMessage(hWnd, WM_INPUTLANGCHANGEREQUEST, 0, (LPARAM)(isCtrl ? layouts[2] : layouts[1])); } else if (current == layouts[1]) { PostMessage(hWnd, WM_INPUTLANGCHANGEREQUEST, 0, (LPARAM)(isCtrl ? layouts[2] : layouts[0])); } else { PostMessage(hWnd, WM_INPUTLANGCHANGEREQUEST, 0, (LPARAM)(isCtrl ? layouts[1] : layouts[0])); } } LRESULT CALLBACK KbdHook(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode<0) return CallNextHookEx(g_khook, nCode, wParam, lParam); if (nCode==HC_ACTION) { KBDLLHOOKSTRUCT *ks=(KBDLLHOOKSTRUCT*)lParam; if (ks->vkCode==VK_CAPITAL) { int shs = 65535 & GetKeyState(VK_SHIFT); int cts = 65535 & GetKeyState(VK_CONTROL); #ifdef NXDEBUG int cls = 65535 & GetKeyState(VK_CAPITAL); char buf[1000]; sprintf(buf, "KbdHook: nCode=%d wParam=%x lParam=%lx vkCode=%d cls=%x shs=%x\n", nCode, (int)wParam, (long)lParam, (int)ks->vkCode, (int)cls, (int)shs); OutputDebugStringA(buf); #endif if ((shs & 0x8000) != 0) { #ifdef NXDEBUG OutputDebugStringA("seeing original Caps request, passing by\n"); #endif goto skip; } if (wParam==WM_KEYDOWN) { #ifdef NXDEBUG OutputDebugStringA("seeing Caps-as-language, sending language change request\n"); #endif HWND hWnd=GetForegroundWindow(); if (hWnd) { cswSetLayout(hWnd, ((cts & 0x8000) != 0)); } } return 1; } } skip: return CallNextHookEx(g_khook,nCode,wParam,lParam); } void failedx(const TCHAR *msg) { MessageBox(NULL,msg,_T("Error"),MB_OK|MB_ICONERROR); ExitProcess(1); } void failed(const TCHAR *msg) { DWORD fm; TCHAR *msg1,*msg2; const TCHAR *args[2]; fm=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM| FORMAT_MESSAGE_IGNORE_INSERTS, NULL,GetLastError(),0,(LPTSTR)&msg1,0,NULL); if (fm==0) ExitProcess(1); args[0]=msg; args[1]=msg1; fm=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_STRING| FORMAT_MESSAGE_ARGUMENT_ARRAY, _T("%1: %2"),0,0,(LPTSTR)&msg2,0,(va_list*)&args[0]); if (fm==0) ExitProcess(1); MessageBox(NULL,msg2,_T("Error"),MB_OK|MB_ICONERROR); ExitProcess(1); } void CALLBACK TimerCb(HWND hWnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime) { if (WaitForSingleObject(g_hEvent,0)==WAIT_OBJECT_0) PostQuitMessage(0); } int WINAPI CALLBACK WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { MSG msg; DWORD sz; BOOL fQuit=FALSE; TCHAR *cmd; cmd=GetCommandLine(); sz=lstrlen(cmd); if (sz>2 && (lstrcmp(cmd+sz-2,_T(" q"))==0) || (lstrcmp(cmd+sz-2,_T(" Q"))==0)) fQuit=TRUE; if (sz>2 && (lstrcmp(cmd+sz-3,_T(" 3s"))==0) || (lstrcmp(cmd+sz-3,_T(" 3S"))==0)) mode_3s = TRUE; g_hEvent=CreateEvent(NULL,TRUE,FALSE,_T("HaaliLSwitch")); if (g_hEvent==NULL) failed(_T("CreateEvent()")); if (GetLastError()==ERROR_ALREADY_EXISTS) { if (fQuit) { SetEvent(g_hEvent); goto quit; } failedx(_T("CPSwitch or LSwitch is already running!")); } if (fQuit) failedx(_T("CPSwitch or LSwitch is not running!")); sz=GetModuleFileName(NULL,g_prog_dir,MAX_PATH); if (sz==0) failed(_T("GetModuleFileName()")); if (sz==MAX_PATH) failedx(_T("Module file name is too long.")); while (sz>0 && g_prog_dir[sz-1]!=_T('\\')) --sz; g_prog_dir_len=sz; if (SetTimer(NULL,0,500,TimerCb)==0) failed(_T("SetTimer()")); g_khook=SetWindowsHookEx(WH_KEYBOARD_LL,KbdHook,GetModuleHandle(0),0); if (g_khook==0) failed(_T("SetWindowsHookEx()")); while (GetMessage(&msg,0,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } UnhookWindowsHookEx(g_khook); quit: CloseHandle(g_hEvent); ExitProcess(0); }