Layouts, iPad-style rendering, taps, shift and layers

- JSON layouts (en-US, sv-SE inheriting number/symbol layers via base)
- LayoutModel + KeyGeometry: proportional rows, nearest-key hit testing
- KeyboardSurface: multi-pointer touch/mouse routing to the controller
- KeyboardController + ShiftState: iOS shift/caps-lock, layers, globe, dismiss
- QML view with light/dark iPad palette and drag handle
- DevHooks: SLOPOSK_AUTOTYPE, SLOPOSK_SCREENSHOT for headless checks
- Unit tests for shift, loader, geometry and controller

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 14:50:21 +02:00
co-authored by Claude Opus 5.5
parent cdef9b4ad0
commit be14bbcc62
35 changed files with 1970 additions and 65 deletions
+56 -20
View File
@@ -1,6 +1,59 @@
# --- sloposk_core: everything that runs without a compositor; also the "Sloposk" QML module.
qt_add_library(sloposk_core STATIC
backend/TextBackend.h
engine/InputEngine.h
engine/DirectEngine.h engine/DirectEngine.cpp
input/ShiftState.h input/ShiftState.cpp
input/KeyboardController.h input/KeyboardController.cpp
input/KeyboardSurface.h input/KeyboardSurface.cpp
layout/Layout.h
layout/LayoutLoader.h layout/LayoutLoader.cpp
layout/LayoutRepository.h layout/LayoutRepository.cpp
layout/KeyGeometry.h layout/KeyGeometry.cpp
layout/LayoutModel.h layout/LayoutModel.cpp
)
# QML lives in the top-level qml/ dir; alias each file so the module sees it at its root.
set(SLOPOSK_QML_FILES
Main.qml
Keyboard.qml
Key.qml
DragHandle.qml
Theme.qml
)
list(TRANSFORM SLOPOSK_QML_FILES PREPEND ${PROJECT_SOURCE_DIR}/qml/ OUTPUT_VARIABLE sloposk_qml_paths)
foreach(file IN LISTS SLOPOSK_QML_FILES)
set_source_files_properties(${PROJECT_SOURCE_DIR}/qml/${file} PROPERTIES QT_RESOURCE_ALIAS ${file})
endforeach()
set_source_files_properties(${PROJECT_SOURCE_DIR}/qml/Theme.qml PROPERTIES QT_QML_SINGLETON_TYPE TRUE)
qt_add_qml_module(sloposk_core
URI Sloposk
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml/Sloposk
QML_FILES ${sloposk_qml_paths}
)
file(GLOB layout_files CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/layouts/*.json)
qt_add_resources(sloposk_core "layouts"
PREFIX /layouts
BASE ${PROJECT_SOURCE_DIR}/layouts
FILES ${layout_files}
)
target_include_directories(sloposk_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
# The generated QML type registration includes QML_ELEMENT headers by bare name.
target_include_directories(sloposk_core PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/input
${CMAKE_CURRENT_SOURCE_DIR}/layout
)
target_link_libraries(sloposk_core PUBLIC Qt6::Quick PkgConfig::XKB)
# --- sloposk: the app, with the compositor-specific parts.
qt_add_executable(sloposk
main.cpp
backend/TextBackend.h
DevHooks.h DevHooks.cpp
backend/InputMethodProtocol.h
backend/KWinInputMethod.h backend/KWinInputMethod.cpp
backend/KWinInputContext.h backend/KWinInputContext.cpp
@@ -14,28 +67,11 @@ qt6_generate_wayland_protocol_client_sources(sloposk PRIVATE_CODE FILES
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/qwayland-input-method-unstable-v1.cpp
PROPERTIES COMPILE_OPTIONS "-include;wayland-client-protocol.h")
# QML lives in the top-level qml/ dir; alias each file so the module sees it at its root.
set(SLOPOSK_QML_FILES
Main.qml
)
list(TRANSFORM SLOPOSK_QML_FILES PREPEND ${PROJECT_SOURCE_DIR}/qml/ OUTPUT_VARIABLE sloposk_qml_paths)
foreach(file IN LISTS SLOPOSK_QML_FILES)
set_source_files_properties(${PROJECT_SOURCE_DIR}/qml/${file} PROPERTIES QT_RESOURCE_ALIAS ${file})
endforeach()
qt_add_qml_module(sloposk
URI Sloposk
QML_FILES ${sloposk_qml_paths}
)
target_include_directories(sloposk PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(sloposk PRIVATE
Qt6::Gui
Qt6::Quick
sloposk_core
sloposk_coreplugin
Qt6::WaylandClient
LayerShellQt::Interface
PkgConfig::XKB
PkgConfig::WAYLAND
)