mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-08 01:45:32 +00:00
108 lines
3.7 KiB
C++
108 lines
3.7 KiB
C++
|
|
|
|
#pragma once // _S2
|
|
|
|
#include "../../../core/src/kmx/kmx_processevent.h" // _S2 included before all to prevent use of legacy_kmx_file
|
|
|
|
#include "../../../../developer/kmcompx/include/pch.h" // _S2 #include "pch.h"
|
|
#include "CheckNCapsConsistency.h"
|
|
//#include "../../../../developer/kmcompx/include/compfile.h" // _S2 #include <compfile.h>
|
|
//#include "../../../../developer/kmcompx/include/compiler.h" // _S2 #include <compiler.h>
|
|
//#include <comperr.h> // double?
|
|
|
|
//#include "../../../../developer/kmcompx/include/kmcmpdll.h" // _S2 #include <kmcmpdll.h>
|
|
#include "CharToKeyConversion.h"
|
|
|
|
#include <windows.h> // added _S2 needed?
|
|
|
|
/**
|
|
* If any rule uses CAPS or NCAPS for a given key, then every rule that
|
|
* uses that key must also use CAPS or NCAPS, as otherwise the results are
|
|
* inconsistent. For example, if Caps Lock is on, then [K_F] may still be
|
|
* matched:
|
|
*
|
|
* + [K_F] > 'foo'
|
|
* + [CAPS K_F] > 'bar'
|
|
*
|
|
* Because of the way that KeymanWeb compiles rules, this may even apply when
|
|
* we have a key rule that would otherwise be ignored due to context. In the
|
|
* following example, [Caps Lock] + [y] would result in no output (or default
|
|
* output) rather than 'bar', because the preceding rule would capture the
|
|
* Y key, ignoring Caps Lock, meaning that the subsequent rule would never
|
|
* even get tested. (Note that this was introduced in the KeymanWeb compiler
|
|
* fix for extremely long if/else ladders in Keyman 12 in #1561, and this is
|
|
* technically slightly inconsistent with Keyman Core, although in my analysis
|
|
* only in this already ambiguous situation.
|
|
*
|
|
* 'x' + [K_Y] > 'foo'
|
|
* [CAPS K_Y] > 'bar'
|
|
*
|
|
* Given all this, we'll warn any time we find a key that has inconsistent use
|
|
* of CAPS/NCAPS in its rules.
|
|
*
|
|
* @param fk Keyboard to check
|
|
*/
|
|
|
|
bool CheckNCapsConsistency(PFILE_KEYBOARD fk) {
|
|
struct CapsUsage {
|
|
int ncaps_line, caps_line, neither_line;
|
|
};
|
|
|
|
// 256 virtual key codes + sizeof the virtual key dictionary is max key code possible
|
|
const int nkeys = 256 + fk->cxVKDictionary;
|
|
const int oldCurrentLine = currentLine;
|
|
auto caps_ncaps_usage = new CapsUsage [nkeys];
|
|
|
|
memset(caps_ncaps_usage, 0, nkeys * sizeof(CapsUsage));
|
|
|
|
PFILE_GROUP gp;
|
|
KMX_DWORD gn;
|
|
for (gn = 0, gp = fk->dpGroupArray; gn < fk->cxGroupArray; gn++, gp++) {
|
|
if (!gp->fUsingKeys) {
|
|
continue;
|
|
}
|
|
|
|
PFILE_KEY kp;
|
|
KMX_DWORD kn;
|
|
for (kn = 0, kp = gp->dpKeyArray; kn < gp->cxKeyArray; kn++, kp++) {
|
|
KMX_UINT key;
|
|
KMX_UINT shift;
|
|
if (kp->ShiftFlags & ISVIRTUALKEY) {
|
|
if (kp->Key >= nkeys) {
|
|
assert(false);
|
|
continue;
|
|
}
|
|
key = kp->Key;
|
|
shift = kp->ShiftFlags;
|
|
}
|
|
else if (!MapUSCharToVK(kp->Key, &key, &shift)) {
|
|
// Not a valid key
|
|
continue;
|
|
}
|
|
|
|
if (shift & NOTCAPITALFLAG) {
|
|
if (!caps_ncaps_usage[key].ncaps_line) caps_ncaps_usage[key].ncaps_line = (kp->Line == 0 ? 1 : kp->Line);
|
|
}
|
|
else if (shift & CAPITALFLAG) {
|
|
if (!caps_ncaps_usage[key].caps_line) caps_ncaps_usage[key].caps_line = (kp->Line == 0 ? 1 : kp->Line);
|
|
}
|
|
else {
|
|
if (!caps_ncaps_usage[key].neither_line) caps_ncaps_usage[key].neither_line = (kp->Line == 0 ? 1 : kp->Line);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < nkeys; i++) {
|
|
if (caps_ncaps_usage[i].neither_line && (caps_ncaps_usage[i].caps_line || caps_ncaps_usage[i].ncaps_line)) {
|
|
// We set the current line to one needing work: the developer should add the NCAPS flag
|
|
currentLine = caps_ncaps_usage[i].neither_line;
|
|
AddWarning(CWARN_KeyShouldIncludeNCaps);
|
|
}
|
|
}
|
|
|
|
delete[] caps_ncaps_usage;
|
|
|
|
currentLine = oldCurrentLine;
|
|
|
|
return TRUE;
|
|
}
|