Jump to content
Sign in to follow this  
johnnyzero

AutoPopKeyboard - exclude windows by class

Recommended Posts

johnnyzero

I came across this existing AutoIT code that works pretty well for what I need: automatically pop up the oncreen keyboard as needed for text input when using "desktop mode" programs on a Windows tablet.

Pretty clever: it detects when the cursor changes to an i-beam and assumes you've clicked on a text input field.

;#RequireAdmin
#include <WinAPI.au3>
#include <GUIConstants.au3>
#include <Constants.au3>
#Include <WinAPIEx.au3>
;#include <SendMessage.au3>
#include <TrayConstants.au3>

Opt("TrayOnEventMode", 1) ; Use event trapping for tray menu
Opt("TrayMenuMode", 3) ; Default tray menu items will not be shown.

$iTrayIBeam = TrayCreateItem("Toggle Cursor I-Beam")
TrayItemSetOnEvent(-1, "ToggleIBeam")

$iTrayDebug = TrayCreateItem("Debug Tooltips")
TrayItemSetOnEvent(-1, "DebugMode")

TrayCreateItem("") ; Create a separator line.

TrayCreateItem("Exit")
TrayItemSetOnEvent(-1, "OnTrayMenuExit")

TraySetState()
TraySetClick(16)

; Set left click
TraySetOnEvent($TRAY_EVENT_PRIMARYUP, "OnTrayIconClick")
TraySetIcon("Resources\Enabled.ico")


Global $title,$lastTitle,$cursorBlinking, $editDetected, $visible, $PID, $debugMode, $Address, $useIBeam
Global $triggerMethod, $lastTriggerMethod, $debugMsg, $lastDebugMsg

Global $enabled = True

Global $myError = ObjEvent("AutoIt.Error","ErrorTrapper")    ; Initialize COM error handler - used for the Excel hack

Global Const $TRIGGER_EXCEL = "XLMAIN"
Global const $TRIGGER_BROWSER = "BROWSER"
Global Const $TRIGGER_CURSORBLINKING = "CB"
Global Const $TRIGGER_IBEAM = "IBEAM"

While 1
    ;
    Sleep(100)


    If  RegRead('HKLM\SYSTEM\CurrentControlSet\Control\PriorityControl', 'ConvertibleSlateMode') = 0 And $enabled Then
        $title = WinGetTitle('[ACTIVE]','')
        $hwnd=WinGetHandle('[ACTIVE]','')
        $className = _WinAPI_GetClassName($hwnd)

        $cursorBlinking=False
        $editDetected=False

        ;Check if we're using a browser as these are sandboxed.... Also Excel doesn't seem to be coming through
        local $browser=""
        Switch $className
            Case "Chrome_WidgetWin_1"
                $browser="Chrome"
            Case "MozillaWindowClass"
                $browser="FireFox"
            Case "IEFrame"
                $browser="IE"
            Case "XLMain"
                ;Kludge...!!! Seems an error is thrown if in edit mode, so let's use that to our advantage! Could stop working at any time...
                local $excelObj = ObjGet('','Excel.Application')
                if @error  and $visible Then ;bit flaky so had to do this to prevent keyboard bouncing up and down
                    $editDetected =True
                Else

                    If IsObj($excelObj) Then
                        local $excelActiveCell = $excelObj.ActiveCell.Address
                        if @error then $editDetected = True
                        if DebugMode then ShowDebugMessage("Excel - " & $title & ": " & $excelActiveCell,True)
                        $triggerMethod = $TRIGGER_EXCEL
                    Elseif $debugMode Then
                        ShowDebugMessage("Could not get Excel object")
                    EndIf
                EndIf
        EndSwitch

        ;If we're not already in Edit Mode, check if we've got anything in the browser title to indicate edit mode
        if $browser<>"" and not $editDetected Then
            $className=$browser
            if StringInStr($title," [input]") then
                $editDetected=True
                $triggerMethod= $TRIGGER_BROWSER
            EndIf
        EndIf

        ;If we still haven't got anything, look for a 'blinking cursor'
        if not $editDetected Then
            $Info = _WinAPI_GetGUIThreadInfo(_WinAPI_GetWindowThreadProcessId($hwnd, $PID))
            If Not @error Then $editDetected = ($info[0] = 1)
            $cursorBlinking=$editDetected
            if $editDetected then $triggerMethod = $TRIGGER_CURSORBLINKING
        EndIf

        ;If all else fails, IBeam cursor...
        if not $editDetected and $useIBeam Then
            $cursor = MouseGetCursor()
            $editDetected = ($cursor =5) ; 5 is for an I-Beam cursor
        EndIf

        if $debugMode then
            $debugMsg="Variables - Keyboard: " & $visible & ", Trigger: " & $triggerMethod & ", Last Trigger: " & $lastTriggerMethod & ", EditDetected: " & $editDetected
            if $debugMsg <> $lastDebugMsg then ShowDebugMessage ($debugMsg)
            $lastDebugMsg=$debugMsg
        EndIf

        If $editDetected and (not $visible or $title <> $lastTitle) Then
            $keyboard = ShellExecute('"C:\Program Files\Common Files\microsoft shared\ink\TabTip.exe"') ;Can we replace this with a PostMessage???
            $visible = True

        ElseIf not $editDetected and $visible Then
            HideKeyboard()
            $visible = False
        EndIf
        $lastTitle = $title
        $lastTriggerMethod = $triggerMethod
    EndIf

