Clicking keyboard 'Next' key using UIAutomation - iphone

I have a search field in my app and I have set the return key type of the keyboard for this field to UIReturnKeyNext. I am attempting to write a UIAutomation test that clicks the Next button on the keyboard using the following line:
UIATarget.localTarget().frontMostApp().mainWindow().keyboard().keys().firstWithName("next");
This call is failing because the key with name 'next' is not being found. I have done a dump of all of the elements in my app using:
UIATarget.localTarget().frontMostApp().logElementTree();
This reveals that there is indeed a key in the keyboard with name 'next', but somehow my attempt to retrieve it as show above still fails. I can however retrieve other keys (like the key for the letter 'u') using this method. Is there a known issue here or am I doing something wrong?
I've tried other variations with no luck:
UIATarget.localTarget().frontMostApp().mainWindow().keyboard().elements()["next"];
Here is a screen capture of the elements in my UIAKeyboard:

If you just want to click it, and you know the keyboard has "next" as "Return key" (defined in your nib), then you can use this:
app.keyboard().typeString("\n");

Jelle's approach worked for me. But I also found an alternative way if anybody needed it.
XCUIApplication().keyboards.buttons["return"].tap()
Where you can create XCUIApplication() as a singleton on each UI Test session. The thing about this approach is you can now distinguish between return and done and other variants and even check for their existence.
You can go extra and do something like following:
extension UIReturnKeyType {
public var title: String {
switch self {
case .next:
return "Next"
case .default:
return "return"
case .continue:
return "Continue"
case .done:
return "Done"
case .emergencyCall:
return "Emergency call"
case .go:
return "Go"
case .join:
return "Join"
case .route:
return "Route"
case .yahoo, .google, .search:
return "Search"
case .send:
return "Send"
}
}
}
extension XCUIElement {
func tap(button: UIReturnKeyType) {
XCUIApplication().keyboards.buttons[button.title].tap()
}
}
And you can use it like:
let usernameTextField = XCUIApplication().textFields["username"]
usernameTextField.typeText("username")
usernameTextField.tap(button: .next)

I dont't have an example to test, but as the "Next" button is an UIAButton, and not an UIAKey you could try :
UIATarget.localTarget().frontMostApp().mainWindow().keyboard().buttons()["next"];
If it doesn't work, you can also try
UIATarget.localTarget().frontMostApp().mainWindow().keyboard().buttons()[4];

The following works for me:
UIATarget.localTarget().frontMostApp().mainWindow().keyboard().buttons().firstWi‌​thPredicate("name contains[c] 'next'");

For me, keyboard does not fall under mainWindow() in the View Hierarchy. It is at the same level as mainWindow() when you logElementTree() from top level. So, what you want to do is:
UIATarget.localTarget().frontMostApp().keyboard().buttons()["next"];
This worked for me when I was trying to press the "Search" button on keyboard.

Related

MAUI Text Entry on Complete not Working - Possible Work around?

