- 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>
34 lines
885 B
C++
34 lines
885 B
C++
#pragma once
|
|
|
|
#include <QtGlobal>
|
|
#include <limits>
|
|
|
|
// iOS shift semantics:
|
|
// - tap: shift the next character only
|
|
// - double-tap: caps lock; tap again to unlock
|
|
// - hold while typing: every character shifted, off on release
|
|
// Times are in milliseconds and passed in, so this stays deterministic.
|
|
class ShiftState
|
|
{
|
|
public:
|
|
enum class Mode { Off, Once, Locked };
|
|
|
|
static constexpr qint64 DoubleTapMs = 300;
|
|
|
|
Mode mode() const { return m_mode; }
|
|
bool isUppercase() const { return m_mode != Mode::Off; }
|
|
|
|
void press(qint64 timeMs);
|
|
void release();
|
|
void characterTyped();
|
|
|
|
// Auto-capitalization hint; ignored while shift is held or locked.
|
|
void setAutomatic(bool capitalize);
|
|
|
|
private:
|
|
Mode m_mode = Mode::Off;
|
|
bool m_held = false;
|
|
bool m_typedWhileHeld = false;
|
|
qint64 m_lastPress = std::numeric_limits<qint64>::min() / 2;
|
|
};
|