VB or C# interface

Is there any small example of invoking and using the Keyman keyboard with the API in either VB or C#?
If so, can someone post an example?
Thanks

Welcome to the Keyman community, @RustyE!

We’ve got a simple example of consuming the API in VBScript at https://help.keyman.com/developer/engine/desktop/10.0/api/IKeyman/

At present, we don’t have any examples of using the API from C# or VB .NET in our documentation. The API is available as a COM interface so you should be able to follow the standard method of importing a COM library into a .NET project.

When you put together a working solution, please do share here or suggest a documentation update!

Hi Marc,

Thanks for the prompt reply J

I have created a small .Net program that works pretty well, but I haven’t figured out the method by which I can change the keyboard language.

To create a .Net app, one needs to:
Register your .dll file after Keyman Desktop is installed (mine is Windows 10 x64)

  1. In a CMD window, navigate to the DLL location
    a. C:\Program Files (x86)\Common Files\Keyman\Keyman Engine>

  2. Then type: regsvr32 kmcomapi.dll
    a. Open Visual Studio (I tested VS2010 thru VS2019 and all worked the same)

  3. Open the References for the project
    a. Click Add Reference
    b. Select COM tab
    1. Find and select KEYMAN API LIBRARY (64 bit)
    Program Example (VB Windows Forms):

  4. Create 2 buttons
    a. btnShow
    b. btnHide
    c. btnSelectLanguage

  5. Create 1 Textbox
    a. Textbox1

  6. Create 1 Combobox
    b. cmbSourceLanguage

    *** Form Load ***
    Public Class frmMain
    Public Keyman As New clsKeyman
    Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim dt As DataTable = clslanguages.SelectALL()
    dim SOURCE_Language as integer
    For Each row As DataRow In dt.Rows
    With row
    Dim KeymanLang As String = Keyman.FindLanguage(.Item(“Name”))
    cmbSourceLanguage.Items.Add(ThisItem)
    If .Item(“Name”).ToString.ToLower = “english” Then
    SOURCE_Language = ThisItem
    End If
    End With
    Next
    cmbSourceLanguage.SelectedIndex = SOURCE_Language.Index
    End Sub

    Private Sub txtSourceSubject_GotFocus(sender As Object, e As EventArgs) Handles txtSourceSubject.GotFocus
    SetKeymanLanguage(cmbSourceLanguage.SelectedItem)
    SetKeymanLanguage(cmbSourceLanguage.SelectedItem)
    End Sub

    Private Sub txtSourceSubject_LostFocus(sender As Object, e As EventArgs) Handles txtSourceSubject.LostFocus
    Keyman.Hide()
    End Sub

    Private Sub SetKeymanLanguage(ByVal Language As ComboItem)
    If Language.Name = “English” Then
    Keyman.Hide()
    Else
    Keyman.SelectLanguage(Language.KeymanName)
    Keyman.Show()
    End If
    End Sub
    End Class

*** clsKeyman ***

‘’’


‘’’ Keyman Properties
‘’'AutoApply - Determines whether settings changes are applied To Keyman Engine automatically As they are made.
‘’'Control - Returns an IKeymanControl Interface that provides methods For controlling the Keyman process And user Interface.
‘’'Errors - Returns an IKeymanErrors Interface that lists errors that the API incurred When undertaking various processes.
‘’'Hotkeys - Returns an IKeymanHotkeys Interface that lists all Of the configured Interface hotkeys.
‘’'Keyboards - Returns an IKeymanKeyboardsInstalled Interface that lists all Of the currently installed Keyman keyboards.
‘’'Languages - Returns an IKeymanLanguages Interface that lists all Of the currently avilable Windows languages And input methods.
‘’'hotkeys - Returns an IKeymanhotkeys Interface that lists all Of the configuration settings And values For Keyman Engine.
‘’'Packages - Returns an IKeymanPackagesInstalled Interface that lists all Of the currently installed Keyman packages.
‘’‘SystemInfo - Returns an IKeymanSystemInfo Interface that describes the current system configuration.
‘’’

Public Class clsKeyman
Dim Keyman As New keymanapi.Keyman

''' <summary>
''' Show the on screen keyboard with current language
''' </summary>
Public Sub Show()
    Keyman.Control.StartVisualKeyboard()
End Sub

''' <summary>
''' Hide the on screen keyboard
''' </summary>
Public Sub Hide()
    Keyman.Control.StopVisualKeyboard()
End Sub

''' <summary>
''' Start Keyman (no keyboard will show until SHOW)
''' </summary>
Public Sub Start()
    Keyman.Control.StartKeyman()
End Sub

''' <summary>
''' Hide the visual keyboard and stop Keyman
''' </summary>
Public Sub [Stop]()
    Keyman.Control.StopVisualKeyboard()
    Keyman.Control.StopKeyman()
End Sub

''' <summary>
''' Find the Keyman installed keyboard language LAYOUTNAME
''' </summary>
''' <param name="Language">A language name like Spanish, French, Arabic, Greek, Chinese..etc.</param>
''' <returns></returns>
Public Function FindLanguage(ByVal Language As String) As String
    Dim lang As keymanapi.IKeymanLanguage
    For Each lang In Keyman.Languages
        If lang.LayoutName.Contains(Language) Then
            Return lang.LayoutName
        End If
    Next
    Return String.Empty
End Function

''' <summary>
''' Set the ACTIVELANGUAGE for the on screen keyboard
''' </summary>
''' <param name="Language">Keyman LAYOUTNAME</param>
Public Sub SelectLanguage(ByVal Language As String)
    Dim lang As keymanapi.IKeymanLanguage
    For Each lang In Keyman.Languages
        If Language = lang.LayoutName Then
            Keyman.Control.ActiveLanguage = lang
            Exit For
        End If
    Next
    Keyman.Refresh()
End Sub

End Class

1 Like

Good work :slight_smile:

Yes, ActiveLanguage is a nice convenient way of switching languages. You can have a bit more control if you use the Windows API ITfInputProcessorProfileMgr::ActivateProfile (and .NET has a wrapper for this as well) but you might not need the extra functionality in the Windows interface.

This shouldn’t be required? Did you find it to be necessary in order for the library to appear in references in Visual Studio?

Yes, the COM was visible, but when you tried to add it to References within Visual Studio, it would tell you it was not registered and could not load it.
I then did the Regsvr32 trick; reloaded the program (VS); and it loaded perfectly and all methods etc. were available immediately.

Is there a method for moving the keyboard on the screen?
i.e. if the keyboard covers a control (Textbox for example), it would be good to be able to set the screen location. (also, BTW, when using multiple screens it would be nice to be able to specify the screen as well) :slight_smile:

I’ll have to investigate the COM registration issue. It shouldn’t be necessary :frowning: – Keyman is supposed to register everything at install time.

To move the on screen keyboard, you can do something like (showing C/C++ version):

hwnd = FindWindow("TfrmVisualKeyboard", NULL);
if(hwnd != NULL) {
  MoveWindow(hwnd, x, y, w, h, TRUE);
}

Note that if you change aspect ratio of the window, it will adjust its bounds as it resizes. Also, if you close and reopen it, it make sure it is visible and will attempt to position itself entirely on a single monitor (helps when monitors are attached/removed or resolution changes etc).

Thanks Marc,
I’m finding the TfrmVisualKeyboard window (or at least it is finding an Hwnd for something with that name, but the Movewindow is not working at all.
The keyboard is visible when I run the test application; it does find a hwnd; when I issue the MoveWindow, it doesn’t move and MoveWindow returns a zero.
Ideas?

Oh, sorry. This happens because the Keyman window is at a higher privilege level than your app. So, no, you can’t move the window like that!

Currently, the API does not include any method to control the size and position of the window. There is one workaround:

  1. Close the OSK (Keyman.Control.StopVisualKeyboard())
  2. Update the following registry key HKEY_CURRENT_USER\Software\Keyman\Keyman Engine\On Screen Keyboard, value position (REG_SZ) to the coordinates of the window, e.g. 10,10,500,300. Be aware that these coordinates are not necessarily kept on-screen when the window aspect ratio is adjusted, so you may want to experiment.
  3. Re-open the OSK (Keyman.Control.StartVisualKeyboard())

Hi Marc,

I greatly appreciate your support J

In implementing the registry editing you proposed below, it seems that if the “ratio” of width/height/length are not correct, Keyman will place the errant element at zero.

(I am guessing at the reasoning on this…)

For example, if I set the registry values to “100,100,500,500”, it will move the keyboard, but one of the values will be zero and sometimes (depending upon supplied values) one will be negative and place part or all of the keyboard above the screen so that part is not visible.

Does the keyboard have a width/height/length “ratio” that must be maintained to successfully move the board to preferred locations?

thanks

Regards,

image001.jpg

Rusty

Tough question! It’s probably something we should add to the API; the current setting is really intended to be internal which is why you’re running into this problem.

The calculation for the ratio is complicated, because it takes into account the window border, toolbar and more… :frowning: I wish I had a simple answer. Might be worth opening a feature request (or pull request if you are really keen!) as I don’t know that I have any better solution at present. At the very least, Keyman should validate treat the value in the registry as needing adjustment…

The calculation in question is on GitHub