Compare commits
11 Commits
d023bd7f58
...
f311779ed9
Author | SHA1 | Date |
---|---|---|
nonpop | f311779ed9 | |
Yoni Weill | e907ff65ee | |
nonpop | 265a41a792 | |
nonpop | 661189257e | |
Behnam Mohammadzadeh | 7c70d329a3 | |
nonpop | 9f9a4fd80b | |
javigafe | ff02028ec9 | |
nonpop | 9e3276f3d2 | |
codedokode | b06aeb812d | |
Kristian Setälä | 45b752b130 | |
Hristo Asenov | 9703b88a1d |
|
@ -0,0 +1,15 @@
|
||||||
|
# Exclude Dockerfile and .dockerignore so that the docker layer cache won't be
|
||||||
|
# invalidated after editing them (which changes the build context if they are
|
||||||
|
# not ignored).
|
||||||
|
*Dockerfile*
|
||||||
|
.dockerignore
|
||||||
|
# Exclude git metadata since we only care about the working tree.
|
||||||
|
.git
|
||||||
|
.gitattributes
|
||||||
|
.gitignore
|
||||||
|
# Exclude docs
|
||||||
|
*.md
|
||||||
|
|
||||||
|
*~
|
||||||
|
*.o
|
||||||
|
xkblayout-state
|
|
@ -0,0 +1,13 @@
|
||||||
|
FROM alpine:3.14.2 AS build
|
||||||
|
RUN apk add --no-cache g++ libx11-dev make
|
||||||
|
WORKDIR /repo
|
||||||
|
COPY . .
|
||||||
|
RUN make
|
||||||
|
# RUN make && chmod a+x ./xkblayout-state
|
||||||
|
# Export to a minimal runtime image and run as an unprivileged user.
|
||||||
|
FROM alpine:3.14.2
|
||||||
|
RUN apk add --no-cache libstdc++ libx11
|
||||||
|
USER 1000:1000
|
||||||
|
WORKDIR /repo
|
||||||
|
COPY --from=build --chown=1000:1000 /repo/xkblayout-state .
|
||||||
|
ENTRYPOINT ["./xkblayout-state"]
|
2
Makefile
2
Makefile
|
@ -13,7 +13,7 @@ $(objects): %.o: %.cpp $(headers)
|
||||||
$(CXX) $(CXXFLAGS) -Wall -c -o $@ $<
|
$(CXX) $(CXXFLAGS) -Wall -c -o $@ $<
|
||||||
|
|
||||||
$(program): $(objects)
|
$(program): $(objects)
|
||||||
$(CXX) $(CXXFLAGS) -lX11 $(LDFLAGS) -o $@ $^
|
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ -lX11
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(program) $(objects)
|
rm -f $(program) $(objects)
|
||||||
|
|
|
@ -13,9 +13,11 @@ It's a thin wrapper around a slightly version of Jay Bromley's XKeyboard class,
|
||||||
Compilation and installation
|
Compilation and installation
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
|
- Make sure x11 development libraries are installed (eg. `apt install libx11-dev` on Ubuntu)
|
||||||
- To compile just say: `make`
|
- To compile just say: `make`
|
||||||
- To install copy the resulting executable `xkblayout-state` somewhere in your path
|
- To install copy the resulting executable `xkblayout-state` somewhere in your path
|
||||||
|
|
||||||
|
Alternatively with docker: `docker build .`
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
|
|
|
@ -36,6 +36,7 @@ XKeyboard::XKeyboard()
|
||||||
int reasonReturn;
|
int reasonReturn;
|
||||||
_display = XkbOpenDisplay(displayName, &eventCode, &errorReturn, &major,
|
_display = XkbOpenDisplay(displayName, &eventCode, &errorReturn, &major,
|
||||||
&minor, &reasonReturn);
|
&minor, &reasonReturn);
|
||||||
|
free(displayName);
|
||||||
switch (reasonReturn) {
|
switch (reasonReturn) {
|
||||||
case XkbOD_BadLibraryVersion:
|
case XkbOD_BadLibraryVersion:
|
||||||
throw X11Exception("Bad XKB library version.");
|
throw X11Exception("Bad XKB library version.");
|
||||||
|
@ -91,6 +92,10 @@ Bool XKeyboard::initializeXkb()
|
||||||
|
|
||||||
if (kbdDescPtr->names == NULL) {
|
if (kbdDescPtr->names == NULL) {
|
||||||
std::cerr << "Failed to get keyboard description." << std::endl;
|
std::cerr << "Failed to get keyboard description." << std::endl;
|
||||||
|
XFree(kbdDescPtr);
|
||||||
|
XkbFreeControls(kbdDescPtr, XkbAllControlsMask, true);
|
||||||
|
XkbFreeNames(kbdDescPtr, XkbSymbolsNameMask, true);
|
||||||
|
XkbFreeNames(kbdDescPtr, XkbGroupNamesMask, true);
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +127,7 @@ Bool XKeyboard::initializeXkb()
|
||||||
_groupNames.push_back("");
|
_groupNames.push_back("");
|
||||||
} else {
|
} else {
|
||||||
groupName = groupNameC;
|
groupName = groupNameC;
|
||||||
|
// Remove everything after a brace, e.g. "English(US)" -> "English"
|
||||||
std::string::size_type pos = groupName.find('(', 0);
|
std::string::size_type pos = groupName.find('(', 0);
|
||||||
if (pos != std::string::npos) {
|
if (pos != std::string::npos) {
|
||||||
groupName = groupName.substr(0, pos - 1);
|
groupName = groupName.substr(0, pos - 1);
|
||||||
|
@ -140,32 +146,49 @@ Bool XKeyboard::initializeXkb()
|
||||||
symName = symNameC;
|
symName = symNameC;
|
||||||
XFree(symNameC);
|
XFree(symNameC);
|
||||||
if (symName.empty()) {
|
if (symName.empty()) {
|
||||||
|
XFree(kbdDescPtr);
|
||||||
|
XkbFreeControls(kbdDescPtr, XkbAllControlsMask, true);
|
||||||
|
XkbFreeNames(kbdDescPtr, XkbSymbolsNameMask, true);
|
||||||
|
XkbFreeNames(kbdDescPtr, XkbGroupNamesMask, true);
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
XFree(kbdDescPtr);
|
||||||
|
XkbFreeControls(kbdDescPtr, XkbAllControlsMask, true);
|
||||||
|
XkbFreeNames(kbdDescPtr, XkbSymbolsNameMask, true);
|
||||||
|
XkbFreeNames(kbdDescPtr, XkbGroupNamesMask, true);
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
|
||||||
XkbSymbolParser symParser;
|
XkbSymbolParser symParser;
|
||||||
|
|
||||||
|
// Parser is supposed to extract layout symbols (like us, de, ru)
|
||||||
|
// and variants (like dvorak) from symName string. But sometimes
|
||||||
|
// it gets nothing, for example on my system with Xwayland symName
|
||||||
|
// is "(unnamed)" and both _symbolNames and _variantNames are empty.
|
||||||
symParser.parse(symName, _symbolNames, _variantNames);
|
symParser.parse(symName, _symbolNames, _variantNames);
|
||||||
int count = _symbolNames.size();
|
int symNameCount = _symbolNames.size();
|
||||||
if (count == 1 && _groupNames[0].empty() && _symbolNames[0] == "jp") {
|
|
||||||
|
if (symNameCount == 1 && _groupNames[0].empty() && _symbolNames[0] == "jp") {
|
||||||
_groupCount = 2;
|
_groupCount = 2;
|
||||||
|
_symbolNames.resize(_groupCount);
|
||||||
|
_groupNames.resize(_groupCount);
|
||||||
_symbolNames[1] = _symbolNames[0];
|
_symbolNames[1] = _symbolNames[0];
|
||||||
_symbolNames[0] = "us";
|
_symbolNames[0] = "us";
|
||||||
_groupNames[0] = "US/ASCII";
|
_groupNames[0] = "US/ASCII";
|
||||||
_groupNames[1] = "Japanese";
|
_groupNames[1] = "Japanese";
|
||||||
} else {
|
} else {
|
||||||
if (count < _groupCount) {
|
// If there are less symbol names, than groups,
|
||||||
int j = count;
|
// fill remaining with default name of "en_US".
|
||||||
int k = _groupCount;
|
if (symNameCount < _groupCount) {
|
||||||
while (--j >= 0) _symbolNames[--k] = _symbolNames[j];
|
while (_symbolNames.size() < (size_t)_groupCount) {
|
||||||
while (--k >= 0) _symbolNames[k] = "en_US";
|
_symbolNames.insert(_symbolNames.begin(), "en_US");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
count = _groupNames.size();
|
int groupNameCount = _groupNames.size();
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < groupNameCount; i++) {
|
||||||
if (_groupNames[i].empty()) {
|
if (_groupNames[i].empty()) {
|
||||||
std::string name = getSymbolNameByResNum(i);
|
std::string name = getSymbolNameByResNum(i);
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
|
@ -180,18 +203,22 @@ Bool XKeyboard::initializeXkb()
|
||||||
XkbStateRec xkbState;
|
XkbStateRec xkbState;
|
||||||
XkbGetState(_display, _deviceId, &xkbState);
|
XkbGetState(_display, _deviceId, &xkbState);
|
||||||
_currentGroupNum = xkbState.group;
|
_currentGroupNum = xkbState.group;
|
||||||
|
XFree(kbdDescPtr);
|
||||||
|
XkbFreeControls(kbdDescPtr, XkbAllControlsMask, true);
|
||||||
|
XkbFreeNames(kbdDescPtr, XkbSymbolsNameMask, true);
|
||||||
|
XkbFreeNames(kbdDescPtr, XkbGroupNamesMask, true);
|
||||||
|
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string XKeyboard::getSymbolNameByResNum(int groupResNum)
|
std::string XKeyboard::getSymbolNameByResNum(int groupResNum)
|
||||||
{
|
{
|
||||||
return _symbolNames[groupNumResToXkb(groupResNum)];
|
return _symbolNames.at(groupNumResToXkb(groupResNum));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string XKeyboard::getGroupNameByResNum(int groupResNum)
|
std::string XKeyboard::getGroupNameByResNum(int groupResNum)
|
||||||
{
|
{
|
||||||
return _groupNames[groupNumResToXkb(groupResNum)];
|
return _groupNames.at(groupNumResToXkb(groupResNum));
|
||||||
}
|
}
|
||||||
|
|
||||||
int XKeyboard::groupNumResToXkb(int groupResNum)
|
int XKeyboard::groupNumResToXkb(int groupResNum)
|
||||||
|
@ -201,13 +228,13 @@ int XKeyboard::groupNumResToXkb(int groupResNum)
|
||||||
|
|
||||||
int XKeyboard::groupLookup(int srcValue, StringVector fromText, StringVector toText, int count)
|
int XKeyboard::groupLookup(int srcValue, StringVector fromText, StringVector toText, int count)
|
||||||
{
|
{
|
||||||
const std::string srcText = fromText[srcValue];
|
const std::string srcText = fromText.at(srcValue);
|
||||||
|
|
||||||
if (!srcText.empty()) {
|
if (!srcText.empty()) {
|
||||||
std::string targetText;
|
std::string targetText;
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
targetText = toText[i];
|
targetText = toText.at(i);
|
||||||
if (compareNoCase(srcText, targetText) == 0) {
|
if (compareNoCase(srcText, targetText) == 0) {
|
||||||
srcValue = i;
|
srcValue = i;
|
||||||
break;
|
break;
|
||||||
|
@ -261,17 +288,17 @@ int XKeyboard::currentGroupNum() const
|
||||||
|
|
||||||
std::string XKeyboard::currentGroupName() const
|
std::string XKeyboard::currentGroupName() const
|
||||||
{
|
{
|
||||||
return _groupNames[currentGroupNum()];
|
return _groupNames.at(currentGroupNum());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string XKeyboard::currentGroupSymbol() const
|
std::string XKeyboard::currentGroupSymbol() const
|
||||||
{
|
{
|
||||||
return _symbolNames[currentGroupNum()];
|
return _symbolNames.at(currentGroupNum());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string XKeyboard::currentGroupVariant() const
|
std::string XKeyboard::currentGroupVariant() const
|
||||||
{
|
{
|
||||||
return _variantNames[currentGroupNum()];
|
return _variantNames.at(currentGroupNum());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XKeyboard::setGroupByNum(int groupNum)
|
bool XKeyboard::setGroupByNum(int groupNum)
|
||||||
|
|
Loading…
Reference in New Issue