I'm trying to use text entry on maui to fire an event when completed. I have set the "Completed" event to a handler and it works correctly on windows. But on Android I have no joy, the event just isn't firing.
I realise there is a bug in Maui which is preventing this. But it looks like the problem was discovered in August? It's a fairly basic thing, well at least it appears to be on the face of things.
What is the best work around for this? The only thing I can think is by using the textchanged event instead of completed. This works correctly, but then i have to bodge it by doing this sort of thing:
if (entry1.Text.EndsWith("#"))
{
//Then string is complete, so need to fire correct event
System.Diagnostics.Debug.WriteLine("Complete String Detected");
}
This works and I can use it since I'm awaiting for input from a barcode scanner, so I can set the last terminating character to whatever I want. In this case I set it to a #. I can't figure out a way to detect the return key being pressed.
Thanks
Andrew
There is a similar issue on the github about the Entry.Completed and Entry.ReturnCommand not executed.
This comment shows the cause and the workaround about this problem.
detect the return key being pressed
In addition, I can't understand the problem. I have created a sample to test. The Entry.Completed event will call when I pressed the enter key. I don't kown the return key you mentioned is what. But you can use the IOnKeyListener for the android to detect any key being pressed.
Create a Listener class in the /Platform/Android:
public class MyKeyListener : Java.Lang.Object, IOnKeyListener
{
public bool OnKey(global::Android.Views.View v, [GeneratedEnum] Keycode keyCode, KeyEvent e)
{
var edittext = v as AppCompatEditText;
if (keyCode == Keycode.Enter && e.Action == KeyEventActions.Down )
//I used the Entry key as the example, you can use any other key you want to replace it.
{
edittext.ClearFocus();
edittext.SetBackgroundColor(Color.GreenYellow);
return true;
}
return false;
}
And in the page.xml:
<Entry Completed="Entry_Completed" x:Name="entry"/>
Set the listener to the entry by overriding the OnHandlerChanged() in the page.cs:
protected override void OnHandlerChanged()
      {
            base.OnHandlerChanged();
#if ANDROID
(entry.Handler.PlatformView as AndroidX.AppCompat.Widget.AppCompatEditText).SetOnKeyListener(new MauiAppTest.Platforms.Android.MyKeyListener());
#endif
}
You can also set the listener with the handler. Finally, you can try both the method above and the workaround in the issue on the github.

Trying to get user's latest mouse click in scalafx

I'm trying to get user's latest mouse click in order to display the right table. However, I can't find any way to implement this idea. How do i get user's latest mouse click by using mouseEvent function?
I tried using if else statements but it doesn't work when there is still value in the monstersTable1
def handleEditMonster(action : ActionEvent) = {
val selectedMonster1 = monstersTable1.selectionModel().selectedItem.value
val selectedMonster2 = monstersTable2.selectionModel().selectedItem.value
if (selectedMonster1 != null){
val okClicked = MainApp.showMonsterEditDialog(selectedMonster1)
if (okClicked) showMonstersDetails(Some(selectedMonster1))
} else if (selectedMonster2 != null) {
val okClicked = MainApp.showMonsterEditDialog(selectedMonster2)
if (okClicked) showMonstersDetails(Some(selectedMonster2))
} else {
// Nothing selected.
val alert = new Alert(Alert.AlertType.Warning){
initOwner(MainApp.stage)
title = "No Selection"
headerText = "No monsters Selected"
contentText = "Please select a monsters in the table."
}.showAndWait()
}
}
I want it to be able to access the second table even though selectedMonster1 is still != null
It's not entirely clear from your question what it is you're trying to do, so please bear with me... (For future reference, it's best if you can create a ''minimal, complete and verifiable example'' that illustrates your problem.)
I'm assuming that you have two scalafx.scene.control.TableView instances, referenced via monstersTable1 and monstersTable2. You want to allow the user to select either one of the monsters in the first table, or one of the monsters in the second table, but not to be able to select one monster from each table simultaneously.
I'm unclear when your handleEditMonster function is called, so I'm guessing that it's invoked when the user clicks, say, an Edit Monster button, as that button's clicked event handler.
Do I have that right?
Assuming the above is accurate, you should listen for changes in table selection, and clear the selection in the other table when a new selection is made. The currently selected item in each table is a property that we can add a listener to, so we can achieve this with the following code (in your scene's initialization):
// In the onChange handlers, the first argument references the observable property
// that has been changed (in this case, the property identifying the currently
// selected item in the table), the second is the property's new value and the third
// is its previous value. We can ignore the first and the third arguments in this
// case. If the newValue is non-null (that is, if the user has made a
// selection from this table), then clear the current selection in the other
// table.
monstersTable1.selectionModel.selectedItem.onChange {(_, newValue, _) =>
if(newValue ne null) monstersTable2.selectionModel.clearSelection()
}
monstersTable2.selectionModel.selectedItem.onChange {(_, newValue, _) =>
if(newValue ne null) monstersTable1.selectionModel.clearSelection()
}
This should do the trick for you, and your handleEditMonster function should now work. You might want to add an assertion to guard against both tables having a current selection, which would indicate a bug in the selection handler logic.

Delete command is not working for NSTextField

I have a textfield to which I need to listen to tab key, so that when ever the user press tab from that text field I can move the focus to next text field. I have implemented the below code to perform that operation.
func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
if (commandSelector == #selector(insertTab)) {
if control == firstTextField {
makeNextTextFieldAsFirstResponder()
}
}
return true
}
My problem is that as I have implemented this code, delete key is not doing what it suppose to do(removing last character from the text field's text). Am I missing something here?
I am new to Mac development so excuse me if this question has been asked already somewhere.
I found the solution to my own problem. It turns out to be a simple mistake. I am not sure about how exactly this method works and how the return value affect the nature of the text field as I am new to Mac development, but it seems that the default return value should be false. Any insights to this behaviour are welcome.

How to Implement accessibilityCustomActions for VoiceOver on Mac?

I have a button that responds to various mouse clicks (regular click, right click, control+click, option+click, command+click...) to show different popup menus. Since it would be annoying for VoiceOver users to use actual physical mouse, I would like to map those to different VoiceOver actions.
However, I'm not getting the results I expected. Could someone help me to understand better what I'm missing? Here is what I discovered so far.
If I subclass NSButton and override the following functions, they work fine. Except there's one odd thing. If I press vo+command+space to bring up the list of available actions, VoiceOver says Action 1 instead of Show Menu.
override func accessibilityPerformPress() -> Bool {
print("Pressed!")
return true
}
override func accessibilityPerformShowAlternateUI() -> Bool {
print("Show Alternate UI")
return true
}
override func accessibilityPerformShowMenu() -> Bool {
print("Show Menu")
return true
}
In the same NSButton subclass, if I also override accessibilityCustomActions function, "Do Something" never comes up in the list of available actions when I press vo+command+space.
override func accessibilityCustomActions() -> [NSAccessibilityCustomAction]? {
let custom = NSAccessibilityCustomAction(name: "Do Something", target: self, selector: #selector(doSomething))
return [custom]
}
#objc func doSomething() -> Bool {
print("Done something.")
return true
}
If I subclass NSView instead of NSButton, and override the same functions from #1, everything works fine. Unlike first case, even VoiceOver correctly says "Show Menu" for the action from accessibilityPerformShowMenu instead of "Action 1".
in the same NSView subclass, if I override accessibilityCustomActions along with accessibilityPerformPress, accessibilityPerformShowMenu, or accessibilityPerformShowAlternateUI, "Do Something" doesn't come up in the action list.
However, "Do Something" does come up in the action list if I just override accessibilityCustomActions by itself without accessibilityPerformPress, accessibilityPerformShowMenu, and accessibilityPerformShowAlternateUI.
I tried creating another action with the name "Press" that does the same thing when pressing vo+space, and including in the return value of accessibilityCustomActions. However, Vo+space did not trigger the action. Instead, I had to press vo+command+space, and then select "Press". I guess the action just has the name "Press", but it's not actually connected to vo+space. I'm not sure how I can actually make that particular custom action to respond to vo+space.
I would appreciate if someone could help me to implement accessibilityCustomActions as well as accessibilityPerformPress, accessibilityPerformShowMenu, and accessibilityPerformShowAlternateUI together into NSButton.
Thanks so much!
The problem is that you are overriding these AX methods on the NSButton, not the NSButtonCell. For nearly everything to do with accessibility in NSControls, you will want to deal with the NSCell in question. If you use the custom action code you've written above and stick it in a subclass of NSButtonCell used by your button, then it will work.

How to validate Text mesh pro input field text in unity

I have tried to use text mesh pro input field in my project but I have face one series issue with that. i.e If try to validate empty or null text in input field it fails. For example when user without typing any text in tmp input field and click done button I have set a validation like not allowed to save null empty values but when user click done button without typing any text, those validations are fails. Please suggest any idea to fix this issue. Thanks in advance.
Here is the code I have tried :
var text = TextMeshProText.text; // here "TextMeshProText" is 'TMP_Text'
if(!string.IsNullOrEmpty(text))
{
//do required functionality
}
else
{
// Show alert to the user.
}
I have set the validation like this but without giving any text click on done button it fails null or empty condition and enter in to if.
I found the problem. It fails because you use TMP_Text instead TMP_InputField.
Note that: Use the code for TMP_InputField; not for TMP_Text that is inside it as a child.
Change your code to this:
TMP_InputField TextMeshProText;
...
public void OnClick ()
{
var text = TextMeshProText.text; // here "TextMeshProText" is 'TMP_InputField'
if (!string.IsNullOrEmpty(text))
{
//do required functionality
}
else
{
// Show alert to the user.
}
}
I hope it helps you