spiegel-keyman/windows/src/global/delphi/general/Keyman.System.KeymanCoreDebug.pas
Marc Durdin cec8d11759 feat(developer): track changes to option values better in debugger
Fixes #5695.

When the debugger is in single-step mode, reflects the value of option
stores at the time of the change rather than at the beginning of the
batch.
2021-09-15 15:29:44 +10:00

193 lines
5.8 KiB
ObjectPascal

{
* Keyman is copyright (C) SIL International. MIT License.
*
* Debug interface for Keyman Core, matches keyboardprocessor_debug.h
}
unit Keyman.System.KeymanCoreDebug;
interface
uses
Keyman.System.KeymanCore;
{$WARN SYMBOL_PLATFORM OFF}
{$ALIGN 8}
///
/// The maximum size of context in km_kbp_cp units for a single debug
/// event. This is taken from MAXCONTEXT in keyman32 (Windows) and is purely
/// a convenience value. We can increase it if there is a demonstrated need.
///
const DEBUG_MAX_CONTEXT = 80;
///
/// The number of stores that can be processed in a rule. This is taken from
/// MAXSTOREOFFSETS in keyman32 (Windows) and is purely a convenience value.
/// We can increase it if there is a demonstrated need.
///
const DEBUG_MAX_STORE_OFFSETS = 20;
const DEBUG_STORE_OFFSETS_SIZE = (DEBUG_MAX_STORE_OFFSETS*2+1);
///
/// These modifier flags are used internally in the kmx engine, so will be
/// exposed only in debugging modifier states.
///
const KM_KBP_MODIFIER_VIRTUALKEY = $4000;
const KM_KBP_MODIFIER_VIRTUALCHARKEY = $8000;
///
/// Input key event data. The `character` member is derived from
/// a US English key event for vk + modifier_state, and is 0 if
/// the vk + modifier_state do not generate a character.
///
/// Used only in event type KM_KBP_DEBUG_BEGIN.
///
type
km_kbp_state_debug_key_info = record
vk: uint16_t;
modifier_state: uint16_t;
character: char16_t;
end;
pkm_kbp_state_debug_key_info = ^km_kbp_state_debug_key_info;
km_kbp_state_debug_kmx_option_info = record
store: Pointer; // LPSTORE
value: array[0..DEBUG_MAX_CONTEXT-1] of km_kbp_cp; // value to be saved into the store
end;
pkm_kbp_state_debug_kmx_option_info = ^km_kbp_state_debug_kmx_option_info;
///
/// KMX processor data for each event. kmx_base.h defines the types that are
/// passed in here, read only. Warning: context may contain sentinel values
/// for markers, with the kmx UC_SENTINEL, CODE_CONTEXT, DEADKEY pattern.
///
/// The context value here will be an intermediate value, and may differ
/// from event to event as the context can be rewritten for each rule match.
///
/// Used in all event types except KM_KBP_DEBUG_BEGIN, KM_KBP_DEBUG_END.
///
km_kbp_state_debug_kmx_info = record
context: array [0..DEBUG_MAX_CONTEXT-1] of km_kbp_cp; // The context matched by the rule (? may not need this?) // TODO: rename to context_matched
group: Pointer; // LPGROUP
rule: Pointer; // LPKEY
store_offsets: array [0..DEBUG_STORE_OFFSETS_SIZE-1] of uint16_t; // pairs--store, char position, terminated by 0xFFFF // TODO use a better structure here
/// Track the actions index in the actions that will be returned to
/// the debugger; the debugger uses this to determine when to
/// execute the actions when single-stepping.
first_action: uint16_t;
option: km_kbp_state_debug_kmx_option_info;
end;
pkm_kbp_state_debug_kmx_info = ^km_kbp_state_debug_kmx_info;
///
/// A single debug event.
///
///
{$ALIGN 8}
km_kbp_state_debug_item = record
_type: uint32_t; // TODO: _type as enum, 8 bit with padding? 32 bits is better optimized than 8 bits
flags: uint32_t;
key_info: km_kbp_state_debug_key_info;
kmx_info: km_kbp_state_debug_kmx_info;
end;
pkm_kbp_state_debug_item = ^km_kbp_state_debug_item;
///
/// A single debug event.
///
km_kbp_debug_type = type uint32_t;
const
KM_KBP_DEBUG_BEGIN = 0;
//KM_KBP_DEBUG_BEGIN_ANSI: km_kbp_debug_type = 1, // not supported; instead rewrite ansi keyboards to Unicode with mcompile
KM_KBP_DEBUG_GROUP_ENTER = 2;
KM_KBP_DEBUG_GROUP_EXIT = 3;
KM_KBP_DEBUG_RULE_ENTER = 4;
KM_KBP_DEBUG_RULE_EXIT = 5;
KM_KBP_DEBUG_MATCH_ENTER = 6;
KM_KBP_DEBUG_MATCH_EXIT = 7;
KM_KBP_DEBUG_NOMATCH_ENTER = 8;
KM_KBP_DEBUG_NOMATCH_EXIT = 9;
KM_KBP_DEBUG_END = 10;
KM_KBP_DEBUG_SET_OPTION = 11;
// Flags for KM_KBP_DEBUG_GROUP_EXIT
const KM_KBP_DEBUG_FLAG_RECURSIVE_OVERFLOW = $0001;
const KM_KBP_DEBUG_FLAG_NOMATCH = $0002;
// Flags for KM_KBP_DEBUG_BEGIN
// TODO: do we need this at all?
const KM_KBP_DEBUG_FLAG_UNICODE = $0001; // Always set
// Flags for KM_KBP_DEBUG_END
const KM_KBP_DEBUG_FLAG_OUTPUTKEYSTROKE = $0001;
///
/// Enable or disable debug tracing
///
/// @param state Pointer to initialized state
/// @param value Set to 1 to enable debugging, 0 to disable
///
/// @returns KM_KBP_STATUS_OK on success
///
function km_kbp_state_debug_set(
state: pkm_kbp_state;
value: integer
): km_kbp_status; cdecl; external kmnkbp0 delayed;
///
/// Get current debug tracing status
///
/// @param state Pointer to initialized state
///
/// @returns 1 if debugging is enabled, 0 otherwise
///
function km_kbp_state_debug_get(
state: pkm_kbp_state
): uint8_t; cdecl; external kmnkbp0 delayed;
///
/// Read current debug trace log
///
/// @param state Pointer to initialized state
/// @param num_items Pointer to variable to receive size of list; may be
/// nullptr if not required.
///
/// @returns pointer to read only array of debug item events,
/// with last entry guaranteed to be KM_KBP_DEBUG_END.
///
function km_kbp_state_debug_items(
state: pkm_kbp_state;
num_items: PCardinal
): pkm_kbp_state_debug_item; cdecl; external kmnkbp0 delayed;
implementation
initialization
// Assertions generated by debug_api.cpp for win32 x86.
// Usage: debug-api.exe --print-sizeof
//keyboardprocessor.h:
Assert(sizeof(km_kbp_context_item) = 8);
Assert(sizeof(km_kbp_context_item) = 8);
Assert(sizeof(km_kbp_action_item) = 12);
Assert(sizeof(km_kbp_option_item) = 12);
Assert(sizeof(km_kbp_keyboard_attrs) = 16);
Assert(sizeof(km_kbp_attr) = 16);
//keyboardprocessor_debug.h:
Assert(sizeof(km_kbp_state_debug_item) = 432);
Assert(sizeof(km_kbp_state_debug_key_info) = 6);
Assert(sizeof(km_kbp_state_debug_kmx_info) = 416);
Assert(sizeof(km_kbp_state_debug_kmx_option_info) = 164);
Assert(sizeof(km_kbp_debug_type) = 4);
end.