Skip to content

Commit

Permalink
Different key handling
Browse files Browse the repository at this point in the history
Fixes accents/dead-keys and alt-shortcuts problems

Fixes #12, Fixes #10
  • Loading branch information
ikeblaster authored and dail8859 committed Jan 11, 2020
1 parent 389bdcb commit fa84862
Showing 1 changed file with 84 additions and 35 deletions.
119 changes: 84 additions & 35 deletions src/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@

#define buffChars 1

struct COMBINATION {
UCHAR ch1;
UCHAR ch2;
BYTE vk;
BYTE shift;
BYTE ctrl;
BYTE alt;
};

static HANDLE _hModule;
static NppData nppData;
static HHOOK hook = NULL;
Expand All @@ -34,6 +43,9 @@ static bool hasFocus = true;
static ScintillaEditor editor;
static LPWORD kbBuff = (LPWORD)new byte[buffChars];
static PBYTE kbState = new byte[256];
static std::vector<UCHAR> kbProcessChars;
static std::vector<COMBINATION> kbProcessCombinations;
static size_t kbProcessCombinationsCount;
TCHAR addChars[1024];
TCHAR ignoreChars[1024];

Expand All @@ -59,8 +71,63 @@ const wchar_t *GetIniFilePath() {
return iniPath;
}

static void prepareKeyboardChars() {
BOOL processChars[255] = { FALSE };

kbProcessChars.clear();

// Default characters
for (UCHAR c : "\"'(){}[]<>`")
processChars[c] = TRUE;

// Add user defined
for (SIZE_T i = 0, j = _tcslen(addChars); i < j; i++)
processChars[(UCHAR) addChars[i]] = TRUE;

// Disable ignored
for (SIZE_T i = 0, j = _tcslen(ignoreChars); i < j; i++)
processChars[(UCHAR) ignoreChars[i]] = FALSE;

// Add all enabled into kbProcessChars
for (UCHAR i = 0; i < 255; i++)
if (processChars[i])
kbProcessChars.push_back(i);
}

static void updateKL() {
keyboardLayout = GetKeyboardLayout(0);

// Transform kbProcessChars (pure characters) into kbProcessCombinations (VK keys + alt/ctrl/shift mask)
kbProcessCombinations.clear();

for (UCHAR ch : kbProcessChars) {
SHORT comb = VkKeyScanEx(ch, keyboardLayout);

if (comb == -1) {
continue;
}

UCHAR ch1 = ch;
UCHAR ch2 = ch;
BYTE vk = (comb & 0xFF);
BYTE shift = (comb & 0x100) == 0x100 ? 0x80 : 0;
BYTE ctrl = (comb & 0x200) == 0x200 ? 0x80 : 0;
BYTE alt = (comb & 0x400) == 0x400 ? 0x80 : 0;

if (ch == '(' || ch == ')') {
ch1 = '('; ch2 = ')';
} else if (ch == '[' || ch == ']') {
ch1 = '['; ch2 = ']';
} else if (ch == '{' || ch == '}') {
ch1 = '{'; ch2 = '}';
} else if (ch == '<' || ch == '>') {
ch1 = '<'; ch2 = '>';
}

kbProcessCombinations.push_back(COMBINATION{ ch1, ch2, vk, shift, ctrl, alt });
}

kbProcessCombinationsCount = kbProcessCombinations.size();
}

static void enableSurroundSelection() {
Expand Down Expand Up @@ -134,55 +201,35 @@ LRESULT CALLBACK KeyboardProc(int ncode, WPARAM wparam, LPARAM lparam) {
if ((HIWORD(lparam) & KF_UP) != 0 || !hasFocus)
goto proceed;

char ch1 = 0, ch2 = 0;
UINT scanCode = (lparam >> 16) & 0xFF;
// Get full keyboard state
if (!GetKeyboardState(kbState))
goto proceed;
//Translate state, pressed key and keyboard layout in the respective characters
int amount = ToAsciiEx((UINT)wparam, scanCode, kbState, kbBuff, 0, keyboardLayout);
if (amount < 1)
goto proceed;

// Get first translated character
char ch = (char)kbBuff[0];

// See if the character should be ignored
for (unsigned int i = 0; i < _tcslen(ignoreChars); i++)
if (ch == ignoreChars[i])
goto proceed;

if (ch == '"' || ch == '\'' || ch == '`') {
ch1 = ch2 = (char)ch;
} else if (ch == '(' || ch == ')') {
ch1 = '('; ch2 = ')';
} else if (ch == '[' || ch == ']') {
ch1 = '['; ch2 = ']';
} else if (ch == '{' || ch == '}') {
ch1 = '{'; ch2 = '}';
} else if (ch == '<' || ch == '>') {
ch1 = '<'; ch2 = '>';
} else {
for (unsigned int i = 0; i < _tcslen(addChars); i++)
if (ch == addChars[i])
ch1 = ch2 = (char)ch;
}

if (ch1 != 0 && editor.GetSelectionEmpty() == 0) {
SurroundSelectionsWith(ch1, ch2);
return TRUE; // This key has been "handled" and won't propogate
// Check whether any "registered" combination is pressed
for (size_t i = 0; i < kbProcessCombinationsCount; i++) {
COMBINATION comb = kbProcessCombinations[i];

if (((kbState[comb.vk] & 0xF0) == 0x80)
&& comb.shift == (kbState[VK_SHIFT] & 0xF0)
&& comb.ctrl == (kbState[VK_CONTROL] & 0xF0)
&& comb.alt == (kbState[VK_MENU] & 0xF0)
) {
if (editor.GetSelectionEmpty() == 0) {
SurroundSelectionsWith(comb.ch1, comb.ch2);
return TRUE; // This key has been "handled" and won't propogate
}
break;
}
}

proceed:
return CallNextHookEx(hook, ncode, wparam, lparam); //pass control to next hook in the hook chain.
}


BOOL APIENTRY DllMain(HANDLE hModule, DWORD reasonForCall, LPVOID lpReserved) {
switch (reasonForCall) {
case DLL_PROCESS_ATTACH:
_hModule = hModule;
updateKL();
break;
case DLL_PROCESS_DETACH:
break;
Expand Down Expand Up @@ -226,6 +273,8 @@ extern "C" __declspec(dllexport) void beNotified(SCNotification *notifyCode) {
}
GetPrivateProfileString(TEXT("SurroundSelection"), TEXT("AdditionalChars"), TEXT(""), addChars, 1023, GetIniFilePath());
GetPrivateProfileString(TEXT("SurroundSelection"), TEXT("IgnoreChars"), TEXT(""), ignoreChars, 1023, GetIniFilePath());
prepareKeyboardChars();
updateKL();
break;
}
case NPPN_SHUTDOWN:
Expand Down

0 comments on commit fa84862

Please sign in to comment.