mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-08 01:45:32 +00:00
Merge pull request #10472 from keymanapp/feat/developer/10416-10458-ldml-debugger-markers
feat(developer): LDML keyboard test window marker support 🌱
This commit is contained in:
commit
fa91bdcd85
20 changed files with 347 additions and 437 deletions
|
|
@ -92,7 +92,7 @@ km_core_state_get_intermediate_context(km_core_state *state, km_core_context_ite
|
|||
##### Description:
|
||||
Free the allocated memory belonging to a `km_core_context_item` array previously
|
||||
returned by `km_core_state_get_intermediate_context` (internally, also
|
||||
`context_items_from_utf16` and `context_get`)
|
||||
`context_items_from_utf16` and `km_core_context_get`)
|
||||
##### Parameters:
|
||||
- __context_items__: A pointer to the start of the `km_core_context_item` array
|
||||
to be disposed of.
|
||||
|
|
@ -182,6 +182,41 @@ KMN_API
|
|||
size_t
|
||||
km_core_context_item_list_size(km_core_context_item const *context_items);
|
||||
|
||||
/**
|
||||
*
|
||||
* Copies all items in the context into a new array and returns the new array.
|
||||
* This must be disposed of by caller using `km_core_context_items_dispose`.
|
||||
*
|
||||
* @return km_core_status
|
||||
* * `KM_CORE_STATUS_OK`: On success.
|
||||
* * `KM_CORE_STATUS_INVALID_ARGUMENT`: If non-optional parameters are
|
||||
* null.
|
||||
* * `KM_CORE_STATUS_NO_MEM`: In the event not enough memory can be
|
||||
* allocated for the output buffer.
|
||||
*
|
||||
* @param context A pointer to an opaque context object
|
||||
* @param out A pointer to the result variable: A pointer to the start
|
||||
* of the `km_core_context_item` array containing a copy of
|
||||
* the context. Terminated with a type of `KM_CORE_CT_END`.
|
||||
* Must be disposed of with
|
||||
* `km_core_context_items_dispose`.
|
||||
*/
|
||||
KMN_API
|
||||
km_core_status
|
||||
km_core_context_get(km_core_context const *context,
|
||||
km_core_context_item **out);
|
||||
|
||||
/**
|
||||
* Return the number of items in the context.
|
||||
*
|
||||
* @return size_t The number of items in the context, and will return 0 if
|
||||
* passed a null `context` pointer.
|
||||
* @param context A pointer to an opaque context object
|
||||
*/
|
||||
KMN_API
|
||||
size_t
|
||||
km_core_context_length(km_core_context *);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ icu::UnicodeString context_items_to_unicode_string(km_core_context const *contex
|
|||
|
||||
km_core_context_item *items = nullptr;
|
||||
km_core_status status;
|
||||
if((status = context_get(context, &items)) != KM_CORE_STATUS_OK) {
|
||||
if((status = km_core_context_get(context, &items)) != KM_CORE_STATUS_OK) {
|
||||
DebugLog("Failed to retrieve context with %s", status);
|
||||
return nullString;
|
||||
}
|
||||
|
|
@ -297,8 +297,8 @@ bool km::core::actions_update_app_context_nfu(
|
|||
km_core_status status = KM_CORE_STATUS_OK;
|
||||
km_core_context_item *items = nullptr;
|
||||
|
||||
if((status = context_get(cached_context, &items)) != KM_CORE_STATUS_OK) {
|
||||
DebugLog("context_get failed with %d", status);
|
||||
if((status = km_core_context_get(cached_context, &items)) != KM_CORE_STATUS_OK) {
|
||||
DebugLog("km_core_context_get failed with %d", status);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -169,38 +169,6 @@ km_core_status
|
|||
context_items_to_utf32(km_core_context_item const *item,
|
||||
km_core_usv *buf,
|
||||
size_t *buf_size);
|
||||
/**
|
||||
*
|
||||
* Copies all items in the context into a new array and returns the new array.
|
||||
* This must be disposed of by caller using `km_core_context_items_dispose`.
|
||||
*
|
||||
* @return km_core_status
|
||||
* * `KM_CORE_STATUS_OK`: On success.
|
||||
* * `KM_CORE_STATUS_INVALID_ARGUMENT`: If non-optional parameters are
|
||||
* null.
|
||||
* * `KM_CORE_STATUS_NO_MEM`: In the event not enough memory can be
|
||||
* allocated for the output buffer.
|
||||
*
|
||||
* @param context A pointer to an opaque context object
|
||||
* @param out A pointer to the result variable: A pointer to the start
|
||||
* of the `km_core_context_item` array containing a copy of
|
||||
* the context. Terminated with a type of `KM_CORE_CT_END`.
|
||||
* Must be disposed of with
|
||||
* `km_core_context_items_dispose`.
|
||||
*/
|
||||
km_core_status
|
||||
context_get(km_core_context const *context,
|
||||
km_core_context_item **out);
|
||||
|
||||
/**
|
||||
* Return the number of items in the context.
|
||||
*
|
||||
* @return size_t The number of items in the context, and will return 0 if
|
||||
* passed a null `context` pointer.
|
||||
* @param context A pointer to an opaque context object
|
||||
*/
|
||||
size_t
|
||||
context_length(km_core_context *);
|
||||
|
||||
/**
|
||||
* Add more items to the end (insertion point) of the context. If these exceed
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ km_core_cp* km::core::get_context_as_string(km_core_context *context) {
|
|||
size_t buf_size = 0;
|
||||
km_core_context_item* context_items = nullptr;
|
||||
|
||||
if(context_get(context, &context_items) != KM_CORE_STATUS_OK) {
|
||||
if(km_core_context_get(context, &context_items) != KM_CORE_STATUS_OK) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ km_core_status km_core_context_set(km_core_context *ctxt, km_core_context_item c
|
|||
}
|
||||
|
||||
|
||||
km_core_status context_get(km_core_context const *ctxt,
|
||||
km_core_status km_core_context_get(km_core_context const *ctxt,
|
||||
km_core_context_item **out_ptr)
|
||||
{
|
||||
assert(ctxt); assert(out_ptr);
|
||||
|
|
@ -184,7 +184,7 @@ void km_core_context_clear(km_core_context *ctxt)
|
|||
}
|
||||
|
||||
|
||||
size_t context_length(km_core_context *ctxt)
|
||||
size_t km_core_context_length(km_core_context *ctxt)
|
||||
{
|
||||
assert(ctxt);
|
||||
return ctxt ? ctxt->size() : 0;
|
||||
|
|
|
|||
|
|
@ -310,11 +310,11 @@ km_core_cp * km_core_state_context_debug(
|
|||
return _new_error_string(u"<error retrieving intermediate context>");
|
||||
}
|
||||
} else if(context_type == KM_CORE_DEBUG_CONTEXT_CACHED) {
|
||||
if(context_get(km_core_state_context(state), &context_items) != KM_CORE_STATUS_OK) {
|
||||
if(km_core_context_get(km_core_state_context(state), &context_items) != KM_CORE_STATUS_OK) {
|
||||
return _new_error_string(u"<error retrieving cached context>");
|
||||
}
|
||||
} else if(context_type == KM_CORE_DEBUG_CONTEXT_APP) {
|
||||
if(context_get(km_core_state_app_context(state), &context_items) != KM_CORE_STATUS_OK) {
|
||||
if(km_core_context_get(km_core_state_app_context(state), &context_items) != KM_CORE_STATUS_OK) {
|
||||
return _new_error_string(u"<error retrieving app context>");
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -218,6 +218,16 @@ int main(int argc, char *argv []) {
|
|||
}
|
||||
console_color::enabled = console_color::isaterminal() || arg_color;
|
||||
|
||||
km_core_actions act = {0};
|
||||
|
||||
std::cout << "sizeof(km_core_actions): " << sizeof(km_core_actions) << std::endl;
|
||||
std::cout << "&km_core_actions.code_points_to_delete: " << ((intptr_t)(&act.code_points_to_delete)-(intptr_t)(&act)) << std::endl;
|
||||
std::cout << "&km_core_actions.output: " << ((intptr_t)(&act.output)-(intptr_t)(&act)) << std::endl;
|
||||
std::cout << "&km_core_actions.persist_options: " << ((intptr_t)(&act.persist_options)-(intptr_t)(&act)) << std::endl;
|
||||
std::cout << "&km_core_actions.do_alert: " << ((intptr_t)(&act.do_alert)-(intptr_t)(&act)) << std::endl;
|
||||
std::cout << "&km_core_actions.emit_keystroke: " << ((intptr_t)(&act.emit_keystroke)-(intptr_t)(&act)) << std::endl;
|
||||
std::cout << "&km_core_actions.new_caps_lock_state: " << ((intptr_t)(&act.new_caps_lock_state)-(intptr_t)(&act)) << std::endl;
|
||||
|
||||
// actions
|
||||
test_two_backspaces();
|
||||
test_marker_text_interleaved();
|
||||
|
|
|
|||
|
|
@ -79,19 +79,19 @@ int main(int, char * [])
|
|||
km_core_context_items_dispose(ctxt2);
|
||||
|
||||
// Test lengths, these are Unicode Scalar Values, not utf16 codeunits.
|
||||
if(context_length(&mock_ctxt1) != bmp_ctxt_size) return __LINE__;
|
||||
if(context_length(&mock_ctxt2) != smp_ctxt_size) return __LINE__;
|
||||
if(km_core_context_length(&mock_ctxt1) != bmp_ctxt_size) return __LINE__;
|
||||
if(km_core_context_length(&mock_ctxt2) != smp_ctxt_size) return __LINE__;
|
||||
|
||||
// retrieve bmp context and check it's okay.
|
||||
km_core_context_item *tmp_ctxt;
|
||||
try_status(context_get(&mock_ctxt1, &tmp_ctxt));
|
||||
try_status(km_core_context_get(&mock_ctxt1, &tmp_ctxt));
|
||||
ctxt_size=sizeof ctxt_buffer/sizeof(km_core_cp);
|
||||
try_status(context_items_to_utf16(tmp_ctxt, ctxt_buffer, &ctxt_size));
|
||||
km_core_context_items_dispose(tmp_ctxt);
|
||||
if (initial_bmp_context != ctxt_buffer) return __LINE__;
|
||||
|
||||
// retrieve smp context and check it's okay.
|
||||
try_status(context_get(&mock_ctxt2, &tmp_ctxt));
|
||||
try_status(km_core_context_get(&mock_ctxt2, &tmp_ctxt));
|
||||
ctxt_size=sizeof ctxt_buffer/sizeof(km_core_cp);
|
||||
try_status(context_items_to_utf16(tmp_ctxt, ctxt_buffer, &ctxt_size));
|
||||
km_core_context_items_dispose(tmp_ctxt);
|
||||
|
|
@ -99,7 +99,7 @@ int main(int, char * [])
|
|||
|
||||
// Call km_core_context_clear
|
||||
km_core_context_clear(&mock_ctxt2);
|
||||
if(context_length(&mock_ctxt2) != 0) return __LINE__;
|
||||
if(km_core_context_length(&mock_ctxt2) != 0) return __LINE__;
|
||||
|
||||
// Mutation tests
|
||||
try_status(context_shrink(&mock_ctxt1, 42, nullptr));
|
||||
|
|
@ -117,7 +117,7 @@ int main(int, char * [])
|
|||
|
||||
// Check it matches. The marker will be elided during the conversion.
|
||||
ctxt_size=sizeof ctxt_buffer/sizeof(km_core_cp);
|
||||
try_status(context_get(&mock_ctxt1, &tmp_ctxt));
|
||||
try_status(km_core_context_get(&mock_ctxt1, &tmp_ctxt));
|
||||
try_status(context_items_to_utf16(tmp_ctxt, ctxt_buffer, &ctxt_size));
|
||||
if (std::u16string(u"Hello World!") != ctxt_buffer) return __LINE__;
|
||||
km_core_context_items_dispose(tmp_ctxt);
|
||||
|
|
@ -128,7 +128,7 @@ int main(int, char * [])
|
|||
// expected if you go by the test string above.
|
||||
try_status(context_shrink(&mock_ctxt1, 8, ctxt1));
|
||||
ctxt_size=sizeof ctxt_buffer/sizeof(km_core_cp);
|
||||
try_status(context_get(&mock_ctxt1, &tmp_ctxt));
|
||||
try_status(km_core_context_get(&mock_ctxt1, &tmp_ctxt));
|
||||
try_status(context_items_to_utf16(tmp_ctxt, ctxt_buffer, &ctxt_size));
|
||||
if (std::u16string(u"Bye, Hello") != ctxt_buffer) return __LINE__;
|
||||
|
||||
|
|
|
|||
|
|
@ -133,9 +133,9 @@ int main(int argc, char * argv[])
|
|||
try_status(context_items_from_utf16(u"Hello 😁", &citems));
|
||||
try_status(km_core_context_set(km_core_state_context(test_state), citems));
|
||||
km_core_context_items_dispose(citems);
|
||||
if(context_length(km_core_state_context(test_state)) != 7)
|
||||
if(km_core_context_length(km_core_state_context(test_state)) != 7)
|
||||
return __LINE__;
|
||||
if(context_length(km_core_state_context(test_clone)) != 0)
|
||||
if(km_core_context_length(km_core_state_context(test_clone)) != 0)
|
||||
return __LINE__;
|
||||
|
||||
// Overwrite some data.
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ setup(const char *keyboard, const km_core_cp *context) {
|
|||
bool
|
||||
is_identical_context(km_core_cp const *cached_context) {
|
||||
size_t buf_size;
|
||||
try_status(context_get(km_core_state_context(test_state), &citems));
|
||||
try_status(km_core_context_get(km_core_state_context(test_state), &citems));
|
||||
try_status(context_items_to_utf16(citems, nullptr, &buf_size));
|
||||
km_core_cp *new_cached_context = new km_core_cp[buf_size];
|
||||
try_status(context_items_to_utf16(citems, new_cached_context, &buf_size));
|
||||
|
|
@ -145,7 +145,7 @@ test_context_set_if_needed_cached_context_has_markers() {
|
|||
|
||||
km_core_context_item *citems_new;
|
||||
|
||||
try_status(context_get(km_core_state_context(test_state), &citems_new));
|
||||
try_status(km_core_context_get(km_core_state_context(test_state), &citems_new));
|
||||
|
||||
for (int i = 0; citems[i].type || citems_new[i].type; i++) {
|
||||
assert(citems_new[i].type == citems[i].type);
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ run_test(const km::core::path &source, const km::core::path &compiled) {
|
|||
// Compare context and text store at each step
|
||||
// should be identical unless an action has caused the context to be invalidated
|
||||
size_t n = 0;
|
||||
try_status(context_get(km_core_state_context(test_state), &citems));
|
||||
try_status(km_core_context_get(km_core_state_context(test_state), &citems));
|
||||
try_status(context_items_to_utf16(citems, nullptr, &n));
|
||||
km_core_cp *core_context_str = new km_core_cp[n];
|
||||
try_status(context_items_to_utf16(citems, core_context_str, &n));
|
||||
|
|
@ -271,7 +271,7 @@ run_test(const km::core::path &source, const km::core::path &compiled) {
|
|||
|
||||
// Compare final output - retrieve internal context
|
||||
size_t n = 0;
|
||||
try_status(context_get(km_core_state_context(test_state), &citems));
|
||||
try_status(km_core_context_get(km_core_state_context(test_state), &citems));
|
||||
try_status(context_items_to_utf16(citems, nullptr, &n));
|
||||
km_core_cp *core_context_str = new km_core_cp[n];
|
||||
try_status(context_items_to_utf16(citems, core_context_str, &n));
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ verify_context(std::u16string& text_store, km_core_state* &test_state, std::vect
|
|||
// Compare context and text store at each step - should be identical
|
||||
size_t n = 0;
|
||||
km_core_context_item* citems = nullptr;
|
||||
try_status(context_get(km_core_state_context(test_state), &citems));
|
||||
try_status(km_core_context_get(km_core_state_context(test_state), &citems));
|
||||
try_status(context_items_to_utf16(citems, nullptr, &n));
|
||||
km_core_cp *buf = new km_core_cp[n];
|
||||
try_status(context_items_to_utf16(citems, buf, &n));
|
||||
|
|
|
|||
|
|
@ -63,9 +63,9 @@ bool is_identical_context(km_core_cp const *cached_context, km_core_debug_contex
|
|||
debug_context(context_type);
|
||||
|
||||
if(context_type == KM_CORE_DEBUG_CONTEXT_APP) {
|
||||
try_status(context_get(km_core_state_app_context(test_state), &citems));
|
||||
try_status(km_core_context_get(km_core_state_app_context(test_state), &citems));
|
||||
} else {
|
||||
try_status(context_get(km_core_state_context(test_state), &citems));
|
||||
try_status(km_core_context_get(km_core_state_context(test_state), &citems));
|
||||
}
|
||||
try_status(context_items_to_utf16(citems, nullptr, &buf_size));
|
||||
km_core_cp* new_cached_context = new km_core_cp[buf_size];
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ inherited frmLdmlKeyboardDebug: TfrmLdmlKeyboardDebug
|
|||
OnChange = memoChange
|
||||
OnClick = memoClick
|
||||
OnEnter = memoGotFocus
|
||||
OnExit = memoLostFocus
|
||||
OnKeyUp = memoKeyUp
|
||||
OnMessage = memoMessage
|
||||
IsDebugging = False
|
||||
|
|
|
|||
|
|
@ -32,8 +32,6 @@ uses
|
|||
PaintPanel,
|
||||
KeymanDeveloperDebuggerMemo,
|
||||
Keyman.System.Debug.DebugCore,
|
||||
Keyman.System.Debug.DebugEvent,
|
||||
Keyman.System.Debug.DebugUIStatus,
|
||||
Keyman.System.Debug.DebugUtils,
|
||||
Keyman.System.KeymanCore,
|
||||
Keyman.System.KeymanCoreDebug,
|
||||
|
|
@ -42,6 +40,13 @@ uses
|
|||
UfrmTike,
|
||||
UserMessages;
|
||||
|
||||
type
|
||||
TLdmlDebugUIStatus = (
|
||||
duiStarting,
|
||||
duiTest,
|
||||
duiClosing
|
||||
);
|
||||
|
||||
type
|
||||
TfrmLdmlKeyboardDebug = class(TTikeForm)
|
||||
memo: TKeymanDeveloperDebuggerMemo;
|
||||
|
|
@ -56,7 +61,6 @@ type
|
|||
mnuPaste: TMenuItem; // I4808
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure memoGotFocus(Sender: TObject);
|
||||
procedure memoLostFocus(Sender: TObject);
|
||||
procedure FormDestroy(Sender: TObject);
|
||||
procedure FormClose(Sender: TObject; var Action: TCloseAction);
|
||||
procedure memoChange(Sender: TObject);
|
||||
|
|
@ -70,27 +74,15 @@ type
|
|||
procedure memoKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
|
||||
procedure FormResize(Sender: TObject);
|
||||
private
|
||||
|
||||
FDebugVisible: Boolean;
|
||||
FRunning: Boolean;
|
||||
FFileName: string;
|
||||
debugkeyboard: TDebugKeyboard;
|
||||
_FCurrentEvent: Integer;
|
||||
FDefaultFont: Boolean;
|
||||
FEvents: TDebugEventList;
|
||||
FUIStatus: TDebugUIStatus;
|
||||
FUIStatus: TLdmlDebugUIStatus;
|
||||
FUIDisabled: Boolean;
|
||||
|
||||
{ Deadkey member variables }
|
||||
FSelectedDeadkey: TDeadKeyInfo;
|
||||
FSavedSelection: TMemoSelection;
|
||||
|
||||
procedure ResetEvents;
|
||||
procedure ExecuteEvent(n: Integer);
|
||||
procedure ExecuteEventAction(n: Integer);
|
||||
procedure SetUIStatus(const Value: TDebugUIStatus);
|
||||
procedure DisableUI;
|
||||
procedure EnableUI;
|
||||
function GetStatusText: string;
|
||||
procedure SetStatusText(Value: string);
|
||||
|
||||
|
|
@ -102,7 +94,6 @@ type
|
|||
FDebugFileName: WideString;
|
||||
procedure ClearDeadkeys;
|
||||
procedure ClearDeadkeyStyle;
|
||||
function GetCurrentEvent: TDebugEvent;
|
||||
procedure UninitDeadkeys;
|
||||
procedure UpdateDeadkeyDisplay;
|
||||
procedure UpdateDeadkeys;
|
||||
|
|
@ -114,8 +105,7 @@ type
|
|||
procedure CleanupCoreState;
|
||||
function SetKeyEventContext: Boolean;
|
||||
function HandleMemoKeydown(var Message: TMessage): Boolean;
|
||||
procedure SetCurrentEvent(Value: Integer);
|
||||
procedure Run;
|
||||
procedure Run(vkey: Word);
|
||||
|
||||
protected
|
||||
function GetHelpTopic: string; override;
|
||||
|
|
@ -132,7 +122,7 @@ type
|
|||
|
||||
function GetDebugKeyboard: TDebugKeyboard;
|
||||
|
||||
property UIStatus: TDebugUIStatus read FUIStatus write SetUIStatus;
|
||||
property UIStatus: TLdmlDebugUIStatus read FUIStatus write FUIStatus;
|
||||
|
||||
property DebugFileName: WideString read FDebugFileName write FDebugFileName;
|
||||
property CompiledFileName: string read FFileName write FFileName; // I4695
|
||||
|
|
@ -141,11 +131,7 @@ type
|
|||
procedure ShowDebugForm;
|
||||
procedure HideDebugForm;
|
||||
|
||||
property DebugVisible: Boolean read FDebugVisible;
|
||||
|
||||
function ShortcutDisabled(Key: Word): Boolean;
|
||||
|
||||
property CurrentEvent: TDebugEvent read GetCurrentEvent;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
|
@ -153,20 +139,18 @@ implementation
|
|||
{$R *.DFM}
|
||||
|
||||
uses
|
||||
System.Character,
|
||||
System.Math,
|
||||
|
||||
Keyman.Developer.System.HelpTopics,
|
||||
|
||||
ActiveX,
|
||||
dmActionsDebugger,
|
||||
dmActionsMain,
|
||||
Glossary,
|
||||
Keyman.Developer.System.Project.ProjectLog,
|
||||
Keyman.Developer.UI.Project.ProjectUI,
|
||||
Keyman.Developer.UI.UfrmLdmlKeyboardEditor,
|
||||
Keyman.UI.Debug.CharacterGridRenderer,
|
||||
KeyNames,
|
||||
kmxfile,
|
||||
kmxfileconsts,
|
||||
ErrorControlledRegistry,
|
||||
RegistryKeys,
|
||||
KeymanDeveloperOptions,
|
||||
KeymanDeveloperUtils,
|
||||
ScanCodeMap,
|
||||
|
|
@ -174,13 +158,9 @@ uses
|
|||
UfrmEditor,
|
||||
UfrmMain,
|
||||
UfrmMessages,
|
||||
UfrmRegressionTestFailure,
|
||||
UfrmSelectSystemKeyboard,
|
||||
Unicode,
|
||||
utilstr,
|
||||
UTikeDebugMode,
|
||||
VKeys,
|
||||
XString;
|
||||
utilstr;
|
||||
|
||||
const
|
||||
// WM_KEYDOWN bits; KEYFLAG_KEYMAN is a reserved value
|
||||
|
|
@ -197,18 +177,19 @@ begin
|
|||
|
||||
FDeadkeys := TDebugDeadkeyInfoList.Create;
|
||||
|
||||
FUIStatus := duiInvalid;
|
||||
FEvents := TDebugEventList.Create;
|
||||
FUIStatus := duiStarting;
|
||||
FDefaultFont := True;
|
||||
memo.Align := alClient;
|
||||
memo.ReadOnly := False;
|
||||
memo.IsDebugging := True;
|
||||
StatusText := 'Simple Test';
|
||||
|
||||
UIStatus := duiReadyForInput;
|
||||
UIStatus := duiTest;
|
||||
end;
|
||||
|
||||
procedure TfrmLdmlKeyboardDebug.FormDestroy(Sender: TObject);
|
||||
begin
|
||||
ResetDebug;
|
||||
FreeAndNil(FEvents);
|
||||
UninitDeadkeys;
|
||||
end;
|
||||
|
||||
|
|
@ -224,9 +205,6 @@ end;
|
|||
|
||||
procedure TfrmLdmlKeyboardDebug.memoGotFocus(Sender: TObject);
|
||||
begin
|
||||
if UIStatus = duiReadyForInput then
|
||||
UIStatus := duiFocusedForInput;
|
||||
|
||||
memoSelMove(memo);
|
||||
end;
|
||||
|
||||
|
|
@ -236,30 +214,15 @@ begin
|
|||
memoSelMove(memo);
|
||||
end;
|
||||
|
||||
procedure TfrmLdmlKeyboardDebug.memoLostFocus(Sender: TObject);
|
||||
begin
|
||||
if UIStatus = duiFocusedForInput then
|
||||
UIStatus := duiReadyForInput;
|
||||
end;
|
||||
|
||||
function TfrmLdmlKeyboardDebug.HandleMemoKeydown(var Message: TMessage): Boolean;
|
||||
begin
|
||||
if (Message.wParam = VK_ESCAPE) and
|
||||
(GetKeyState(VK_SHIFT) < 0) and
|
||||
(UIStatus <> duiPaused) then // I4033
|
||||
UIStatus := duiPaused
|
||||
else if (Message.wParam = VK_F6) and
|
||||
if (Message.wParam = VK_F6) and
|
||||
(GetKeyState(VK_CONTROL) >= 0) and
|
||||
(GetKeyState(VK_MENU) >= 0) and
|
||||
(UIStatus <> duiFocusedForInput) then
|
||||
(GetKeyState(VK_MENU) >= 0) then
|
||||
begin
|
||||
EditorMemo.SetFocus;
|
||||
end
|
||||
else if (Message.wParam = VK_ESCAPE) and
|
||||
(GetKeyState(VK_SHIFT) < 0) and
|
||||
(UIStatus = duiPaused) then
|
||||
UIStatus := duiFocusedForInput
|
||||
else if UIStatus in [duiTest, duiFocusedForInput] then
|
||||
else if UIStatus = duiTest then
|
||||
begin
|
||||
Exit(ProcessKeyEvent(Message));
|
||||
end
|
||||
|
|
@ -274,9 +237,9 @@ procedure TfrmLdmlKeyboardDebug.memoMessage(Sender: TObject; var Message: TMessa
|
|||
begin
|
||||
Handled := False;
|
||||
|
||||
if UIStatus = duiClosing then
|
||||
if UIStatus <> duiTest then
|
||||
begin
|
||||
Exit; // Don't process while destroying...
|
||||
Exit;
|
||||
end;
|
||||
|
||||
case Message.Msg of
|
||||
|
|
@ -384,63 +347,35 @@ begin
|
|||
Exit(True);
|
||||
end;
|
||||
|
||||
FEvents.Clear;
|
||||
FEvents.AddLdmlStateItems(FDebugCore.State, vkey, modifier, debugkeyboard);
|
||||
Run(vkey);
|
||||
|
||||
FRunning := True;
|
||||
SetCurrentEvent(0);
|
||||
Run;
|
||||
UpdateDeadkeys;
|
||||
end
|
||||
else
|
||||
begin
|
||||
FEvents.Clear;
|
||||
Result := False;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TfrmLdmlKeyboardDebug.SetCurrentEvent(Value: Integer);
|
||||
function UsvToString(p: pkm_core_usv): string;
|
||||
begin
|
||||
_FCurrentEvent := Value;
|
||||
Result := '';
|
||||
while p^ <> 0 do
|
||||
begin
|
||||
Result := Result + Char.ConvertFromUtf32(p^);
|
||||
Inc(p);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TfrmLdmlKeyboardDebug.Run;
|
||||
begin
|
||||
FRunning := True;
|
||||
try
|
||||
while (_FCurrentEvent < FEvents.Count) do
|
||||
begin
|
||||
ExecuteEvent(_FCurrentEvent);
|
||||
SetCurrentEvent(_FCurrentEvent + 1);
|
||||
if UIStatus = duiPaused then // I4033
|
||||
Exit;
|
||||
end;
|
||||
finally
|
||||
FRunning := False;
|
||||
EnableUI;
|
||||
UpdateCharacterGrid;
|
||||
// We want to refresh the memo and character grid for rapid typing
|
||||
memo.Update;
|
||||
sgChars.Update;
|
||||
procedure TfrmLdmlKeyboardDebug.Run(vkey: Word);
|
||||
|
||||
procedure DoAlert;
|
||||
begin
|
||||
MessageBeep(0);
|
||||
end;
|
||||
|
||||
if UIStatus <> duiTest then
|
||||
if memo.Focused
|
||||
then UIStatus := duiFocusedForInput
|
||||
else UIStatus := duiReadyForInput;
|
||||
end;
|
||||
|
||||
{ Stores }
|
||||
|
||||
procedure TfrmLdmlKeyboardDebug.ExecuteEvent(n: Integer);
|
||||
begin
|
||||
memo.ReadOnly := False;
|
||||
memo.Selection := FSavedSelection;
|
||||
ExecuteEventAction(n);
|
||||
FSavedSelection := memo.Selection;
|
||||
memo.ReadOnly := True;
|
||||
end;
|
||||
|
||||
procedure TfrmLdmlKeyboardDebug.ExecuteEventAction(n: Integer);
|
||||
type
|
||||
TMemoSelectionState = record
|
||||
Selection: TMemoSelection;
|
||||
|
|
@ -481,126 +416,6 @@ procedure TfrmLdmlKeyboardDebug.ExecuteEventAction(n: Integer);
|
|||
UpdateDeadkeys;
|
||||
end;
|
||||
|
||||
procedure DoBackspace(BackspaceType: km_core_backspace_type);
|
||||
var
|
||||
m, n: Integer;
|
||||
dk: TDeadKeyInfo;
|
||||
state: TMemoSelectionState;
|
||||
begin
|
||||
// Offset is zero-based, but string is 1-based. Beware!
|
||||
state := SaveMemoSelectionState;
|
||||
n := memo.SelStart;
|
||||
m := n;
|
||||
|
||||
if memo.SelLength > 0 then
|
||||
begin
|
||||
// If the memo has a selection, we have given Core an empty context,
|
||||
// which forces it to emit a KM_CORE_BT_UNKNOWN backspace, which is
|
||||
// exactly what we want here. We just delete the selection
|
||||
Assert(BackspaceType = KM_CORE_BT_UNKNOWN);
|
||||
memo.SelText := '';
|
||||
RealignMemoSelectionState(state);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
case BackspaceType of
|
||||
KM_CORE_BT_MARKER:
|
||||
begin
|
||||
Assert(m >= 1);
|
||||
Assert(memo.Text[m] = #$FFFC);
|
||||
dk := FDeadkeys.GetFromPosition(m-1);
|
||||
Assert(Assigned(dk));
|
||||
dk.Delete;
|
||||
Dec(m);
|
||||
end;
|
||||
KM_CORE_BT_CHAR:
|
||||
begin
|
||||
Assert(m >= 1);
|
||||
Assert(memo.Text[m] <> #$FFFC);
|
||||
// Delete surrogate pairs
|
||||
if (m > 1) and
|
||||
Uni_IsSurrogate2(memo.Text[m]) and
|
||||
Uni_IsSurrogate1(memo.Text[m-1]) then
|
||||
Dec(m, 2)
|
||||
// Delete \r\n line breaks
|
||||
else if (m > 1) and
|
||||
(memo.Text[m] = #$0A) and
|
||||
(memo.Text[m-1] = #$0D) then
|
||||
Dec(m, 2)
|
||||
else
|
||||
Dec(m);
|
||||
end;
|
||||
KM_CORE_BT_UNKNOWN:
|
||||
begin
|
||||
while (m >= 1) and (memo.Text[m] = #$FFFC) do
|
||||
begin
|
||||
dk := FDeadkeys.GetFromPosition(m-1);
|
||||
Assert(Assigned(dk));
|
||||
dk.Delete;
|
||||
Dec(m);
|
||||
end;
|
||||
|
||||
// Delete character
|
||||
if (m > 1) and
|
||||
Uni_IsSurrogate2(memo.Text[m]) and
|
||||
Uni_IsSurrogate1(memo.Text[m-1]) then
|
||||
Dec(m, 2)
|
||||
else
|
||||
Dec(m);
|
||||
|
||||
// Also delete deadkeys to left of current character
|
||||
while (m >= 1) and (memo.Text[m] = #$FFFC) do
|
||||
begin
|
||||
dk := FDeadkeys.GetFromPosition(m-1);
|
||||
Assert(Assigned(dk));
|
||||
dk.Delete;
|
||||
Dec(m);
|
||||
end;
|
||||
end;
|
||||
else
|
||||
Assert(False, 'Unrecognised backspace type');
|
||||
end;
|
||||
|
||||
memo.Text := Copy(memo.Text, 1, m) + Copy(memo.Text, n+1, MaxInt);
|
||||
memo.SelStart := m;
|
||||
|
||||
RealignMemoSelectionState(state);
|
||||
end;
|
||||
|
||||
procedure DoDeadkey(dkCode: Integer);
|
||||
var
|
||||
dk: TDeadKeyInfo;
|
||||
i: Integer;
|
||||
state: TMemoSelectionState;
|
||||
begin
|
||||
dk := TDeadKeyInfo.Create;
|
||||
dk.Memo := memo;
|
||||
dk.Deadkey := nil;
|
||||
for i := 0 to debugkeyboard.Deadkeys.Count - 1 do
|
||||
if debugkeyboard.Deadkeys[i].Value = dkCode then
|
||||
begin
|
||||
dk.Deadkey := debugkeyboard.Deadkeys[i];
|
||||
Break;
|
||||
end;
|
||||
if not Assigned(dk.Deadkey) then
|
||||
dk.Free //silent failure
|
||||
else
|
||||
begin
|
||||
state := SaveMemoSelectionState;
|
||||
|
||||
memo.SelText := WideChar($FFFC);
|
||||
memo.SelStart := memo.SelStart + memo.SelLength; // I1603
|
||||
memo.SelLength := 0;
|
||||
dk.Position := memo.SelStart - 1;
|
||||
|
||||
RealignMemoSelectionState(state);
|
||||
|
||||
FDeadkeys.Add(dk);
|
||||
UpdateDeadkeyDisplay;
|
||||
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure DoHandleShortcut(vk: UINT);
|
||||
begin
|
||||
// Because we disable shortcuts in the debug memo, there are a small set of
|
||||
|
|
@ -610,7 +425,13 @@ procedure TfrmLdmlKeyboardDebug.ExecuteEventAction(n: Integer);
|
|||
// apart from Ctrl+A
|
||||
|
||||
if GetKeyState(VK_CONTROL) >= 0 then
|
||||
begin
|
||||
if (vk = VK_RETURN) and (GetKeyState(VK_MENU) >= 0) then
|
||||
begin
|
||||
memo.SelText := #13#10;
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
case vk of
|
||||
Ord('A'): memo.SelectAll;
|
||||
|
|
@ -653,85 +474,187 @@ procedure TfrmLdmlKeyboardDebug.ExecuteEventAction(n: Integer);
|
|||
end;
|
||||
end;
|
||||
|
||||
procedure DoChar(const text: string);
|
||||
function ContextToDebugString(context_items: pkm_core_context_item; offset, length: Integer): string;
|
||||
var
|
||||
state: TMemoSelectionState;
|
||||
outText: array of UInt32;
|
||||
ox: Integer;
|
||||
pc: pkm_core_context_item;
|
||||
dk: TDeadKeyInfo;
|
||||
begin
|
||||
state := SaveMemoSelectionState;
|
||||
// Line breaks: replace \r (0x0D) with \r\n (0x0D 0x0A) so line breaks work
|
||||
memo.SelText := ReplaceStr(Text, #$0D, #$0D#$0A);
|
||||
memo.SelStart := memo.SelStart + memo.SelLength; // I1603
|
||||
memo.SelLength := 0;
|
||||
RealignMemoSelectionState(state);
|
||||
end;
|
||||
SetLength(outText, length + 1);
|
||||
|
||||
procedure DoBell;
|
||||
begin
|
||||
MessageBeep(0);
|
||||
end;
|
||||
|
||||
begin
|
||||
DisableUI;
|
||||
with FEvents[n].Action do
|
||||
begin
|
||||
case ActionType of
|
||||
KM_CORE_IT_EMIT_KEYSTROKE: DoEmitKeystroke(dwData);
|
||||
KM_CORE_IT_CHAR: DoChar(Text);
|
||||
KM_CORE_IT_MARKER: DoDeadkey(dwData);
|
||||
KM_CORE_IT_ALERT: DoBell;
|
||||
KM_CORE_IT_BACK: DoBackspace(km_core_backspace_type(dwData));
|
||||
KM_CORE_IT_PERSIST_OPT: ; //TODO
|
||||
KM_CORE_IT_CAPSLOCK: ; //TODO
|
||||
KM_CORE_IT_INVALIDATE_CONTEXT: ; // no-op
|
||||
ox := 0;
|
||||
pc := context_items;
|
||||
while pc._type <> KM_CORE_CT_END do
|
||||
begin
|
||||
if pc._type = KM_CORE_CT_CHAR then
|
||||
outText[ox] := pc.character
|
||||
else
|
||||
begin
|
||||
dk := TDeadKeyInfo.Create;
|
||||
dk.Deadkey := TDebugDeadkey.Create;
|
||||
dk.Deadkey.Name := '\m{'+IntToStr(pc.marker)+'}';
|
||||
dk.Deadkey.Value := pc.marker;
|
||||
dk.Position := ox + offset;
|
||||
dk.SavedPosition := ox + offset;
|
||||
FDeadkeys.Add(dk);
|
||||
outText[ox] := $FFFC;
|
||||
end;
|
||||
Inc(pc);
|
||||
Inc(ox);
|
||||
end;
|
||||
// AddDEBUG(Format('%d: %d [%s]', [ActionType, dwData, Text]));
|
||||
end;
|
||||
EnableUI;
|
||||
end;
|
||||
|
||||
procedure TfrmLdmlKeyboardDebug.DisableUI;
|
||||
outText[ox] := 0;
|
||||
|
||||
Result := USVToString(@outText[0]);
|
||||
end;
|
||||
|
||||
var
|
||||
actions: pkm_core_actions;
|
||||
context_items: pkm_core_context_item;
|
||||
selection: TMemoSelection;
|
||||
output: string;
|
||||
lhs, rhs, context: string;
|
||||
status: km_core_status;
|
||||
dk: TDeadKeyInfo;
|
||||
context_items_length: Integer;
|
||||
state: TMemoSelectionState;
|
||||
Adjustment: Integer;
|
||||
begin
|
||||
FUIDisabled := True;
|
||||
// UpdateControlCaptions;
|
||||
end;
|
||||
|
||||
procedure TfrmLdmlKeyboardDebug.EnableUI;
|
||||
begin
|
||||
if not FRunning then
|
||||
actions := km_core_state_get_actions(FDebugCore.State);
|
||||
if actions = nil then
|
||||
begin
|
||||
GetGlobalProjectUI.Log(plsError, FDebugFileName,
|
||||
'Failed to get actions from Keyman Core', 0, 0);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
context_items := nil;
|
||||
status := km_core_context_get(km_core_state_context(FDebugCore.State), @context_items);
|
||||
if status <> KM_CORE_STATUS_OK then
|
||||
begin
|
||||
GetGlobalProjectUI.Log(plsError, FDebugFileName,
|
||||
'Failed to get context from Keyman Core with error '+IntToStr(Ord(Status)), 0, 0);
|
||||
km_core_actions_dispose(actions);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
selection := memo.Selection;
|
||||
|
||||
// TODO: #10471 deleting U+000D U+000A should delete as a unit
|
||||
|
||||
try
|
||||
if (actions.emit_keystroke = 1) and (vkey <> VK_BACK) and
|
||||
(actions.code_points_to_delete = 0) and (actions.output^ = 0) then
|
||||
begin
|
||||
// If the keystroke is being emitted, then it was not matched by LDML, and
|
||||
// must be a frame key. We exclude Bksp as a special case which needs
|
||||
// additional processing. All other frame keys should be passed to the
|
||||
// text control for default processing.
|
||||
end
|
||||
else
|
||||
begin
|
||||
if selection.Finish > selection.Start then
|
||||
begin
|
||||
// We have a selection, so we should remove it first and then continue
|
||||
// as normal. We will have given Core a zero-length context, so we
|
||||
// need to save everything before the start of selection before
|
||||
// continuing, and cleanup any markers that were in the selection
|
||||
if (actions.emit_keystroke = 0) or (vkey = VK_BACK) then
|
||||
begin
|
||||
state := SaveMemoSelectionState;
|
||||
memo.SelText := '';
|
||||
RealignMemoSelectionState(state);
|
||||
selection := memo.Selection;
|
||||
end;
|
||||
lhs := Copy(memo.Text, 1, selection.Start);
|
||||
end
|
||||
else
|
||||
lhs := '';
|
||||
|
||||
context := Copy(memo.Text, lhs.Length + 1, selection.Start - lhs.Length);
|
||||
rhs := Copy(memo.Text, lhs.Length + context.Length + 1, MaxInt);
|
||||
|
||||
// Reinsert the context
|
||||
|
||||
context_items_length := km_core_context_length(km_core_state_context(FDebugCore.State));
|
||||
Adjustment := context_items_length - selection.Start + lhs.Length;
|
||||
|
||||
// Delete all markers that are in the context, because we will reinsert
|
||||
// them shortly, and adjust marker positions to right of insertion point
|
||||
|
||||
for dk in FDeadkeys do
|
||||
begin
|
||||
if (dk.Position > lhs.Length) and (dk.Position < selection.Start) then
|
||||
begin
|
||||
dk.Delete;
|
||||
end
|
||||
else if dk.Position >= selection.Start then
|
||||
begin
|
||||
dk.Position := dk.Position + Adjustment;
|
||||
end;
|
||||
end;
|
||||
|
||||
// Build the new context string and create new markers
|
||||
|
||||
output := ContextToDebugString(context_items, lhs.Length, context_items_length);
|
||||
|
||||
// Merge left of context, context, and right of context and update memo
|
||||
// insertion point position
|
||||
|
||||
memo.Text := lhs + output + rhs;
|
||||
selection.Start := lhs.Length + output.Length;
|
||||
selection.Finish := selection.Start;
|
||||
selection.Anchor := selection.Start;
|
||||
memo.Selection := selection;
|
||||
end;
|
||||
|
||||
// actions.persist_options are not currently supported by LDML
|
||||
|
||||
if actions.do_alert <> 0 then
|
||||
begin
|
||||
DoAlert;
|
||||
end;
|
||||
|
||||
if actions.emit_keystroke <> 0 then
|
||||
begin
|
||||
DoEmitKeystroke(vkey);
|
||||
end;
|
||||
|
||||
finally
|
||||
km_core_actions_dispose(actions);
|
||||
km_core_context_items_dispose(context_items);
|
||||
|
||||
FUIDisabled := False;
|
||||
UpdateCharacterGrid;
|
||||
|
||||
// We want to refresh the memo and character grid for rapid typing
|
||||
memo.Update;
|
||||
sgChars.Update;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ Stores }
|
||||
|
||||
procedure TfrmLdmlKeyboardDebug.CleanupCoreState;
|
||||
begin
|
||||
FreeAndNil(FDebugCore);
|
||||
end;
|
||||
|
||||
procedure TfrmLdmlKeyboardDebug.ResetEvents;
|
||||
begin
|
||||
if _FCurrentEvent > 0 then
|
||||
begin
|
||||
FEvents.Clear;
|
||||
SetCurrentEvent(0);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TfrmLdmlKeyboardDebug.HideDebugForm;
|
||||
begin
|
||||
frmKeymanDeveloper.ShowDebug(False); // I4796
|
||||
FDebugVisible := False;
|
||||
ResetDebug;
|
||||
UIStatus := duiReadyForInput;
|
||||
end;
|
||||
|
||||
procedure TfrmLdmlKeyboardDebug.ShowDebugForm;
|
||||
begin
|
||||
UIStatus := duiTest;
|
||||
|
||||
frmKeymanDeveloper.ShowDebug(True); // I4796
|
||||
|
||||
FDebugVisible := True;
|
||||
|
||||
//UpdateFont(nil);
|
||||
if not SetupDebug then
|
||||
Exit;
|
||||
|
||||
|
|
@ -741,8 +664,6 @@ end;
|
|||
procedure TfrmLdmlKeyboardDebug.ResetDebug;
|
||||
begin
|
||||
FreeAndNil(debugkeyboard);
|
||||
SetCurrentEvent(1);
|
||||
ResetEvents;
|
||||
ClearDeadkeys; // I1699
|
||||
CleanupCoreState;
|
||||
memo.Text := '';
|
||||
|
|
@ -783,67 +704,6 @@ begin
|
|||
memo.Font := FFont;
|
||||
end;
|
||||
|
||||
procedure TfrmLdmlKeyboardDebug.SetUIStatus(const Value: TDebugUIStatus);
|
||||
var
|
||||
FOldUIStatus: TDebugUIStatus;
|
||||
begin
|
||||
if FUIStatus <> Value then
|
||||
begin
|
||||
FOldUIStatus := FUIStatus;
|
||||
FUIStatus := Value;
|
||||
|
||||
case Value of
|
||||
duiTest:
|
||||
begin
|
||||
StatusText := 'Simple Test';
|
||||
memo.ReadOnly := False;
|
||||
memo.IsDebugging := True;
|
||||
end;
|
||||
duiFocusedForInput:
|
||||
begin
|
||||
DisableUI;
|
||||
StatusText := 'Focused for input';
|
||||
memo.ReadOnly := False;
|
||||
memo.IsDebugging := True;
|
||||
end;
|
||||
duiReadyForInput:
|
||||
begin
|
||||
if memo.Focused then UIStatus := duiFocusedForInput
|
||||
else
|
||||
begin
|
||||
EnableUI;
|
||||
StatusText := 'Ready for input';
|
||||
memo.ReadOnly := True;
|
||||
memo.IsDebugging := False;
|
||||
end;
|
||||
end;
|
||||
duiPaused:
|
||||
begin
|
||||
EnableUI;
|
||||
FUIDisabled := False; // I4033
|
||||
StatusText := 'Paused';
|
||||
memo.ReadOnly := True;
|
||||
memo.IsDebugging := False;
|
||||
end;
|
||||
end;
|
||||
if FOldUIStatus = duiTest then
|
||||
begin
|
||||
if memo.Focused then
|
||||
begin
|
||||
GetParentForm(memo).ActiveControl := nil;
|
||||
memo.SetFocus;
|
||||
end;
|
||||
end
|
||||
end;
|
||||
end;
|
||||
|
||||
function TfrmLdmlKeyboardDebug.GetCurrentEvent: TDebugEvent;
|
||||
begin
|
||||
if (_FCurrentEvent >= 0) and (_FCurrentEvent < FEvents.Count)
|
||||
then Result := FEvents[_FCurrentEvent]
|
||||
else Result := nil;
|
||||
end;
|
||||
|
||||
function TfrmLdmlKeyboardDebug.GetDebugKeyboard: TDebugKeyboard;
|
||||
begin
|
||||
Result := debugkeyboard;
|
||||
|
|
@ -971,7 +831,6 @@ begin
|
|||
|
||||
if not memo.ReadOnly then
|
||||
begin
|
||||
FSavedSelection := memo.Selection;
|
||||
UpdateCharacterGrid; // I4808
|
||||
end;
|
||||
end;
|
||||
|
|
@ -981,7 +840,8 @@ begin
|
|||
if csDestroying in ComponentState then
|
||||
Exit;
|
||||
|
||||
TCharacterGridRenderer.Fill(sgChars, memo.Text, FDeadkeys, memo.SelStart, memo.SelLength, memo.Selection.Anchor);
|
||||
TCharacterGridRenderer.Fill(sgChars, memo.Text, FDeadkeys, memo.SelStart,
|
||||
memo.SelLength, memo.Selection.Anchor, True);
|
||||
TCharacterGridRenderer.Size(sgChars, memo.Font);
|
||||
end;
|
||||
|
||||
|
|
|
|||
|
|
@ -83,8 +83,6 @@ procedure TfrmLdmlKeyboardEditor.StartDebugging;
|
|||
begin
|
||||
if not IsDebugVisible then
|
||||
begin
|
||||
FDebugForm.UIStatus := duiReadyForInput;
|
||||
|
||||
(ProjectFileUI as TxmlLdmlProjectFileUI).Debug := True; // I4687
|
||||
|
||||
frmMessages.Clear; // I4686
|
||||
|
|
|
|||
|
|
@ -93,9 +93,6 @@ type
|
|||
vk: uint16_t;
|
||||
modifier_state: uint16_t
|
||||
): Boolean; overload;
|
||||
|
||||
function AddLdmlStateItems(state: pkm_core_state; vk,
|
||||
modifier_state: uint16_t; debugkeyboard: TDebugKeyboard): Boolean;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
|
@ -375,36 +372,6 @@ begin
|
|||
Assert(action._type = KM_CORE_IT_END);
|
||||
end;
|
||||
|
||||
function TDebugEventList.AddLdmlStateItems(
|
||||
state: pkm_core_state;
|
||||
vk: uint16_t;
|
||||
modifier_state: uint16_t;
|
||||
debugkeyboard: TDebugKeyboard
|
||||
): Boolean;
|
||||
var
|
||||
action: pkm_core_action_item;
|
||||
begin
|
||||
// TODO: use action struct
|
||||
Result := True;
|
||||
action := km_core_state_action_items(state, nil);
|
||||
while (action._type <> KM_CORE_IT_END) do
|
||||
begin
|
||||
Result := Result and AddActionItem(vk, action);
|
||||
Inc(action);
|
||||
end;
|
||||
|
||||
if action._type = KM_CORE_IT_EMIT_KEYSTROKE then
|
||||
begin
|
||||
// The EMIT_KEYSTROKE action comes after all rules have completed processing
|
||||
Result := Result and AddActionItem(vk, action);
|
||||
Inc(action);
|
||||
end;
|
||||
|
||||
// By the time we get to the end of rule processing, all actions should have
|
||||
// already been undertaken
|
||||
Assert(action._type = KM_CORE_IT_END);
|
||||
end;
|
||||
|
||||
{ TDebugEventRuleData }
|
||||
|
||||
procedure TDebugEventRuleData.FillStoreList(event: pkm_core_state_debug_item; KeyboardMemory: PChar);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ type
|
|||
|
||||
class procedure Fill(grid: TStringGrid; const text: string;
|
||||
deadkeys: TDebugDeadkeyInfoList;
|
||||
SelStart, SelLength, SelAnchor: Integer); static;
|
||||
SelStart, SelLength, SelAnchor: Integer;
|
||||
DeadkeysAreCalledMarkers: Boolean = False); static;
|
||||
class procedure Render(grid: TStringGrid; ACol, ARow: Integer;
|
||||
Rect: TRect; State: TGridDrawState; CharFont: TFont); static;
|
||||
class procedure Size(grid: TStringGrid; CharFont: TFont); static;
|
||||
|
|
@ -36,7 +37,8 @@ uses
|
|||
|
||||
class procedure TCharacterGridRenderer.Fill(grid: TStringGrid;
|
||||
const text: string; deadkeys: TDebugDeadkeyInfoList;
|
||||
SelStart, SelLength, SelAnchor: Integer);
|
||||
SelStart, SelLength, SelAnchor: Integer;
|
||||
DeadkeysAreCalledMarkers: Boolean);
|
||||
type
|
||||
TCellType = (ctChar, ctDeadkey);
|
||||
TCell = record
|
||||
|
|
@ -87,7 +89,9 @@ type
|
|||
if not Assigned(cell.dk)
|
||||
then grid.Cells[x, 0] := '???'
|
||||
else grid.Cells[x, 0] := cell.dk.Deadkey.Name;
|
||||
grid.Cells[x, 1] := 'Deadkey';
|
||||
if DeadkeysAreCalledMarkers
|
||||
then grid.Cells[x, 1] := 'Marker'
|
||||
else grid.Cells[x, 1] := 'Deadkey';
|
||||
end
|
||||
else
|
||||
begin
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ type
|
|||
km_core_virtual_key = uint16_t;
|
||||
|
||||
km_core_usv = uint32_t; // UTF-32
|
||||
pkm_core_usv = ^km_core_usv;
|
||||
km_core_cp = WideChar;
|
||||
pkm_core_cp = ^km_core_cp;
|
||||
|
||||
|
|
@ -70,6 +71,7 @@ type
|
|||
end;
|
||||
|
||||
pkm_core_context_item = ^km_core_context_item;
|
||||
ppkm_core_context_item = ^pkm_core_context_item;
|
||||
|
||||
const
|
||||
KM_CORE_CONTEXT_ITEM_END: km_core_context_item = (
|
||||
|
|
@ -82,7 +84,7 @@ const
|
|||
keymancore = 'keymancore-1.dll';
|
||||
|
||||
procedure km_core_context_items_dispose(
|
||||
const context_items: km_core_context_item
|
||||
context_items: pkm_core_context_item
|
||||
); cdecl; external keymancore delayed;
|
||||
|
||||
function km_core_context_set(
|
||||
|
|
@ -90,10 +92,18 @@ function km_core_context_set(
|
|||
context_items: pkm_core_context_item
|
||||
): km_core_status; cdecl; external keymancore delayed;
|
||||
|
||||
function km_core_context_get(
|
||||
context: pkm_core_context;
|
||||
context_items: ppkm_core_context_item
|
||||
): km_core_status; cdecl; external keymancore delayed;
|
||||
|
||||
procedure km_core_context_clear(
|
||||
context: pkm_core_context
|
||||
); cdecl; external keymancore delayed;
|
||||
|
||||
function km_core_context_length(
|
||||
context: pkm_core_context
|
||||
): uint32; cdecl; external keymancore delayed;
|
||||
|
||||
type
|
||||
km_core_option_scope = (
|
||||
|
|
@ -162,6 +172,35 @@ type
|
|||
|
||||
pkm_core_action_item = ^km_core_action_item;
|
||||
|
||||
km_core_bool = uint32;
|
||||
|
||||
km_core_caps_state = (
|
||||
KM_CORE_CAPS_UNCHANGED = -1,
|
||||
KM_CORE_CAPS_OFF = 0,
|
||||
KM_CORE_CAPS_ON = 1
|
||||
);
|
||||
|
||||
km_core_actions = record
|
||||
code_points_to_delete: uint32; // number of codepoints (not codeunits!) to delete from app context.
|
||||
|
||||
// null-term string of characters to insert into document
|
||||
output: pkm_core_usv;
|
||||
|
||||
// list of options to persist, terminated with KM_CORE_OPTIONS_END
|
||||
persist_options: pkm_core_option_item;
|
||||
|
||||
// issue a beep, 0 = no, 1 = yes
|
||||
do_alert: km_core_bool;
|
||||
|
||||
// emit the (unmodified) input keystroke to the application, 0 = no, 1 = yes
|
||||
emit_keystroke: km_core_bool;
|
||||
|
||||
// -1=unchanged, 0=off, 1=on
|
||||
new_caps_lock_state: km_core_caps_state;
|
||||
|
||||
end;
|
||||
pkm_core_actions = ^km_core_actions;
|
||||
|
||||
// These types are used only for debugging convenience
|
||||
type
|
||||
km_core_action_item_array = array[0..100] of km_core_action_item;
|
||||
|
|
@ -241,6 +280,14 @@ function km_core_state_action_items(
|
|||
num_items: pinteger
|
||||
): pkm_core_action_item; cdecl; external keymancore delayed;
|
||||
|
||||
function km_core_state_get_actions(
|
||||
state: pkm_core_state
|
||||
): pkm_core_actions; cdecl; external keymancore delayed;
|
||||
|
||||
function km_core_actions_dispose(
|
||||
actions: pkm_core_actions
|
||||
): km_core_status; cdecl; external keymancore delayed;
|
||||
|
||||
function km_core_state_to_json(
|
||||
state: pkm_core_state;
|
||||
buf: PAnsiChar;
|
||||
|
|
@ -613,4 +660,24 @@ begin
|
|||
RaiseLastOSError;
|
||||
end;
|
||||
|
||||
// Verify size of km_core_actions - from x86 core c++ build, test_actions.cpp
|
||||
|
||||
procedure VerifyKmCoreActionsSize;
|
||||
var
|
||||
act: km_core_actions;
|
||||
begin
|
||||
{$IFDEF WIN64}
|
||||
{$ERROR Struct size not yet verified for 64-bit}
|
||||
{$ENDIF}
|
||||
assert(sizeof(km_core_actions) = 24);
|
||||
// &km_core_actions.code_points_to_delete: 0
|
||||
assert(Uint32(@act.output) - Uint32(@act) = 4);
|
||||
assert(Uint32(@act.persist_options) - Uint32(@act) = 8);
|
||||
assert(Uint32(@act.do_alert) - Uint32(@act) = 12);
|
||||
assert(Uint32(@act.emit_keystroke) - Uint32(@act) = 16);
|
||||
assert(Uint32(@act.new_caps_lock_state) - Uint32(@act) = 20);
|
||||
end;
|
||||
|
||||
initialization
|
||||
VerifyKmCoreActionsSize;
|
||||
end.
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ libkeymancore.so.1 libkeymancore #MINVER#
|
|||
(c++|optional)"typeinfo name for std::codecvt_utf8_utf16<char16_t, 1114111ul, (std::codecvt_mode)0>@Base" 17.0.244
|
||||
km_core_actions_dispose@Base 17.0.197
|
||||
km_core_context_clear@Base 17.0.195
|
||||
km_core_context_get@Base 17.0.195
|
||||
km_core_context_item_list_size@Base 17.0.195
|
||||
km_core_context_items_dispose@Base 17.0.195
|
||||
km_core_context_length@Base 17.0.195
|
||||
km_core_context_set@Base 17.0.195
|
||||
km_core_cp_dispose@Base 17.0.244
|
||||
km_core_event@Base 17.0.195
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue