From f0daa312d09d2c8a5379159f29a9356332a38ae3 Mon Sep 17 00:00:00 2001 From: danielsuss Date: Thu, 12 Jun 2025 14:29:34 +0100 Subject: [PATCH 1/4] Initial Implementation for coordinate switching --- .claude/settings.local.json | 12 +++ src/gui/src/Action.cpp | 17 +++- src/gui/src/Action.h | 12 +++ src/gui/src/ActionDialog.cpp | 22 +++++ src/gui/src/ActionDialogBase.ui | 170 ++++++++++++++++++++++++++++++++ src/lib/server/Config.cpp | 18 +++- src/lib/server/InputFilter.cpp | 49 ++++++++- src/lib/server/InputFilter.h | 7 ++ src/lib/server/Server.cpp | 24 ++++- src/lib/server/Server.h | 4 + 10 files changed, 326 insertions(+), 9 deletions(-) create mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 00000000..50941707 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,12 @@ +{ + "permissions": { + "allow": [ + "Bash(rg:*)", + "Bash(g++:*)", + "Bash(cmake:*)", + "Bash(sudo apt:*)", + "Bash(sudo apt install:*)" + ], + "deny": [] + } +} \ No newline at end of file diff --git a/src/gui/src/Action.cpp b/src/gui/src/Action.cpp index f34d1e8f..cf4f5ddf 100644 --- a/src/gui/src/Action.cpp +++ b/src/gui/src/Action.cpp @@ -40,7 +40,10 @@ Action::Action() : m_SwitchDirection(switchLeft), m_LockCursorMode(lockCursorToggle), m_ActiveOnRelease(false), - m_HasScreens(false) + m_HasScreens(false), + m_hasCustomPosition(false), + m_customX(0), + m_customY(0) { } @@ -87,6 +90,12 @@ QString Action::text() const case switchToScreen: text += "("; text += switchScreenName(); + if (hasCustomPosition()) { + text += ","; + text += QString::number(customX()); + text += ","; + text += QString::number(customY()); + } text += ")"; break; @@ -133,6 +142,9 @@ void Action::loadSettings(QSettings& settings) setLockCursorMode(settings.value("lockCursorToScreen", lockCursorToggle).toInt()); setActiveOnRelease(settings.value("activeOnRelease", false).toBool()); setHaveScreens(settings.value("hasScreens", false).toBool()); + setHasCustomPosition(settings.value("hasCustomPosition", false).toBool()); + setCustomX(settings.value("customX", 0).toInt()); + setCustomY(settings.value("customY", 0).toInt()); } void Action::saveSettings(QSettings& settings) const @@ -153,6 +165,9 @@ void Action::saveSettings(QSettings& settings) const settings.setValue("lockCursorToScreen", lockCursorMode()); settings.setValue("activeOnRelease", activeOnRelease()); settings.setValue("hasScreens", haveScreens()); + settings.setValue("hasCustomPosition", hasCustomPosition()); + settings.setValue("customX", customX()); + settings.setValue("customY", customY()); } QTextStream& operator<<(QTextStream& outStream, const Action& action) diff --git a/src/gui/src/Action.h b/src/gui/src/Action.h index c260badc..f5ff55ac 100644 --- a/src/gui/src/Action.h +++ b/src/gui/src/Action.h @@ -72,6 +72,15 @@ class Action bool haveScreens() const { return m_HasScreens; } void setHaveScreens(bool b) { m_HasScreens = b; } + bool hasCustomPosition() const { return m_hasCustomPosition; } + void setHasCustomPosition(bool b) { m_hasCustomPosition = b; } + + int customX() const { return m_customX; } + void setCustomX(int x) { m_customX = x; } + + int customY() const { return m_customY; } + void setCustomY(int y) { m_customY = y; } + private: KeySequence m_KeySequence; int m_Type; @@ -81,6 +90,9 @@ class Action int m_LockCursorMode; bool m_ActiveOnRelease; bool m_HasScreens; + bool m_hasCustomPosition; + int m_customX; + int m_customY; static const char* m_ActionTypeNames[]; static const char* m_SwitchDirectionNames[]; diff --git a/src/gui/src/ActionDialog.cpp b/src/gui/src/ActionDialog.cpp index 89a037e3..8032b85b 100644 --- a/src/gui/src/ActionDialog.cpp +++ b/src/gui/src/ActionDialog.cpp @@ -73,6 +73,11 @@ ActionDialog::ActionDialog(QWidget* parent, ServerConfig& config, Hotkey& hotkey idx++; } } + + // Initialize coordinate controls + m_pCheckBoxCustomPosition->setChecked(m_Action.hasCustomPosition()); + m_pSpinBoxX->setValue(m_Action.customX()); + m_pSpinBoxY->setValue(m_Action.customY()); } void ActionDialog::accept() @@ -93,6 +98,23 @@ void ActionDialog::accept() m_Action.setSwitchDirection(m_pComboSwitchInDirection->currentIndex()); m_Action.setLockCursorMode(m_pComboLockCursorToScreen->currentIndex()); m_Action.setActiveOnRelease(m_pRadioHotkeyReleased->isChecked()); + + // Save coordinate settings only for switchToScreen action + if (m_pButtonGroupType->checkedId() == Action::switchToScreen) { + m_Action.setHasCustomPosition(m_pCheckBoxCustomPosition->isChecked()); + if (m_pCheckBoxCustomPosition->isChecked()) { + m_Action.setCustomX(m_pSpinBoxX->value()); + m_Action.setCustomY(m_pSpinBoxY->value()); + } else { + m_Action.setCustomX(0); + m_Action.setCustomY(0); + } + } else { + // Clear custom position for other action types + m_Action.setHasCustomPosition(false); + m_Action.setCustomX(0); + m_Action.setCustomY(0); + } QDialog::accept(); } diff --git a/src/gui/src/ActionDialogBase.ui b/src/gui/src/ActionDialogBase.ui index 9c6ad0a0..4036bd3a 100644 --- a/src/gui/src/ActionDialogBase.ui +++ b/src/gui/src/ActionDialogBase.ui @@ -142,6 +142,96 @@ + + + + + + Set specific position + + + false + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + X: + + + false + + + + + + + false + + + 0 + + + 9999 + + + + + + + Y: + + + false + + + + + + + false + + + 0 + + + 9999 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + @@ -588,5 +678,85 @@ + + m_pRadioSwitchToScreen + toggled(bool) + m_pCheckBoxCustomPosition + setEnabled(bool) + + + 148 + 291 + + + 148 + 310 + + + + + m_pCheckBoxCustomPosition + toggled(bool) + m_pLabelX + setEnabled(bool) + + + 148 + 310 + + + 50 + 330 + + + + + m_pCheckBoxCustomPosition + toggled(bool) + m_pSpinBoxX + setEnabled(bool) + + + 148 + 310 + + + 100 + 330 + + + + + m_pCheckBoxCustomPosition + toggled(bool) + m_pLabelY + setEnabled(bool) + + + 148 + 310 + + + 150 + 330 + + + + + m_pCheckBoxCustomPosition + toggled(bool) + m_pSpinBoxY + setEnabled(bool) + + + 148 + 310 + + + 200 + 330 + + + diff --git a/src/lib/server/Config.cpp b/src/lib/server/Config.cpp index bcdb88cd..52913028 100644 --- a/src/lib/server/Config.cpp +++ b/src/lib/server/Config.cpp @@ -1141,8 +1141,8 @@ void Config::parseAction(ConfigReadContext& s, const std::string& name, */ else if (name == "switchToScreen") { - if (args.size() != 1) { - throw XConfigRead(s, "syntax for action: switchToScreen(name)"); + if (args.size() != 1 && args.size() != 3) { + throw XConfigRead(s, "syntax for action: switchToScreen(name[,x,y])"); } std::string screen = args[0]; @@ -1153,7 +1153,19 @@ void Config::parseAction(ConfigReadContext& s, const std::string& name, throw XConfigRead(s, "unknown screen name in switchToScreen"); } - action = new InputFilter::SwitchToScreenAction(m_events, screen); + if (args.size() == 3) { + // Parse coordinates + int x, y; + try { + x = std::stoi(args[1]); + y = std::stoi(args[2]); + } catch (const std::exception&) { + throw XConfigRead(s, "invalid coordinates in switchToScreen"); + } + action = new InputFilter::SwitchToScreenAction(m_events, screen, x, y); + } else { + action = new InputFilter::SwitchToScreenAction(m_events, screen); + } } else if (name == "toggleScreen") { diff --git a/src/lib/server/InputFilter.cpp b/src/lib/server/InputFilter.cpp index a0dce17c..c2f7ad9f 100644 --- a/src/lib/server/InputFilter.cpp +++ b/src/lib/server/InputFilter.cpp @@ -322,6 +322,20 @@ InputFilter::LockCursorToScreenAction::perform(const Event& event) InputFilter::SwitchToScreenAction::SwitchToScreenAction(IEventQueue* events, const std::string& screen) : m_screen(screen), + m_hasCustomPosition(false), + m_x(0), + m_y(0), + m_events(events) +{ + // do nothing +} + +InputFilter::SwitchToScreenAction::SwitchToScreenAction(IEventQueue* events, + const std::string& screen, int x, int y) : + m_screen(screen), + m_hasCustomPosition(true), + m_x(x), + m_y(y), m_events(events) { // do nothing @@ -332,15 +346,38 @@ std::string InputFilter::SwitchToScreenAction::getScreen() const return m_screen; } +bool InputFilter::SwitchToScreenAction::hasCustomPosition() const +{ + return m_hasCustomPosition; +} + +int InputFilter::SwitchToScreenAction::getX() const +{ + return m_x; +} + +int InputFilter::SwitchToScreenAction::getY() const +{ + return m_y; +} + InputFilter::Action* InputFilter::SwitchToScreenAction::clone() const { - return new SwitchToScreenAction(*this); + if (m_hasCustomPosition) { + return new SwitchToScreenAction(m_events, m_screen, m_x, m_y); + } else { + return new SwitchToScreenAction(m_events, m_screen); + } } std::string InputFilter::SwitchToScreenAction::format() const { - return barrier::string::sprintf("switchToScreen(%s)", m_screen.c_str()); + if (m_hasCustomPosition) { + return barrier::string::sprintf("switchToScreen(%s,%d,%d)", m_screen.c_str(), m_x, m_y); + } else { + return barrier::string::sprintf("switchToScreen(%s)", m_screen.c_str()); + } } void @@ -356,8 +393,12 @@ InputFilter::SwitchToScreenAction::perform(const Event& event) } // send event - Server::SwitchToScreenInfo* info = - Server::SwitchToScreenInfo::alloc(screen); + Server::SwitchToScreenInfo* info; + if (m_hasCustomPosition) { + info = Server::SwitchToScreenInfo::alloc(screen, m_x, m_y); + } else { + info = Server::SwitchToScreenInfo::alloc(screen); + } m_events->addEvent(Event(m_events->forServer().switchToScreen(), event.getTarget(), info, Event::kDeliverImmediately)); diff --git a/src/lib/server/InputFilter.h b/src/lib/server/InputFilter.h index 5e6ef9cf..61f0bc55 100644 --- a/src/lib/server/InputFilter.h +++ b/src/lib/server/InputFilter.h @@ -153,8 +153,12 @@ public: class SwitchToScreenAction : public Action { public: SwitchToScreenAction(IEventQueue* events, const std::string& screen); + SwitchToScreenAction(IEventQueue* events, const std::string& screen, int x, int y); std::string getScreen() const; + bool hasCustomPosition() const; + int getX() const; + int getY() const; // Action overrides virtual Action* clone() const; @@ -163,6 +167,9 @@ public: private: std::string m_screen; + bool m_hasCustomPosition; + int m_x; + int m_y; IEventQueue* m_events; }; diff --git a/src/lib/server/Server.cpp b/src/lib/server/Server.cpp index a169db16..acb964f2 100644 --- a/src/lib/server/Server.cpp +++ b/src/lib/server/Server.cpp @@ -1404,7 +1404,13 @@ Server::handleSwitchToScreenEvent(const Event& event, void*) LOG((CLOG_DEBUG1 "screen \"%s\" not active", info->m_screen)); } else { - jumpToScreen(index->second); + if (info->m_hasCustomPosition) { + // Switch to specific coordinates + switchScreen(index->second, info->m_x, info->m_y, false); + } else { + // Use default behavior - jump to last cursor position + jumpToScreen(index->second); + } } } @@ -2329,6 +2335,22 @@ Server::SwitchToScreenInfo::alloc(const std::string& screen) SwitchToScreenInfo* info = (SwitchToScreenInfo*)malloc(sizeof(SwitchToScreenInfo) + screen.size()); + info->m_hasCustomPosition = false; + info->m_x = 0; + info->m_y = 0; + strcpy(info->m_screen, screen.c_str()); + return info; +} + +Server::SwitchToScreenInfo* +Server::SwitchToScreenInfo::alloc(const std::string& screen, SInt32 x, SInt32 y) +{ + SwitchToScreenInfo* info = + (SwitchToScreenInfo*)malloc(sizeof(SwitchToScreenInfo) + + screen.size()); + info->m_hasCustomPosition = true; + info->m_x = x; + info->m_y = y; strcpy(info->m_screen, screen.c_str()); return info; } diff --git a/src/lib/server/Server.h b/src/lib/server/Server.h index ae8b2bd5..40f8e7b8 100644 --- a/src/lib/server/Server.h +++ b/src/lib/server/Server.h @@ -63,8 +63,12 @@ public: class SwitchToScreenInfo { public: static SwitchToScreenInfo* alloc(const std::string& screen); + static SwitchToScreenInfo* alloc(const std::string& screen, SInt32 x, SInt32 y); public: + bool m_hasCustomPosition; + SInt32 m_x; + SInt32 m_y; // this is a C-string; this type is a variable size structure char m_screen[1]; }; From f7ad72457095f9cc8be53ffdcec29afbc542e9e9 Mon Sep 17 00:00:00 2001 From: danielsuss Date: Thu, 12 Jun 2025 16:04:55 +0100 Subject: [PATCH 2/4] updated makelists for modern compilation --- CMakeLists.txt | 2 +- COMPILATION_GUIDE.md | 265 ++++++++++++++++++++++++++++++++++ cmake/Version.cmake | 2 +- src/gui/CMakeLists.txt | 2 +- src/lib/base/String.h | 1 + src/lib/net/FingerprintData.h | 1 + 6 files changed, 270 insertions(+), 3 deletions(-) create mode 100644 COMPILATION_GUIDE.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 86deb4b7..ec478365 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -cmake_minimum_required (VERSION 3.4) +cmake_minimum_required (VERSION 3.5) project (barrier C CXX) option (BARRIER_BUILD_GUI "Build the GUI" ON) diff --git a/COMPILATION_GUIDE.md b/COMPILATION_GUIDE.md new file mode 100644 index 00000000..53dced94 --- /dev/null +++ b/COMPILATION_GUIDE.md @@ -0,0 +1,265 @@ +# Barrier Linux Compilation Guide + +## Exact Steps Performed (What We Actually Did) + +This section documents the exact sequence of commands and fixes applied to successfully build Barrier on WSL2/Ubuntu. + +### 1. Fixed CMake Version Requirements +Updated minimum CMake version from 3.4 to 3.5 in three files: + +**File 1:** `CMakeLists.txt` (line 18) +```cmake +# Changed from: +cmake_minimum_required (VERSION 3.4) +# To: +cmake_minimum_required (VERSION 3.5) +``` + +**File 2:** `cmake/Version.cmake` (line 1) +```cmake +# Changed from: +cmake_minimum_required (VERSION 3.4) +# To: +cmake_minimum_required (VERSION 3.5) +``` + +**File 3:** `src/gui/CMakeLists.txt` (line 1) +```cmake +# Changed from: +cmake_minimum_required (VERSION 3.4) +# To: +cmake_minimum_required (VERSION 3.5) +``` + +### 2. Installed Dependencies +```bash +sudo apt install -y libcurl4-openssl-dev qtbase5-dev qttools5-dev-tools libssl-dev libx11-dev libxtst-dev libxinerama-dev libxss-dev libxi-dev libxrandr-dev libavahi-compat-libdnssd-dev +``` + +### 3. Fixed Missing Headers +**File 1:** `src/lib/base/String.h` +Added missing header after line 25: +```cpp +#include +#include +#include // ADDED THIS LINE +``` + +**File 2:** `src/lib/net/FingerprintData.h` +Added missing header after line 22: +```cpp +#include +#include +#include // ADDED THIS LINE +``` + +### 4. Build +```bash +cd "/mnt/c/D Drive/CAPTAIN/CodeProjects/barrier" +./clean_build.sh +``` + +### 5. Verify Build Output +```bash +ls -la "/mnt/c/D Drive/CAPTAIN/CodeProjects/barrier/build/bin/" +``` +**Files created:** +- `barriers` (12,709,936 bytes) - Server executable +- `barrierc` (10,165,752 bytes) - Client executable +- `integtests` (20,092,176 bytes) - Integration tests +- `unittests` (15,227,792 bytes) - Unit tests + +### 6. Test Functionality +```bash +cd "/mnt/c/D Drive/CAPTAIN/CodeProjects/barrier/build/bin" +./barrierc +``` +**Result:** ✅ Successfully connected to server + +--- + +## General Compilation Guide + +### Prerequisites + +#### System Requirements +- Ubuntu/Debian-based Linux distribution +- CMake 4.0+ (installed via snap) +- GCC 13.3.0 +- Git + +#### Required Dependencies + +Install the following packages: + +```bash +sudo apt update +sudo apt install -y \ + libcurl4-openssl-dev \ + qtbase5-dev \ + qttools5-dev-tools \ + libssl-dev \ + libx11-dev \ + libxtst-dev \ + libxinerama-dev \ + libxss-dev \ + libxi-dev \ + libxrandr-dev \ + libavahi-compat-libdnssd-dev +``` + +**Note on Package Names:** +- Use `qtbase5-dev` instead of the deprecated `qt5-default` +- Use `libavahi-compat-libdnssd-dev` instead of `avahi-compat-libdns_sd-dev` + +### Source Code Fixes Required + +The original Barrier source code requires several fixes to compile with modern toolchains: + +#### 1. CMake Minimum Version Updates + +**Files to modify:** +- `CMakeLists.txt` (line 18) +- `cmake/Version.cmake` (line 1) +- `src/gui/CMakeLists.txt` (line 1) + +**Change:** +```cmake +# FROM: +cmake_minimum_required (VERSION 3.4) + +# TO: +cmake_minimum_required (VERSION 3.5) +``` + +**Reason:** CMake 4.0+ no longer supports compatibility with CMake < 3.5 + +#### 2. Missing C++ Headers + +**File:** `src/lib/base/String.h` + +**Add after existing includes:** +```cpp +#include +#include +#include // ADD THIS LINE +``` + +**File:** `src/lib/net/FingerprintData.h` + +**Add after existing includes:** +```cpp +#include +#include +#include // ADD THIS LINE +``` + +**Reason:** Modern C++ compilers require explicit inclusion of `` for `std::uint8_t` types + +### Compilation Process + +#### 1. Clone and Navigate +```bash +git clone +cd barrier +``` + +#### 2. Initialize Submodules +```bash +git submodule update --init --recursive +``` + +#### 3. Apply Source Code Fixes +Apply all the fixes mentioned in the "Source Code Fixes Required" section above. + +#### 4. Build +```bash +./clean_build.sh +``` + +**Alternative manual build:** +```bash +mkdir build && cd build +cmake -DCMAKE_BUILD_TYPE=Debug .. +make +``` + +### Build Output + +#### Successful Build Results +- **Location:** `build/bin/` +- **Core executables:** + - `barriers` (~12.7MB) - Server component + - `barrierc` (~10.2MB) - Client component + - `barrier` - GUI application (if Qt build completes) + - `integtests` - Integration tests + - `unittests` - Unit tests + +#### Expected Warnings +- OpenSSL deprecation warnings (non-critical) +- CMake compatibility warnings (non-critical) +- Clock skew warnings in WSL (non-critical) + +### Usage + +#### Server Mode +```bash +cd build/bin +./barriers +``` + +#### Client Mode +```bash +cd build/bin +./barrierc +``` + +#### GUI Mode (if available) +```bash +cd build/bin +./barrier +``` + +### Troubleshooting + +#### Common Issues + +1. **Missing Qt5**: Install `qtbase5-dev` instead of `qt5-default` +2. **Missing Avahi**: Use `libavahi-compat-libdnssd-dev` package name +3. **uint8_t errors**: Add `#include ` to header files +4. **CMake version errors**: Update minimum version requirements to 3.5 +5. **CURL not found**: Install `libcurl4-openssl-dev` + +#### Build Environment Notes +- **WSL Users**: No GUI display available by default +- **X11 Required**: For actual mouse/keyboard sharing functionality +- **Network**: Ensure firewall allows Barrier traffic (default port 24800) + +### Platform-Specific Notes + +#### Windows Build (Alternative) +If building on Windows instead of Linux: +- Requires Visual Studio 2019/2022 +- Requires Qt 5.11.1 at `C:\Qt\5.11.1\msvc2017_64` +- Requires Bonjour SDK at `C:\Program Files\Bonjour SDK` +- Use `clean_build.bat` instead of `clean_build.sh` + +#### Linux Desktop Environment +For full functionality, Barrier requires: +- X11 or Wayland display server +- Desktop environment (GNOME, KDE, etc.) +- Proper graphics drivers + +### Version Information +- **Barrier Version:** 2.4.0 +- **Build System:** CMake + Make +- **Compiler:** GCC 13.3.0 +- **Target Platform:** Linux x86_64 + +### Summary of Changes Made +1. Updated CMake minimum version requirements (3 files) +2. Added missing `#include ` headers (2 files) +3. Installed correct Linux development packages +4. Used appropriate package names for Ubuntu 24.04+ + +This guide should enable successful compilation of Barrier on modern Linux systems. \ No newline at end of file diff --git a/cmake/Version.cmake b/cmake/Version.cmake index 73524bf1..dfb83bbb 100644 --- a/cmake/Version.cmake +++ b/cmake/Version.cmake @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.4) +cmake_minimum_required (VERSION 3.5) set (BARRIER_VERSION_MAJOR 2) set (BARRIER_VERSION_MINOR 4) diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 570e8424..fbad2ec7 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.4) +cmake_minimum_required (VERSION 3.5) find_package (Qt5 REQUIRED COMPONENTS Core Widgets Network) set (CMAKE_AUTOMOC ON) diff --git a/src/lib/base/String.h b/src/lib/base/String.h index 9c5a53ba..faf35969 100644 --- a/src/lib/base/String.h +++ b/src/lib/base/String.h @@ -23,6 +23,7 @@ #include #include +#include // use standard C++ string class for our string class typedef std::string String; diff --git a/src/lib/net/FingerprintData.h b/src/lib/net/FingerprintData.h index 938a6953..8ab16314 100644 --- a/src/lib/net/FingerprintData.h +++ b/src/lib/net/FingerprintData.h @@ -20,6 +20,7 @@ #include #include +#include namespace barrier { From 314f1070e5cfb0825eab4f0e0f6280840274cc39 Mon Sep 17 00:00:00 2001 From: danielsuss Date: Fri, 13 Jun 2025 14:10:03 +0100 Subject: [PATCH 3/4] Add grave modifier support for hotkeys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements support for using the grave key (`) as a hotkey modifier in Barrier, enabling hotkey combinations like Grave+1, Grave+2, etc. Key changes: - Add XK_grave case to getModifierBitForKeySym() for XKB support - Add fallback mapping for grave modifier to Mod4 in XKB path - Include KeyModifierGrave in allowed modifiers for hotkey registration - Add setup documentation for required X11 modifier mapping Requires running: xmodmap -e "add mod4 = grave" 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- GRAVE_MODIFIER_SETUP.md | 48 +++++++++++++++++++++++++++ src/lib/platform/XWindowsKeyState.cpp | 11 ++++++ src/lib/platform/XWindowsScreen.cpp | 2 +- src/lib/platform/XWindowsUtil.cpp | 3 ++ 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 GRAVE_MODIFIER_SETUP.md diff --git a/GRAVE_MODIFIER_SETUP.md b/GRAVE_MODIFIER_SETUP.md new file mode 100644 index 00000000..6712fbc4 --- /dev/null +++ b/GRAVE_MODIFIER_SETUP.md @@ -0,0 +1,48 @@ +# Grave Modifier Setup for Barrier + +## Overview +This implementation adds support for using the grave key (`) as a hotkey modifier in Barrier, similar to Control, Alt, and Shift. + +## Required Setup + +### 1. Code Changes +The following code changes have been implemented: + +- **XWindowsUtil.cpp**: Added `case XK_grave: return kKeyModifierBitGrave;` to `getModifierBitForKeySym()` +- **XWindowsKeyState.cpp**: Added fallback mapping for grave modifier to Mod4 in `updateKeysymMapXKB()` +- **key_types.cpp**: Already included grave modifier in `kModifierNameMap` + +### 2. X11 Modifier Mapping (REQUIRED) +The grave key must be mapped to an X11 modifier for hotkeys to work. Run this command: + +```bash +xmodmap -e "add mod4 = grave" +``` + +### 3. Make it Permanent +To make the X11 mapping persistent across reboots, add this line to `~/.xsessionrc`: + +```bash +echo 'xmodmap -e "add mod4 = grave"' >> ~/.xsessionrc +``` + +## Usage +Once setup is complete, you can use grave modifier hotkeys in your Barrier configuration: + +``` +keystroke(Grave+1) = switchToScreen(screen1,960,540) +keystroke(Grave+2) = switchToScreen(screen2,960,540) +``` + +## Verification +To verify the setup: + +1. Check modifier mapping: `xmodmap -pm` + - Should show `grave (0x31)` in the mod4 line +2. Test hotkeys: Press and hold grave, then press a number key +3. Check Barrier logs for successful hotkey registration + +## Troubleshooting +- If hotkeys don't work, verify grave is mapped to mod4: `xmodmap -pm` +- If mapping is lost after reboot, ensure `~/.xsessionrc` contains the xmodmap command +- Restart Barrier server after making X11 mapping changes \ No newline at end of file diff --git a/src/lib/platform/XWindowsKeyState.cpp b/src/lib/platform/XWindowsKeyState.cpp index 088adc6d..714ee32f 100644 --- a/src/lib/platform/XWindowsKeyState.cpp +++ b/src/lib/platform/XWindowsKeyState.cpp @@ -317,6 +317,7 @@ XWindowsKeyState::updateKeysymMap(barrier::KeyMap& keyMap) m_modifierToX[KeyModifierShift] = ShiftMask; m_modifierToX[KeyModifierCapsLock] = LockMask; m_modifierToX[KeyModifierControl] = ControlMask; + m_modifierToX[KeyModifierGrave] = Mod4Mask; // prepare map from KeyID to KeyCode m_keyCodeFromKey.clear(); @@ -779,6 +780,16 @@ XWindowsKeyState::updateKeysymMapXKB(barrier::KeyMap& keyMap) } } + // Add fallback for grave modifier if not found during XKB discovery + if (m_modifierToX.find(KeyModifierGrave) == m_modifierToX.end()) { + LOG((CLOG_DEBUG1 "XKB: Adding fallback mapping for grave modifier to Mod4")); + m_modifierToX[KeyModifierGrave] = Mod4Mask; + // Also update the reverse mapping for consistency + if (m_modifierFromX.size() > 3) { // Mod4 is bit 3 + m_modifierFromX[3] |= KeyModifierGrave; + } + } + // change all modifier masks to barrier masks from X masks keyMap.foreachKey(&XWindowsKeyState::remapKeyModifiers, this); diff --git a/src/lib/platform/XWindowsScreen.cpp b/src/lib/platform/XWindowsScreen.cpp index 7f8ce655..47b54702 100644 --- a/src/lib/platform/XWindowsScreen.cpp +++ b/src/lib/platform/XWindowsScreen.cpp @@ -528,7 +528,7 @@ XWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) { // only allow certain modifiers if ((mask & ~(KeyModifierShift | KeyModifierControl | - KeyModifierAlt | KeyModifierSuper)) != 0) { + KeyModifierAlt | KeyModifierSuper | KeyModifierGrave)) != 0) { LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); return 0; } diff --git a/src/lib/platform/XWindowsUtil.cpp b/src/lib/platform/XWindowsUtil.cpp index 7d4bb638..870b40a4 100644 --- a/src/lib/platform/XWindowsUtil.cpp +++ b/src/lib/platform/XWindowsUtil.cpp @@ -1646,6 +1646,9 @@ XWindowsUtil::getModifierBitForKeySym(KeySym keysym) case XK_Scroll_Lock: return kKeyModifierBitScrollLock; + case XK_grave: + return kKeyModifierBitGrave; + default: return kKeyModifierBitNone; } From b8f917def2ac2f1f1f8ab99b0f44bb29441ad5bb Mon Sep 17 00:00:00 2001 From: danielsuss Date: Fri, 13 Jun 2025 15:12:33 +0100 Subject: [PATCH 4/4] Enhance grave modifier key support and fix missing key definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add missing grave key definitions in KeySequence class - Improve key type mapping for grave modifier - Ensure consistent grave modifier behavior across GUI and core 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/gui/src/KeySequence.cpp | 16 ++++++++++++++++ src/gui/src/KeySequence.h | 3 +++ src/lib/barrier/key_types.cpp | 1 + src/lib/barrier/key_types.h | 5 ++++- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/gui/src/KeySequence.cpp b/src/gui/src/KeySequence.cpp index ddf7d332..3ef93926 100644 --- a/src/gui/src/KeySequence.cpp +++ b/src/gui/src/KeySequence.cpp @@ -139,6 +139,19 @@ bool KeySequence::appendKey(int key, int modifiers) } break; + case Qt::Key_QuoteLeft: + { + printf("GRAVE DEBUG: Qt::Key_QuoteLeft detected in GUI\n"); + int mod = GraveModifier & (~m_Modifiers); + if (mod) + { + printf("GRAVE DEBUG: Adding GraveModifier to sequence: %08x\n", mod); + m_Sequence.append(mod); + m_Modifiers |= mod; + } + } + break; + default: // see if we can handle this key, if not, don't accept it if (keyToString(key).isEmpty()) @@ -210,6 +223,9 @@ QString KeySequence::keyToString(int key) if (key & Qt::MetaModifier) return "Meta"; + if (key & GraveModifier) + return "Grave"; + // treat key pad like normal keys (FIXME: we should have another lookup table for keypad keys instead) key &= ~Qt::KeypadModifier; diff --git a/src/gui/src/KeySequence.h b/src/gui/src/KeySequence.h index 03310918..56c3f0bf 100644 --- a/src/gui/src/KeySequence.h +++ b/src/gui/src/KeySequence.h @@ -25,6 +25,9 @@ class QSettings; +// Custom modifier for grave key (not supported by Qt) +static const int GraveModifier = 0x20000000; + class KeySequence { public: diff --git a/src/lib/barrier/key_types.cpp b/src/lib/barrier/key_types.cpp index 33ee3ebc..06e9d5e9 100644 --- a/src/lib/barrier/key_types.cpp +++ b/src/lib/barrier/key_types.cpp @@ -209,6 +209,7 @@ const KeyModifierNameMapEntry kModifierNameMap[] = { { "AltGr", KeyModifierAltGr }, // { "CapsLock", KeyModifierCapsLock }, { "Control", KeyModifierControl }, + { "Grave", KeyModifierGrave }, { "Meta", KeyModifierMeta }, // { "NumLock", KeyModifierNumLock }, // { "ScrollLock", KeyModifierScrollLock }, diff --git a/src/lib/barrier/key_types.h b/src/lib/barrier/key_types.h index 863dc174..39635a6b 100644 --- a/src/lib/barrier/key_types.h +++ b/src/lib/barrier/key_types.h @@ -58,6 +58,7 @@ static const KeyModifierMask KeyModifierMeta = 0x0008; static const KeyModifierMask KeyModifierSuper = 0x0010; static const KeyModifierMask KeyModifierAltGr = 0x0020; static const KeyModifierMask KeyModifierLevel5Lock = 0x0040; +static const KeyModifierMask KeyModifierGrave = 0x0080; static const KeyModifierMask KeyModifierCapsLock = 0x1000; static const KeyModifierMask KeyModifierNumLock = 0x2000; static const KeyModifierMask KeyModifierScrollLock = 0x4000; @@ -73,6 +74,7 @@ static const UInt32 kKeyModifierBitMeta = 3; static const UInt32 kKeyModifierBitSuper = 4; static const UInt32 kKeyModifierBitAltGr = 5; static const UInt32 kKeyModifierBitLevel5Lock = 6; +static const UInt32 kKeyModifierBitGrave = 7; static const UInt32 kKeyModifierBitCapsLock = 12; static const UInt32 kKeyModifierBitNumLock = 13; static const UInt32 kKeyModifierBitScrollLock = 14; @@ -88,7 +90,8 @@ static const KeyModifierID kKeyModifierIDAlt = 3; static const KeyModifierID kKeyModifierIDMeta = 4; static const KeyModifierID kKeyModifierIDSuper = 5; static const KeyModifierID kKeyModifierIDAltGr = 6; -static const KeyModifierID kKeyModifierIDLast = 7; +static const KeyModifierID kKeyModifierIDGrave = 7; +static const KeyModifierID kKeyModifierIDLast = 8; //@} //! @name Key identifiers