WEnd


Func OnTrayMenuExit()
    Exit
EndFunc

;Toggle Enabled/Disabled mode
Func OnTrayIconClick()
    if $enabled Then
        TraySetIcon("Resources\Disabled.ico")
        $enabled=False
    Else
        TraySetIcon("Resources\Enabled.ico")
        $enabled=True
    EndIf
    ;ConsoleWrite("Single" & @CRLF)
EndFunc


Func ErrorTrapper()
    Local $err = $myError.number
    If $err = 0 Then $err = -1
    SetError($err)  ; to check for after this function returns
    if $debugMode then ShowDebugMessage ("[ErrorTrapper] Error Code: " & $err)
Endfunc

;Tray Menu - Show us what's happening...
Func DebugMode()
    $debugMode = not $debugMode
    SetTrayMenuCheck($iTrayDebug, $debugMode)
EndFunc

;Tray Menu -Toggle use of I-Beam as a fallback edit mode check method
Func ToggleIBeam()
    $useIBeam = not $useIBeam
    SetTrayMenuCheck($iTrayIBeam, $useIBeam)
EndFunc

Func SetTrayMenuCheck($controlID, $checked)
    Local $state
    If $checked then
        $state = $TRAY_CHECKED
    Else
        $state = $TRAY_UNCHECKED
    EndIf
    TrayItemSetState($controlID, $state)
EndFunc

Func HideKeyboard()
    Local Const $WM_MESSAGE = 0x112
    Local Const $WM_WPARAM  = 0xF060
    ;Local Const $AUTOIT_CLASS = "IPTip_Main_Window"
    Local $hClass = _WinAPI_FindWindow("IPTip_Main_Window","") ;WinGetHandle("[CLASS:IPTip_Main_Window]")
    if @error then
        If $debugMode Then ShowDebugMessage("[HideKeyboard] Error occured in getting keyboard handle");$hClass = GetKBHandle()
    Else
        If $debugMode Then ShowDebugMessage("[HideKeyboard] Handle " & $hClass)
    EndIf
    if not @error Then
        if $debugMode then ShowDebugMessage ("[HideKeyboard] Hidekeyboard called")
        Local $dll = DllOpen("User32.dll")
        Local $res=DllCall($dll, "bool", "PostMessage", "HWND", $hClass,"UINT",$WM_MESSAGE, "WPARAM",$WM_WPARAM,"LPARAM","0")
        if @error and $debugMode then ShowDebugMessage("[HideKeyboard] Error occured in PostMessage")
    Else
        if $debugMode then ToolTip("[HideKeyboard] error occured in getting handle")
    EndIf
EndFunc


Func ShowDebugMessage($msg, $toolTipOnly = False)
    ToolTip ($msg,MouseGetPos(0)+20, MouseGetPos(1)-50)
    if not $toolTipOnly then ConsoleWrite($msg & @CRLF)
EndFunc

For the most part, it works perfectly. However, if you click on a text field in a Metro app (or the Search field on the Start screen), the keyboard pops up as it should, but it gets stuck and then you can't get rid of it. Metro already has the ability to automatically popup/hide the onscreen keyboard as needed, and I assume my script is conflicting with that.

So I think I need to use WinActive or some other function to exclude the following window classes:

Windows.UI.Core.CoreWindow                (Metro apps)

ImmersiveLauncher                                 (the Start screen)

 

I'm not a programmer (just a bit of experience with AutoIT and Autohotkey), so any help or advice will be much appreciated.

Please note: by design, this script will only pop up the keyboard if it detects that you're in "tablet mode" by checking for a 0 dword value of the following registry key:

HKLMSYSTEMCurrentControlSetControlPriorityControlConvertibleSlateMode

So if you want to test the script on a non-tablet Windows 8 device, you'll need to temporarily set that value in your registry. Or, you could remove that part of the code.

Thanks!

Edited by johnnyzero
  • Like 1

Share this post


Link to post
Share on other sites
powerofos

<snip>

Hey guys,

I appreciate your code, but its not works right now, my tablet pc is lenovo miix520, system; win10 HOME edition, can you figure out what happens?

 

regards,

           ZQY

Edited by Melba23
Quote removed

Share this post


Link to post
Share on other sites
Melba23

powerofos,

When you reply, please use the "Reply to this topic" button at the top of the thread or the "Reply to this topic" editor at the bottom rather than the "Quote" button - it just pads the thread unnecessarily.

M23

 


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______Open Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×