Conversation
User Test ResultsTest specification and instructions
Test Artifacts |
mcdurdin
left a comment
There was a problem hiding this comment.
I don't think this is correct. The base keyboard dialog needs to run elevated -- because when you change the base keyboard, Keyman needs to mcompile each of the installed keyboards against the new base keyboard:
keyman/windows/src/engine/kmcomapi/com/options/keymanoptions.pas
Lines 133 to 135 in 1536a5f
The problem here is that the base layout setting is saved against the Admin user, but needs to be saved against the current user. This probably is best solved by splitting the admin component -- mcompiling -- out of the TKeymanOptions.Apply function, and running it as a separate step from the Base Keyboard dialog. Then the Base Keyboard dialog does not show elevated, but just elevates when OK is clicked, if it detects that new mcompiles need to be run, and does that as a kmshell -mcompile <basekeylayoutid> call? (implementation calls: TKeymanKeyboardInstalled.UpdateBaseLayout for each installed keyboard).
TKPRecompileMnemonicKeyboard then needs a parameter for the base layout, rather than reading it from the context options:
So some plumbing required, sadly.
This change may not have been the prefered change but it worked. It does run as an elevated but the process is created as a current user. |
|
Did you verify that this worked with a baselayout you had never selected previously? How could the mcompiled .kmx files be written to the C:\ProgramData folder if the base layout steps are run non-elevated? One reasonably straightforward way to address this, for starting as a non-elevated user:
Also:
|
Need to verify that the relevant files are saved in ProgramData too and that the base keyboard is mapped as expected! |
Test Prerequisites
Test Specs
Test Results
Note The Keyman Configuration window becomes unclickable until I click out of the app and click back. It does not show unresponding.
|
Note, if a crash dialog appears, FAIL the test. Also, please Copy to Clipboard and paste it into the test report. TEST_BASE_KEYBOARD_CURRENT_USER (FAIL): a crash dialog appeared |
2d6a4ee to
2c48025
Compare
|
@Meng-Heng |
|
I'll hold off reviewing until build passes 😀 |
Test Specs
Test Results
|
| kdl: IKeymanDefaultLanguage; | ||
| FIcon: string; | ||
| FMutex: TKeymanMutex; // I2720 | ||
| BaseKeyboardID: Integer; |
There was a problem hiding this comment.
I am not comfortable with a BaseKeyboard variable and a FBaseKeyboard parameter -- too easy to confuse them! Can we perhaps refactor the fmBaseKeyboard case into a ConfigureAndSetBaseKeyboard function?
mcdurdin
left a comment
There was a problem hiding this comment.
Just some minor tweaks and a question about whether we need to publish a new public API for this? (I don't think the work is wasted effort, because you gained a deeper knowledge of how kmcomapi interfaces are implemented, but I am sorry if we decide that it really can be an internal interface)
| (not FileExists(ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '.kmx') or | ||
| not FileExists(ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '-d.kmx')) then |
There was a problem hiding this comment.
Let's make a function to build these filenames?
There was a problem hiding this comment.
I not sure I follow what you mean, if you mean something like this? It doesn't add anything really for a function that is only called inside this loop.
function InsertBaseKeyboardIdFilename(const BaseFileName: string; BaseKeyboardIDHex: string; Deadkey: Boolean): string;
begin
if Deadkey then
Result := ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '-d.kmx'
else
Result := ChangeFileExt(BaseFileName, '') + '-' + BaseKeyboardIDHex + '.kmx';
end;
function BaseKeyboardNeedsMCompile(BaseKeyboardID: Integer): Boolean;
var
I: Integer;
Keyboard: IKeymanKeyboardInstalled;
KeyboardFileName, BaseKeyboardIDFilename, BaseKeyboardIDDeadkeyFilename: string;
BaseKeyboardIDHex: string;
begin
BaseKeyboardIDHex := IntToHex(BaseKeyboardID, 8);
for I := 0 to kmcom.Keyboards.Count - 1 do
begin
Keyboard := kmcom.Keyboards.Items[I];
KeyboardFileName := Keyboard.Filename;
BaseKeyboardIDFilename := InsertBaseKeyboardIdFilename(KeyboardFileName, BaseKeyboardIDHex, False);
BaseKeyboardIDDeadkeyFilename := InsertBaseKeyboardIdFilename(KeyboardFileName, BaseKeyboardIDHex, True);
if FileExists(KeyboardFileName) and
(not FileExists(BaseKeyboardIDFilename) or
not FileExists(BaseKeyboardIDDeadkeyFilename)) then
Exit(True);
end;
Result := False;
end;
There was a problem hiding this comment.
I see UpgradeMnemonicLayout.pas has similar references. It'd be nice to group them so that we have a single set of functions that do the string manipulation.
| var | ||
| BaseKeyboardID: Integer; | ||
| begin | ||
| WaitForElevatedConfiguration(Handle, '-basekeyboard'); | ||
| // Refresh will be triggered by elevated process | ||
| if ConfigureBaseKeyboard(BaseKeyboardID) then | ||
| begin | ||
| SetBaseKeyboard(Handle, BaseKeyboardID); | ||
| DoRefresh; | ||
| end; |
There was a problem hiding this comment.
This then can also use ConfigureAndSetBaseKeyboard (from earlier comment)
| procedure RefreshInstallation; | ||
|
|
||
| { IKeymanKeyboardInstalled2 } | ||
| procedure MCompileForBaseKeyboard(KLID: Integer); safecall; |
There was a problem hiding this comment.
I wonder if this could be slipped into IIntKeymanKeyboardInstalled and avoid publishing another interface?
There was a problem hiding this comment.
I tried but kmshell needs to be able to make the call, I think.
There was a problem hiding this comment.
Yes, you are right, kmshell is a separate module to kmcomapi, so it needs to be a published API, not an Int(ernal) one. My bad, I even called that out in an earlier review. Sorry for the misdirection.
Co-authored-by: Marc Durdin <marc@durdin.net>
Refactor ConfigureBaseKeyboard to ConfigureAndSetBaseKeyboard call the SetBaseKeyboard from the form rather then from the initprog module.
mcdurdin
left a comment
There was a problem hiding this comment.
LGTM, just asking for a move and rename of the new functions!
There was a problem hiding this comment.
I have made a number of suggestions to these functions. Can you move the whole lot to utilfiletypes.pas, rather than utilstr.pas?
There was a problem hiding this comment.
Can you move the whole lot to utilfiletypes.pas, rather than utilstr.pas?
six for one half-a-dozen for the other. It isn't really filetype identifier but I guess it is making a new filename of the same type. It is also really str manipulation function. I will move it.
Co-authored-by: Marc Durdin <marc@durdin.net>

Fixes: #15152
For all the iterartions this change went through you can read through the rest of this PR.
This PR now shows the BaseKeyboard form without elevation for the current user. On successful change it checks to see if there are already compiled keyboards for the selected basekeyboard. If there aren't compiled keyboards it then elevates to compile the keyboards but passes in the current user's basekeyboard ID. On successful return from the elevated process it sets the basekeyboard as selected by the user.
For installing keyboards it is also important that if the basekeyboard is different the admin user used for elevation that keyboards are compiled against the correct basekeyboard. This change is made in #16528
Build-bot: release:windows
User Testing
TEST_BASE_KEYBOARD_CURRENT_USER
Login into Windows with and account that is a "standard" user and does not have "Administrator" rights.
Install the Keyman from this PR
Open Keyman Configuration -> Keyboard Layouts
Install a keyboard for example sil_ipa
Open Keyman Configuration -> Options
Check
C:\ProgramData\Keyman\Keyman Engine\Keyboard\_Package\sil_ipadon't delete the basesil_ipa.kmxbut delete any with KLIDs for examplesil_ipa-00000409-d.kmxClick Base Keyboard, change the Base Keyboard to German. You will need to enter the login details for a Admin user.
Confirm the Keyboard changes for the current user and not the Admin user used for the elevated processs.
Check
C:\ProgramData\Keyman\Keyman Engine\Keyboard\_Package\sil_ipathere should now be asil_ipa-????0407-d.kmxandsil_ipa-????0407.kmxTEST_BASE_KEYBOARD_CURRENT_USER_KMX_EXISTS
After completing the steps in
TEST_BASE_KEYBOARD_CURRENT_USERCheck German mcomplied kmx is still there i.e.
C:\ProgramData\Keyman\Keyman Engine\Keyboard\_Package\sil_ipathere should now be asil_ipa-????0407-d.kmxandsil_ipa-????0407.kmx6.Click Base Keyboard, change the Base Keyboard to German. You should Not be asked to enter a admin user.