1 // xkeymacsdll.cpp : Defines the initialization routines for the DLL.
\r
4 #include "xkeymacsdll.h"
\r
6 #include "Commands.h"
\r
7 #include "CmdTable.h"
\r
9 #include "TSFHandler.h"
\r
10 #include "../xkeymacs/resource.h"
\r
16 #define new DEBUG_NEW
\r
18 static char THIS_FILE[] = __FILE__;
\r
21 static AFX_EXTENSION_MODULE XkeymacsdllDLL = { NULL, NULL };
\r
23 static HINSTANCE g_hDllInst = NULL;
\r
25 extern "C" int APIENTRY
\r
26 DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
\r
28 g_hDllInst = hInstance;
\r
30 // Remove this if you use lpReserved
\r
31 UNREFERENCED_PARAMETER(lpReserved);
\r
34 case DLL_PROCESS_ATTACH:
\r
35 TRACE0("XKEYMACSDLL.DLL Initializing!\n");
\r
37 // Extension DLL one-time initialization
\r
38 if (!AfxInitExtensionModule(XkeymacsdllDLL, hInstance)) {
\r
42 // Insert this DLL into the resource chain
\r
43 // NOTE: If this Extension DLL is being implicitly linked to by
\r
44 // an MFC Regular DLL (such as an ActiveX Control)
\r
45 // instead of an MFC application, then you will want to
\r
46 // remove this line from DllMain and put it in a separate
\r
47 // function exported from this Extension DLL. The Regular DLL
\r
48 // that uses this Extension DLL should then explicitly call that
\r
49 // function to initialize this Extension DLL. Otherwise,
\r
50 // the CDynLinkLibrary object will not be attached to the
\r
51 // Regular DLL's resource chain, and serious problems will
\r
55 new CDynLinkLibrary(XkeymacsdllDLL);
\r
57 catch (CMemoryException* e) {
\r
59 // CUtils::Log("DllMain: 'new' threw an exception");
\r
63 case DLL_THREAD_ATTACH:
\r
65 case DLL_PROCESS_DETACH:
\r
66 TRACE0("XKEYMACSDLL.DLL Terminating!\n");
\r
67 // Terminate the library before destructors are called
\r
68 AfxTermExtensionModule(XkeymacsdllDLL);
\r
69 CXkeymacsDll::ReleaseKeyboardHook();
\r
72 case DLL_THREAD_DETACH:
\r
73 CXkeymacsDll::ReleaseKeyboardHook();
\r
80 //////////////////////////////////////////////////////////////////////
\r
81 // CXkeymacsDll Class
\r
82 //////////////////////////////////////////////////////////////////////
\r
84 #pragma data_seg(".xkmcs")
\r
85 Config CXkeymacsDll::m_Config = {0};
\r
86 bool CXkeymacsDll::m_bEnableKeyboardHook = false;
\r
87 bool CXkeymacsDll::m_bHook = true;
\r
88 int CXkeymacsDll::m_nAccelerate = 0;
\r
89 int CXkeymacsDll::m_nKeyboardSpeed = 31;
\r
90 HCURSOR CXkeymacsDll::m_hCurrentCursor = NULL;
\r
91 BOOL CXkeymacsDll::m_bCursor = FALSE;
\r
92 HCURSOR CXkeymacsDll::m_hCursor[MAX_STATUS] = {'\0'};
\r
95 AppConfig* CXkeymacsDll::m_CurrentConfig = NULL;
\r
96 BYTE (*CXkeymacsDll::m_CmdID)[MAX_KEY];
\r
97 char (*CXkeymacsDll::m_FuncID)[MAX_KEY];
\r
98 HHOOK CXkeymacsDll::m_hHookCallWnd = NULL;
\r
99 HHOOK CXkeymacsDll::m_hHookCallWndRet = NULL;
\r
100 HHOOK CXkeymacsDll::m_hHookGetMessage = NULL;
\r
101 HHOOK CXkeymacsDll::m_hHookShell = NULL;
\r
102 DWORD CXkeymacsDll::m_nHookAltRelease = 0;
\r
103 BOOL CXkeymacsDll::m_bRightShift = FALSE;
\r
104 BOOL CXkeymacsDll::m_bRightControl = FALSE;
\r
105 BOOL CXkeymacsDll::m_bRightAlt = FALSE;
\r
106 TCHAR CXkeymacsDll::m_M_xTip[128] = "";
\r
107 BYTE CXkeymacsDll::m_nOriginal[MAX_COMMAND_TYPE][MAX_KEY] = {'\0'};
\r
108 CList<CClipboardSnap *, CClipboardSnap *> CXkeymacsDll::m_oKillRing;
\r
109 int CXkeymacsDll::m_nKillRing = 0;
\r
110 KbdMacro* CXkeymacsDll::m_kbdMacro = NULL;
\r
112 BOOL CXkeymacsDll::SaveConfig()
\r
114 TCHAR szTmp[MAX_PATH];
\r
115 if (!GetTempPath(MAX_PATH, szTmp))
\r
117 if (_tmakepath_s(szTmp, NULL, szTmp, _T("xkeymacs"), _T("tmp")))
\r
119 HANDLE hFile = CreateFile(szTmp, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
\r
120 if (hFile == INVALID_HANDLE_VALUE)
\r
123 BOOL res = WriteFile(hFile, &m_Config, sizeof(m_Config), &written, NULL) && written == sizeof(m_Config);
\r
124 CloseHandle(hFile);
\r
128 BOOL CXkeymacsDll::LoadConfig()
\r
130 TCHAR szTmp[MAX_PATH];
\r
131 if (!GetTempPath(MAX_PATH, szTmp))
\r
133 if (_tmakepath_s(szTmp, NULL, szTmp, _T("xkeymacs"), _T("tmp")))
\r
135 HANDLE hFile = CreateFile(szTmp, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
\r
136 if (hFile == INVALID_HANDLE_VALUE)
\r
139 BOOL res = ReadFile(hFile, &m_Config, sizeof(m_Config), &read, NULL) && read == sizeof(m_Config);
\r
140 CloseHandle(hFile);
\r
144 void CXkeymacsDll::SetConfig(const Config& config)
\r
149 void CXkeymacsDll::SetHooks()
\r
151 m_hHookCallWnd = SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, g_hDllInst, 0);
\r
152 m_hHookCallWndRet = SetWindowsHookEx(WH_CALLWNDPROCRET, CallWndRetProc, g_hDllInst, 0);
\r
153 m_hHookGetMessage = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, g_hDllInst, 0);
\r
154 m_hHookShell = SetWindowsHookEx(WH_SHELL, ShellProc, g_hDllInst, 0);
\r
155 m_bEnableKeyboardHook = true;
\r
158 void CXkeymacsDll::SetKeyboardHook(DWORD threadId)
\r
160 if (!TLS::GetKeyboardHook())
\r
161 TLS::PutKeyboardHook(SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hDllInst, threadId ? threadId : GetCurrentThreadId()));
\r
164 inline void unhook(HHOOK &hh)
\r
167 UnhookWindowsHookEx(hh);
\r
171 void CXkeymacsDll::ResetHooks()
\r
177 void CXkeymacsDll::ReleaseHooks()
\r
179 unhook(m_hHookCallWnd);
\r
180 unhook(m_hHookCallWndRet);
\r
181 unhook(m_hHookGetMessage);
\r
182 unhook(m_hHookShell);
\r
183 m_bEnableKeyboardHook = false;
\r
186 void CXkeymacsDll::ReleaseKeyboardHook()
\r
188 HHOOK hook = TLS::GetKeyboardHook();
\r
191 UnhookWindowsHookEx(hook);
\r
194 void CXkeymacsDll::SetHookStateDirect(bool enable)
\r
199 void CXkeymacsDll::ToggleHookState()
\r
201 SetHookState(!m_bHook);
\r
204 void CXkeymacsDll::SetHookState(bool enable)
\r
208 msg.Type = IPC32_HOOKSTATE;
\r
209 msg.Enable = enable;
\r
210 if (!CallNamedPipe(m_Config.PipeNameForIPC32, &msg, offsetof(IPC32Message, Enable) + sizeof(bool), &ack, sizeof(DWORD), &read, NMPWAIT_NOWAIT))
\r
211 CUtils::Log(_T("SetHookState: CallNamedPipe failed. (%d)"), GetLastError());
\r
216 bool CXkeymacsDll::GetHookState()
\r
221 void CXkeymacsDll::ShowHookState()
\r
223 IconState main = { MAIN_ICON, STATUS_ENABLE };
\r
225 if (CCommands::IsTemporarilyDisableXKeymacs()) {
\r
226 main.State = STATUS_DISABLE_TMP;
\r
227 m_hCurrentCursor = m_hCursor[STATUS_DISABLE_TMP];
\r
229 main.State = STATUS_ENABLE;
\r
230 m_hCurrentCursor = m_hCursor[STATUS_ENABLE];
\r
233 main.State = STATUS_DISABLE_WOCQ;
\r
234 if (m_CurrentConfig->SettingStyle == SETTING_DISABLE ||
\r
235 (!_tcsicmp(m_CurrentConfig->AppName, _T("Default")) && CUtils::IsDefaultIgnoreApplication())) {
\r
236 main.State = STATUS_DISABLE;
\r
237 m_hCurrentCursor = m_hCursor[STATUS_DISABLE];
\r
239 SendIconMessage(&main, 1);
\r
243 LRESULT CALLBACK CXkeymacsDll::CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
\r
247 const CWPSTRUCT *cwps = reinterpret_cast<CWPSTRUCT *>(lParam);
\r
248 switch (cwps->message) {
\r
249 case WM_IME_STARTCOMPOSITION:
\r
251 CUtils::Log(_T("WM_IME_STARTCOMPOSITION"));
\r
255 case WM_IME_ENDCOMPOSITION:
\r
257 CUtils::Log(_T("WM_IME_ENDCOMPOSITION"));
\r
259 SetIMEState(false);
\r
262 if (cwps->hwnd == GetForegroundWindow() || GetWindowLong(cwps->hwnd, GWL_STYLE) == 0x56000000) {
\r
263 SetIMEState(false);
\r
267 case WM_NCACTIVATE:
\r
268 if (cwps->wParam && cwps->hwnd == GetForegroundWindow()) {
\r
269 SetIMEState(false);
\r
275 return CallNextHookEx(NULL, nCode, wParam, lParam);
\r
278 LRESULT CALLBACK CXkeymacsDll::CallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)
\r
282 const CWPRETSTRUCT *cwprets = reinterpret_cast<CWPRETSTRUCT *>(lParam);
\r
283 switch (cwprets->message) {
\r
285 if (cwprets->hwnd == GetForegroundWindow())
\r
286 InitKeyboardProc();
\r
293 return CallNextHookEx(NULL, nCode, wParam, lParam);
\r
296 LRESULT CALLBACK CXkeymacsDll::GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
\r
300 const MSG *msg = reinterpret_cast<MSG *>(lParam);
\r
301 switch (msg->message) {
\r
302 case WM_IME_STARTCOMPOSITION:
\r
304 CUtils::Log(_T("WM_IME_STARTCOMPOSITION"));
\r
308 case WM_IME_ENDCOMPOSITION:
\r
310 CUtils::Log(_T("WM_IME_ENDCOMPOSITION"));
\r
312 SetIMEState(false);
\r
316 return CallNextHookEx(NULL, nCode, wParam, lParam);
\r
319 void CXkeymacsDll::SetIMEState(bool on)
\r
321 AppName::SetIMEState(on);
\r
322 InitKeyboardProc();
\r
325 LRESULT CALLBACK CXkeymacsDll::ShellProc(int nCode, WPARAM wParam, LPARAM lParam)
\r
327 if (nCode == HSHELL_WINDOWACTIVATED) {
\r
328 SetKeyboardHook(GetWindowThreadProcessId(reinterpret_cast<HWND>(wParam), NULL));
\r
329 TCHAR className[CLASS_NAME_LENGTH];
\r
330 GetClassName(reinterpret_cast<HWND>(wParam), className, CLASS_NAME_LENGTH);
\r
331 if (!_tcsicmp(className, _T("ConsoleWindowClass"))) {
\r
332 AppName::SetIMEState(false);
\r
333 InitKeyboardProc();
\r
337 return CallNextHookEx(NULL, nCode, wParam, lParam);
\r
340 void CXkeymacsDll::InitKeyboardProc()
\r
343 TSFHandler::InitSink();
\r
344 if (m_CurrentConfig == NULL ||
\r
345 _tcsnicmp(m_CurrentConfig->AppName, AppName::GetAppName(), 0xF) || // PROCESSENTRY32 has only 0xF bytes of Name
\r
346 !CUtils::IsMatchWindowText(m_CurrentConfig->WindowText)) {
\r
347 m_CurrentConfig = NULL;
\r
348 for (int nAppID = 0; nAppID < MAX_APP; ++nAppID) {
\r
349 AppConfig* appConfig = m_Config.AppConfig + nAppID;
\r
350 if (_tcsnicmp(appConfig->AppName, AppName::GetAppName(), 0xF) || !CUtils::IsMatchWindowText(appConfig->WindowText))
\r
352 if (m_CurrentConfig == NULL)
\r
353 m_CurrentConfig = appConfig;
\r
355 LPCTSTR curText = m_CurrentConfig->WindowText;
\r
356 LPCTSTR newText = appConfig->WindowText;
\r
357 int curType = CUtils::GetWindowTextType(curText);
\r
358 int newType = CUtils::GetWindowTextType(newText);
\r
359 if (curType < newType || curType == newType && _tcscmp(curText, newText) <= 0)
\r
360 m_CurrentConfig = appConfig;
\r
363 if (m_CurrentConfig == NULL)
\r
364 m_CurrentConfig = GetAppConfig(_T("Default"), m_Config.AppConfig);
\r
366 if (m_CurrentConfig->SettingStyle != SETTING_DISABLE &&
\r
367 (_tcsicmp(m_CurrentConfig->AppName, _T("Default")) || !CUtils::IsDefaultIgnoreApplication()) &&
\r
368 !AppName::GetIMEState() && CUtils::IsDialog() && m_CurrentConfig->UseDialogSetting)
\r
369 // Use Dialog Setting
\r
370 m_CurrentConfig = GetAppConfig(_T("Dialog"), m_CurrentConfig);
\r
371 m_CmdID = m_CurrentConfig->CmdID;
\r
372 m_FuncID = m_CurrentConfig->FuncID;
\r
374 IconState msg[3] = {
\r
375 {CX_ICON, OFF_ICON, ""},
\r
376 {MX_ICON, OFF_ICON, ""},
\r
377 {META_ICON, OFF_ICON, ""}
\r
379 SendIconMessage(msg, 3);
\r
380 CCommands::SetMark(FALSE);
\r
381 CCommands::SetTemporarilyDisableXKeymacs(FALSE);
\r
382 CCommands::Reset();
\r
385 AppConfig* CXkeymacsDll::GetAppConfig(LPCTSTR name, AppConfig* fallback)
\r
387 for (int i = 0; i < MAX_APP; ++i)
\r
388 if (!_tcsicmp(m_Config.AppConfig[i].AppName, name))
\r
389 return m_Config.AppConfig + i;
\r
393 LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
\r
395 BYTE nOrigKey = static_cast<BYTE>(wParam);
\r
396 bool bRelease = (HIWORD(lParam) & KF_UP) != 0;
\r
397 bool bExtended = (HIWORD(lParam) & KF_EXTENDED) != 0;
\r
398 BYTE nKey = nOrigKey;
\r
400 static BOOL bLocked = FALSE;
\r
401 static const BYTE RECURSIVE_KEY = 0x07;
\r
402 static int (*fLastCommand)() = NULL;
\r
403 static BYTE nOneShotModifier[MAX_KEY] = {'\0'};
\r
404 static BOOL bCherryOneShotModifier = FALSE;
\r
406 // CUtils::Log(_T("nCode = %#x, nKey = %#x, lParam = %#x"), nCode, nOrigKey, lParam);
\r
408 if (!m_bEnableKeyboardHook || m_CurrentConfig == NULL || CUtils::IsXkeymacs() ||
\r
409 nCode < 0 || nCode == HC_NOREMOVE)
\r
410 return CallNextHookEx(NULL, nCode, wParam, lParam);
\r
412 // CUtils::Log(_T("nKey = %#x, ext = %d, rel = %d, pre = %d, %#hx, %#hx"), nOrigKey,
\r
413 // (HIWORD(lParam) & KF_EXTENDED) ? 1 : 0, (HIWORD(lParam) & KF_UP) ? 1 : 0, (HIWORD(lParam) & KF_REPEAT) ? 1 : 0,
\r
414 // GetKeyState(nOrigKey), GetAsyncKeyState(nOrigKey));
\r
416 if (nOrigKey == RECURSIVE_KEY) {
\r
418 goto HOOK_RECURSIVE_KEY;
\r
420 goto RECURSIVE_COMMAND;
\r
423 CancelMarkWithShift(nOrigKey, bRelease);
\r
427 nKey = bExtended ? VK_RCONTROL : VK_LCONTROL;
\r
430 nKey = bExtended ? VK_RMENU : VK_LMENU;
\r
433 nKey = bExtended ? VK_RSHIFT : VK_LSHIFT;
\r
438 switch (nOrigKey) {
\r
440 if (m_nHookAltRelease) {
\r
441 if (m_nHookAltRelease & ~HOOK_ALT_LATER)
\r
442 m_nHookAltRelease--;
\r
443 else if (m_nHookAltRelease & HOOK_ALT_LATER)
\r
444 m_nHookAltRelease = 0;
\r
451 for (int i = 0; i < MAX_COMMAND_TYPE; ++i) {
\r
452 int (*fCommand)() = CmdTable::Command(m_CmdID[i][nKey]);
\r
453 if (fCommand && !(nOrigKey == VK_MENU && fCommand == CCommands::MetaAlt))
\r
457 if (nOneShotModifier[nKey]) {
\r
458 ReleaseKey(nOneShotModifier[nKey]);
\r
459 nOneShotModifier[nKey] = 0;
\r
460 if (bCherryOneShotModifier) {
\r
461 bCherryOneShotModifier = FALSE;
\r
468 if (m_CurrentConfig->SettingStyle == SETTING_DISABLE)
\r
471 // Do Nothing for Meadow, Mule for Win32, ... if those use default setting.
\r
472 if (!_tcsicmp(m_CurrentConfig->AppName, _T("Default")) && CUtils::IsDefaultIgnoreApplication())
\r
475 switch (IsPassThrough(nKey)) {
\r
476 case GOTO_DO_NOTHING:
\r
484 // set command type
\r
485 int nType = IsDown(VK_SHIFT) * SHIFT | IsControl() * CONTROL | IsMeta() * META | CCommands::bC_x() * CONTROLX;
\r
486 // Ignore undefined C-x ?
\r
487 if (nType & CONTROLX && m_CmdID[nType][nKey] == 0 && m_FuncID[nType][nKey] < 0) {
\r
488 if (m_CurrentConfig->IgnoreUndefC_x) {
\r
489 CCommands::Reset(GOTO_HOOK);
\r
492 nType &= ~CONTROLX;
\r
494 // Ignore undefined Meta Ctrl+?
\r
495 if (CCommands::bM_() && nType & CONTROL) {
\r
496 if (m_CmdID[nType][nKey] == 0 && m_FuncID[nType][nKey] < 0) {
\r
497 if (m_CurrentConfig->IgnoreUndefMetaCtrl) {
\r
498 if (CheckOriginal(CONTROL, nKey))
\r
500 CCommands::Reset(GOTO_HOOK);
\r
507 int nVirtualType = GetModifierState(FALSE);
\r
508 if (nOrigKey == VK_CONTROL)
\r
509 nVirtualType &= ~CONTROL;
\r
510 if (nOrigKey == VK_MENU)
\r
511 nVirtualType &= ~META;
\r
512 if (CheckOriginal(nVirtualType, nOrigKey))
\r
515 int (*fCommand)() = CmdTable::Command(m_CmdID[nType][nKey]);
\r
516 if (fCommand == CCommands::EnableOrDisableXKeymacs) {
\r
520 if (fCommand == CCommands::EnableXKeymacs) {
\r
521 SetHookState(true);
\r
524 if (fCommand == CCommands::DisableXKeymacs) {
\r
525 SetHookState(false);
\r
531 if (CCommands::bM_x() && !bRelease) {
\r
532 static size_t index = 0;
\r
533 static TCHAR szPath[MAX_PATH] = {'\0'};
\r
534 if (fCommand == CCommands::BackwardChar) {
\r
538 } else if (fCommand == CCommands::BeginningOfLine) {
\r
541 } else if (fCommand == CCommands::DeleteBackwardChar) {
\r
544 memmove(szPath + index, szPath + index + 1, MAX_PATH - index);
\r
548 } else if (fCommand == CCommands::DeleteChar) {
\r
549 if (index < _tcslen(szPath)) {
\r
550 memmove(szPath + index, szPath + index + 1, MAX_PATH - index);
\r
554 } else if (fCommand == CCommands::EndOfLine) {
\r
555 index = _tcslen(szPath);
\r
557 } else if (fCommand == CCommands::ForwardChar) {
\r
558 if (index < _tcslen(szPath))
\r
561 } else if (fCommand == CCommands::KeyboardQuit) {
\r
562 CCommands::bM_x(FALSE);
\r
564 memset(szPath, 0, sizeof(szPath));
\r
566 } else if (nKey == VK_RETURN || fCommand == CCommands::Newline) {
\r
568 CCommands::bM_x(FALSE);
\r
570 memset(szPath, 0, sizeof(szPath));
\r
572 } else if (nKey && index < MAX_PATH - 1) {
\r
573 if (SHORT ascii = ConvVkey(nKey | (static_cast<BYTE>(IsDown(VK_SHIFT, FALSE)) << 8), 1)) {
\r
574 // CUtils::Log("M-x: %#X (%c), %#X (%c)", nKey, nKey, ascii, ascii);
\r
575 if (index < _tcslen(szPath))
\r
576 memmove(szPath + index + 1, szPath + index, MAX_PATH - index - 1);
\r
577 szPath[index++] = static_cast<TCHAR>(ascii);
\r
578 // CUtils::Log("M-x: %c(%#04x)", ascii, ascii);
\r
585 if (CCommands::bC_u() && nType == NONE) {
\r
586 if ('0' <= nKey && nKey <= '9') {
\r
587 CCommands::NumericArgument(nKey - '0');
\r
590 if (nKey == VK_OEM_MINUS) {
\r
591 CCommands::NumericArgumentMinus();
\r
596 #define OneShotModifier(type, vk, mod) \
\r
597 if (CmdTable::Command(m_CmdID[nType & ~type][nKey]) == CCommands::OneShotModifier ## mod || \
\r
598 CmdTable::Command(m_CmdID[nType][nKey]) == CCommands::OneShotModifier ## mod ## Repeat) { \
\r
599 nOneShotModifier[nKey] = vk; \
\r
601 bCherryOneShotModifier = TRUE; \
\r
603 } else if (CmdTable::Command(m_CmdID[nType & ~CONTROL][nKey]) == CCommands::OneShotModifier ## mod ## Repeat) { \
\r
605 bCherryOneShotModifier = FALSE; \
\r
610 OneShotModifier(CONTROL, VK_CONTROL, Ctrl);
\r
611 OneShotModifier(META, VK_MENU, Alt);
\r
612 OneShotModifier(SHIFT, VK_SHIFT, Shift);
\r
614 for (i = 0; i < MAX_KEY; ++i)
\r
615 if (nOneShotModifier[i] == nOrigKey)
\r
618 bCherryOneShotModifier = FALSE;
\r
620 int id = m_FuncID[nType][nKey];
\r
621 if (0 <= id && id < MAX_FUNCTION) {
\r
623 CCommands::Reset(GOTO_HOOK);
\r
628 if (nOrigKey == VK_CONTROL || nOrigKey == VK_MENU || nOrigKey == VK_SHIFT)
\r
630 if (!(nType & SHIFT)) {
\r
631 if (CCommands::IsSetMark()) {
\r
632 if (CCommands::MoveCaret(nKey, nType & CONTROL) != CONTINUE) {
\r
633 CCommands::ClearNumericArgument();
\r
636 CCommands::SetMark(FALSE);
\r
639 if (1 < CCommands::GetNumericArgument()) {
\r
640 Kdu(nKey, CCommands::GetNumericArgument());
\r
641 CCommands::ClearNumericArgument();
\r
647 if (CCommands::IsTemporarilyDisableXKeymacs() && fCommand != CCommands::KeyboardQuit) {
\r
648 CCommands::SetTemporarilyDisableXKeymacs(FALSE);
\r
652 m_bRightControl = IsDown(VK_RCONTROL, FALSE);
\r
653 m_bRightAlt = IsDown(VK_RMENU, FALSE);
\r
654 m_bRightShift = IsDown(VK_RSHIFT, FALSE);
\r
657 goto HOOK_RECURSIVE_KEY;
\r
659 fLastCommand = fCommand;
\r
661 switch (fLastCommand()) {
\r
662 case GOTO_DO_NOTHING:
\r
668 case GOTO_RECURSIVE:
\r
679 SetModifierIcons();
\r
681 m_kbdMacro->Record(nKey, bRelease);
\r
682 return CallNextHookEx(NULL, nCode, wParam, lParam);
\r
685 Kdu(RECURSIVE_KEY, 1, FALSE);
\r
688 CCommands::SetLastCommand(fLastCommand);
\r
691 SetModifierIcons();
\r
692 HOOK_RECURSIVE_KEY:
\r
696 void CXkeymacsDll::CancelMarkWithShift(byte nKey, bool bRelease)
\r
698 static bool bShift;
\r
699 if (IsDepressedShiftKeyOnly(nKey)) {
\r
702 CCommands::SetMark(false);
\r
711 static bool IsShift(byte bVk)
\r
713 return bVk == VK_SHIFT || bVk == VK_LSHIFT || bVk == VK_RSHIFT;
\r
716 bool CXkeymacsDll::IsDepressedShiftKeyOnly(byte nKey)
\r
718 if (!IsShift(nKey))
\r
720 for (byte bVk = 1; bVk < 255; bVk++) {
\r
729 int CXkeymacsDll::IsPassThrough(BYTE nKey)
\r
732 const BYTE *pnID = m_CmdID[NONE];
\r
734 if (IsDown(bVk) && CmdTable::Command(pnID[bVk]) == CCommands::PassThrough) {
\r
737 return GOTO_DO_NOTHING;
\r
743 void CXkeymacsDll::InvokeM_x(LPCTSTR szPath)
\r
745 // CUtils::Log("M-x: szPath=_%s_", szPath);
\r
746 int (*fCommand)() = NULL;
\r
747 for (int i = 0; i < MAX_COMMAND; ++i)
\r
748 if (_tcsicmp(szPath, CmdTable::Name(i)) == 0) {
\r
749 fCommand = CmdTable::Command(i);
\r
753 // CUtils::Log("M-x: Command: _%s_", Commands[i].szCommandName);
\r
756 // CUtils::Log("M-x: Path: _%s_", szPath);
\r
757 ShellExecute(NULL, NULL, szPath, NULL, NULL, SW_SHOWNORMAL);
\r
761 void CXkeymacsDll::SetModifierIcons()
\r
763 IconState icons[6] = {
\r
764 {MX_ICON, CCommands::bM_x(), ""},
\r
765 {CX_ICON, CCommands::bC_x(), ""},
\r
766 {META_ICON, CCommands::bM_(), ""},
\r
767 {SHIFT_ICON, IsDown(VK_SHIFT, FALSE), ""},
\r
768 {CTRL_ICON, IsControl(), ""},
\r
769 {ALT_ICON, IsDown(VK_MENU, FALSE), ""}
\r
771 _tcscpy_s(icons[0].Tip, m_M_xTip);
\r
772 SendIconMessage(icons, 6);
\r
775 void CXkeymacsDll::SetM_xTip(LPCTSTR szPath)
\r
777 _tcscpy_s(m_M_xTip, "M-x LED");
\r
778 if (szPath && _tcslen(szPath) < 128 - 5)
\r
779 _stprintf_s(m_M_xTip, "M-x %s", szPath);
\r
782 void CXkeymacsDll::SendIconMessage(IconState *state, int num)
\r
786 msg.Type = IPC32_ICON;
\r
787 memcpy(msg.IconState, state, num * sizeof(IconState));
\r
788 if (!CallNamedPipe(m_Config.PipeNameForIPC32, &msg, offsetof(IPC32Message, IconState) + sizeof(IconState) * num, &ack, sizeof(DWORD), &read, NMPWAIT_NOWAIT)) {
\r
790 CUtils::Log(_T("SendIconMessage: CallNamedPipe failed. (%d)"), GetLastError());
\r
795 void CXkeymacsDll::Kdu(BYTE bVk, DWORD n, BOOL bOriginal)
\r
798 DepressKey(bVk, bOriginal);
\r
803 void CXkeymacsDll::DepressKey(BYTE bVk, BOOL bOriginal) // bVk is virtual-key code, MSDN said
\r
806 // CUtils::Log(_T("i: %x, %d, %d, %d, %d, %d, %d, %d, %d"), bVk,
\r
807 // IsDown(VK_CONTROL), IsDown(VK_CONTROL, FALSE), IsDepressedModifier(CCommands::C_), IsDepressedModifier(CCommands::C_, FALSE),
\r
808 // IsDown(VK_MENU), IsDown(VK_MENU, FALSE), IsDepressedModifier(CCommands::MetaAlt), IsDepressedModifier(CCommands::MetaAlt, FALSE));
\r
809 SetOriginal(GetModifierState(), bVk);
\r
811 DoKeybd_event(bVk, 0);
\r
814 void CXkeymacsDll::ReleaseKey(BYTE bVk) // bVk is virtual-key code, MSDN said
\r
816 DoKeybd_event(bVk, KEYEVENTF_KEYUP);
\r
819 void CXkeymacsDll::DoKeybd_event(BYTE bVk, DWORD dwFlags)
\r
823 if (m_bRightControl)
\r
824 dwFlags |= KEYEVENTF_EXTENDEDKEY;
\r
829 dwFlags |= KEYEVENTF_EXTENDEDKEY;
\r
837 if (IsDown(VK_CONTROL, FALSE)) // Break
\r
838 dwFlags |= KEYEVENTF_EXTENDEDKEY;
\r
852 dwFlags |= KEYEVENTF_EXTENDEDKEY;
\r
855 // CUtils::Log(_T("b: %x, %x, %x, %#hx, %#hx"), bVk, dwFlags, GetMessageExtraInfo(), GetKeyState(bVk), GetAsyncKeyState(bVk));
\r
856 keybd_event(bVk, 0, dwFlags, GetMessageExtraInfo());
\r
857 // CUtils::Log(_T("a: %x, %x, %x, %#hx, %#hx"), bVk, dwFlags, GetMessageExtraInfo(), GetKeyState(bVk), GetAsyncKeyState(bVk));
\r
860 void CXkeymacsDll::SetOriginal(UINT nType, BYTE bVk)
\r
862 m_nOriginal[nType & ~SHIFT][bVk]++;
\r
865 int CXkeymacsDll::CheckOriginal(UINT nType, BYTE bVk)
\r
868 if (m_nOriginal[nType][bVk])
\r
869 return m_nOriginal[nType][bVk]--;
\r
873 UINT CXkeymacsDll::GetModifierState(BOOL bPhysicalKey)
\r
876 if (IsDown(VK_SHIFT, bPhysicalKey))
\r
878 if (IsDown(VK_CONTROL, bPhysicalKey))
\r
880 if (IsDown(VK_MENU, bPhysicalKey))
\r
885 void CXkeymacsDll::SetModifierState(UINT after, UINT before)
\r
887 if (after & SHIFT && !(before & SHIFT))
\r
888 DepressKey(VK_SHIFT);
\r
889 else if (!(after & SHIFT) && before & SHIFT)
\r
890 ReleaseKey(VK_SHIFT);
\r
892 if (after & CONTROL && !(before & CONTROL))
\r
893 DepressKey(VK_CONTROL);
\r
894 else if (!(after & CONTROL) && before & CONTROL) {
\r
895 ReleaseKey(VK_CONTROL);
\r
896 UpdateKeyboardState(VK_CONTROL, 0);
\r
900 CUtils::IsVisualCpp() || CUtils::IsVisualStudio() ||
\r
901 CUtils::IsInternetExplorer() || CUtils::IsFirefox() || CUtils::IsChrome();
\r
902 if (after & META && !(before & META)) {
\r
904 m_nHookAltRelease |= HOOK_ALT_LATER;
\r
905 DepressKey(VK_MENU);
\r
906 } else if (!(after & META) && before & META) {
\r
908 ++m_nHookAltRelease;
\r
909 ReleaseKey(VK_MENU);
\r
913 BOOL CXkeymacsDll::UpdateKeyboardState(BYTE bVk, BYTE bState)
\r
915 BYTE ks[256] = {'\0'};
\r
916 if (!GetKeyboardState(ks))
\r
919 return SetKeyboardState(ks);
\r
922 BOOL CXkeymacsDll::IsControl()
\r
924 return CCommands::bC_() || IsDepressedModifier(CCommands::C_);
\r
927 BOOL CXkeymacsDll::IsMeta()
\r
929 return CCommands::bM_() || IsDepressedModifier(CCommands::MetaAlt);
\r
932 BOOL CXkeymacsDll::IsDepressedModifier(int (__cdecl *Modifier)(void), BOOL bPhysicalKey)
\r
935 const BYTE *pnID = m_CmdID[NONE];
\r
941 case 0xf0: // Eisu key. GetAsyncKeyState returns the wrong state of Eisu key.
\r
944 if (IsDown(bVk, bPhysicalKey) && CmdTable::Command(pnID[bVk]) == Modifier)
\r
950 BOOL CXkeymacsDll::IsDown(BYTE bVk, BOOL bPhysicalKey)
\r
952 return bPhysicalKey ? GetAsyncKeyState(bVk) < 0 : GetKeyState(bVk) < 0;
\r
955 void CXkeymacsDll::AddKillRing(BOOL bNewData)
\r
957 if (m_CurrentConfig->KillRingMax == 0) {
\r
961 CClipboardSnap *pSnap = new CClipboardSnap;
\r
962 if( !pSnap ) return;
\r
964 BOOL bCapture = pSnap->Capture();
\r
965 bCapture = pSnap->Capture(); // for "office drawing shape format". Can CClipboardSnap care this problem?
\r
969 m_oKillRing.AddHead(pSnap);
\r
971 if (m_oKillRing.IsEmpty()) {
\r
972 m_oKillRing.AddHead(pSnap);
\r
974 CClipboardSnap *pParent;
\r
975 for (pParent = m_oKillRing.GetHead(); pParent->GetNext(); pParent = pParent->GetNext()) {
\r
978 pParent->SetNext(pSnap);
\r
988 if (m_CurrentConfig->KillRingMax < m_oKillRing.GetCount()) {
\r
989 CClipboardSnap *pSnap = m_oKillRing.GetTail();
\r
992 m_oKillRing.RemoveTail();
\r
996 // Return TRUE if there is another data
\r
997 // Return FALSE if there is no more data
\r
998 CClipboardSnap* CXkeymacsDll::GetKillRing(CClipboardSnap* pSnap, BOOL bForce)
\r
1000 if (m_CurrentConfig->KillRingMax == 0) {
\r
1004 if (m_oKillRing.IsEmpty()) {
\r
1008 m_nKillRing %= m_oKillRing.GetCount();
\r
1011 CClipboardSnap oCurrentSnap;
\r
1012 oCurrentSnap.Capture();
\r
1014 CClipboardSnap *pKillRing = m_oKillRing.GetAt(m_oKillRing.FindIndex(m_nKillRing));
\r
1018 for (; pKillRing->GetNext(); pKillRing = pKillRing->GetNext()) {
\r
1021 if (*pKillRing != oCurrentSnap) {
\r
1027 pSnap = m_oKillRing.GetAt(m_oKillRing.FindIndex(m_nKillRing));
\r
1031 return pSnap->GetNext();
\r
1034 void CXkeymacsDll::IncreaseKillRingIndex(int nKillRing)
\r
1036 m_nKillRing += nKillRing;
\r
1039 bool CXkeymacsDll::GetEnableCUA()
\r
1041 return m_CurrentConfig->EnableCUA;
\r
1044 bool CXkeymacsDll::Get326Compatible()
\r
1046 return m_CurrentConfig->Is326Compatible;
\r
1049 bool CXkeymacsDll::Is106Keyboard()
\r
1051 return m_Config.Is106Keyboard;
\r
1054 void CXkeymacsDll::SetKbMacro(KbdMacro* kbdMacro)
\r
1056 m_kbdMacro = kbdMacro;
\r
1059 // call an original command which is defined in dot.xkeymacs
\r
1060 void CXkeymacsDll::CallFunction(int id)
\r
1062 if (id < 0 || id >= MAX_FUNCTION)
\r
1064 BOOL bM_x = FALSE;
\r
1065 TCHAR szPath[MAX_PATH] = {'\0'};
\r
1066 unsigned int index = 0;
\r
1067 BOOL bInitialized = FALSE;
\r
1068 UINT before = GetModifierState(FALSE);
\r
1070 for (KeyBind *p = m_Config.FuncDefs[id]; p->bVk; ++p) {
\r
1071 int nType = p->nType;
\r
1072 BYTE bVk = p->bVk;
\r
1073 int (*fCommand)() = nType < MAX_COMMAND_TYPE ? CmdTable::Command(m_CmdID[nType][bVk]) : NULL;
\r
1075 if (fCommand == CCommands::ExecuteExtendedCommand)
\r
1077 else if (!bInitialized) {
\r
1078 SetModifierState(0, before);
\r
1079 bInitialized = TRUE;
\r
1081 // CUtils::Log("CallFunction: Command Name: %s", Commands[m_CurrentConfig->CmdID[nType][bVk]].szCommandName);
\r
1082 while (fCommand() == GOTO_RECURSIVE)
\r
1087 if (bVk == VK_RETURN)
\r
1088 InvokeM_x(szPath);
\r
1089 else if (bVk != 0)
\r
1090 szPath[index++] = static_cast<TCHAR>(ConvVkey((bVk | (nType << 8)) & 0x7ff /* drop CONTROLX */, 1));
\r
1093 if (!bInitialized) {
\r
1094 SetModifierState(0, before);
\r
1095 bInitialized = TRUE;
\r
1097 if (nType & WIN_WIN)
\r
1098 DepressKey(VK_LWIN);
\r
1099 if (nType & WIN_CTRL)
\r
1100 DepressKey(VK_CONTROL);
\r
1101 if (nType & WIN_ALT)
\r
1102 DepressKey(VK_MENU);
\r
1103 if (nType & SHIFT)
\r
1104 DepressKey(VK_SHIFT);
\r
1106 int nNextType = (p + 1)->nType;
\r
1107 if (nType & SHIFT && !(nNextType & SHIFT))
\r
1108 ReleaseKey(VK_SHIFT);
\r
1109 if (nType & WIN_ALT && !(nNextType & WIN_ALT))
\r
1110 ReleaseKey(VK_MENU);
\r
1111 if (nType & WIN_CTRL && !(nNextType & WIN_CTRL))
\r
1112 ReleaseKey(VK_CONTROL);
\r
1113 if (nType & WIN_WIN && !(nNextType & WIN_WIN))
\r
1114 ReleaseKey(VK_LWIN);
\r
1118 // If this lines is invoked on M-x, a window transition does not work well.
\r
1119 SetModifierState(before, 0);
\r
1123 SHORT CXkeymacsDll::ConvVkey(SHORT in, int mode)
\r
1125 HKL h = GetKeyboardLayout(0);
\r
1126 if (mode == 0) { // ASCII to VKey and state
\r
1127 SHORT r = VkKeyScanEx(static_cast<TCHAR>(in), h);
\r
1128 if (r < 0) // no key correcpont to the char
\r
1130 return r & 0x7ff; // drop state flags of Hankaku and others
\r
1132 // VKey and state to ASCII
\r
1133 const BYTE down = 0x80;
\r
1134 BYTE state[256] = {0};
\r
1135 if (in & (1 << 8))
\r
1136 state[VK_SHIFT] = down;
\r
1137 if (in & (2 << 8))
\r
1138 state[VK_CONTROL] = down;
\r
1139 if (in & (4 << 8))
\r
1140 state[VK_MENU] = down;
\r
1141 UINT vkey = in & 0xff;
\r
1142 state[vkey] = down;
\r
1144 int r = ToAsciiEx(vkey, MapVirtualKeyEx(vkey, MAPVK_VK_TO_VSC, h), state, &word, 0, h);
\r
1148 return static_cast<SHORT>(word);
\r
1149 return static_cast<SHORT>(word >> 8); // drop a dead key
\r
1152 void CXkeymacsDll::SetAccelerate(int nAccelerate)
\r
1154 m_nAccelerate = nAccelerate;
\r
1157 int CXkeymacsDll::GetAccelerate()
\r
1159 return m_nAccelerate;
\r
1162 void CXkeymacsDll::SetKeyboardSpeed(int nKeyboardSpeed)
\r
1164 m_nKeyboardSpeed = nKeyboardSpeed;
\r
1167 unsigned int CXkeymacsDll::GetMaxKeyInterval()
\r
1169 // m_nKeyboardSpeed == 0: slowest repeat rate; approximately 2 characters per second
\r
1170 // m_nKeyboardSpeed == 31: fastest repeat rate; approximately 30 characters per second
\r
1171 // 47 ms is max on my machine w/ KeyboardSpeed 31.
\r
1172 // 1000 / 2 + 50 = 550
\r
1173 // 1000 / 30 + 50 = 83
\r
1174 return (unsigned int) (1000.0 / (2.0 + m_nKeyboardSpeed % 32 * 28.0 / 31.0) + 50.0);
\r
1177 void CXkeymacsDll::SetCursorData(HCURSOR hEnable, HCURSOR hDisableTMP, HCURSOR hDisableWOCQ, HICON hDisable, BOOL bEnable)
\r
1179 m_hCursor[STATUS_ENABLE] = hEnable;
\r
1180 m_hCursor[STATUS_DISABLE_TMP] = hDisableTMP;
\r
1181 m_hCursor[STATUS_DISABLE_WOCQ] = hDisableWOCQ;
\r
1182 m_hCursor[STATUS_DISABLE] = hDisable;
\r
1183 m_bCursor = bEnable;
\r
1186 void CXkeymacsDll::DoSetCursor()
\r
1188 if (m_bCursor && m_hCurrentCursor)
\r
1189 ::SetCursor(m_hCurrentCursor);
\r