I would like to allow the user to zoom only while the control key is held (depressed). I have implemented this as follows within a WindowKeyPressFcn callback function:
function keypress_callback(obj, evd, hZoom)
switch evd.Key
case 'control'
set(hZoom,'Enable','on');
end
%disp(evd); % used for debugging purposes
This function accepts a zoom object handle (hZoom) that is passed from the main program at the moment the callback function is activated (set(hFigure,'WindowKeyPressFcn',{#keypress_callback,hZoom});). I have written a similar WindowKeyReleaseFcn (set via set(hFigure,'WindowKeyReleaseFcn',{#keyrelease_callback,hZoom});) to disable zooming when control is released.
function keyrelease_callback(obj, evd, hZoom)
switch evd.Key
case 'control'
set(hZoom,'Enable','off');
end
%disp(evd); % used for debugging purposes
The goal is to allow normal zooming behavior (click to zoom in by a factor; shift-click to zoom out by a factor; drag clicking to zoom in on a selected region) only while the Ctrl key is depressed. As soon as this modifier key is released, zooming ability should be disabled.
However, this behavior does not work as intended. Simply testing (by disp(evd)) whether a key is pressed reveals that any number of key presses can be made with arbitrary keys; however, if the pressed key is Ctrl, only one such press can be made, and all subsequent presses of Ctrl are ignored, while all subsequent presses of any other key cause the key to appear in the Matab command window instead of triggering the keypress_callback function. Thus, pressing Ctrl appears to somehow inactivate the keypress_callback function, perhaps because focus is shifted from the figure to the zoom object? As a corollary question, the WindowKeyReleaseFcn seems to work fine for non-modifier keys (the evd shows the correct released key), but the key in evd is empty if the released key is a non-modifier key.
I would be grateful if someone could demonstrate the correct implementation of the control-dependent zoom behavior as envisaged.
The more modern way to do things seems to be:
gca
zoom on
z = zoom(gcf);
set(z, 'ButtonDownFilter', #ZoomGate)
where ZoomGate.m contains something like:
function inhibitZoom = ZoomGate(varargin)
if ismember('control', get(gcbo,'currentModifier'))
inhibitZoom = 0;
else
inhibitZoom = 1;
end
EDIT in response to questioner's comments:
My first suggestion was to use a WindowButtonDownFcn callback which then calls zoom itself if it detects the control modifier. This is fine provided you have control over the zoom implementation. Looking back at my code (I did something like this anything up to 15 years ago) I find that it used to be simple — zoom was an m-file and had an obvious way of calling it: zoom down meant "the button has just been pressed". Then, in that way that they do, MathWorks moved the goal posts and changed zoom. It looks like my response at the time was to re-implement my own zoom in the older, simpler style. Doesn't help you, unless you actually want that code (let me know).
Related
Example: A NPC greet you, and you have multiple choises that are questions for the NPC and if you want to know one answer of this questions, you click one button (1,2,3,4). Then the text change and give you the answer of the question.
I'm going to assume you have already set up your GUI and NPC Script.
Getting when a key is pressed is pretty simple in Unity: Use UnityEngine.Input
Example of use:
if(Input.GetKeyDown(KeyCode.Alpha1)) {
//do something
}
This is a basic example.
Input.GetKeyDown returns true only when the key is pressed at that specific moment of checking (the frame). KeyCode.Alpha1 is the key for '1' at the top of alphanumeric keyboards.
To get when the key is held down, for jumping or running, use Input.GetKey instead. This will be true if the key is held down at that instance, instead of only one at the beginning.
To get when the key is released, use 'Input.GetKeyUp'. This only runs once the key is let go.
For setting the color of a Textbox, use yourTextBox.color. I believe it works with both legacy Textboxes and TextMeshPro.
The way to do what you have is this:
In the Update call, check if an NPC is talking with the player.
If so, then check if the player has pressed 1 ,2, 3, or 4, using Input.GetKeyDown. (To make it nicer looking, have each option in a list and use the index of the result. KeyCode is an enum, so you can save it like any other variable.)
Call some function that returns the response to the answer. Return a string or something.
Override the text in the Textbox with the answer, and use yourTextBox.color to set the color as you wish.
This should cover it. I may have some typos or errors, but the basic principals should work. Also, make sure you implement it in a way that makes it easier to edit later. You don't want to write code that can't be added on later, trust me...
So I want 2 different things to happen for when SHIFT+Q is pressed and when merely 'q' is pressed.
Currently when I press SHIFT+Q both actions are being fired, and I don't want that. Is there a way to do this elegantly in the action mapping? I would prefer not to have to hardcode keys in my scripts, but if that's the only way then I will just check in script if shift is currently engaged. It will be a giant headache in the future though if I want to allow players to edit key mappings.
For anyone coming across this in the future - It looks like this feature is being implemented in InputSystem 1.4.0+
(ChangeLog: https://github.com/Unity-Technologies/InputSystem/blob/develop/Packages/com.unity.inputsystem/CHANGELOG.md)
From the changelog:
Added support for keyboard shortcuts and mutually exclusive use of modifiers.
In short, this means that a "Shift+B" binding can now prevent a "B" binding from triggering.
Just need to pick one of the new 'OneModifierComposite' or 'TwoModifierComposite'.
Edit: please scroll to the bottom of this post. It turns out there’s actually a way to do this natively
I’m not totally sure, but one thing that I know will for sure work is to have separate actions mapped to shift and to q. Then in your OnShift function, simply set a “shiftIsPressed” flag to true or false, depending on whether the context is starting or ending. Then your your OnQ function can look something like this:
void OnQ(CallbackContext ctx)
{
if(!ctx.actionStarted) return;
if(shiftPressed) ShiftQ();
else Q();
}
This will keep key remapping open to you. It’s not perfect, if the player remaps Q to, say R, it will also remap ShiftQ to ShiftR. Without knowing more about your application though, that sounds like a good thing.
Edit:
To get Shift+Q to register as a separate action from Q, all you need to do is click the plus button on your ShiftQ action and select “Button With One Modifier Composite”. Then set Shift as the modifier and Q as the button. If you want to rebind Shift+Q to, say R, then set the button to R and the modifier to “Any Button”.
Hope this helps!
I have several shapes in LO Calc and I need those shapes to change their sizes when they are mouse clicked: the first click enlarges the shape, the second click restores the original size.
I'm trying to do this with a macro assigned to those shapes. My problem and my question: how to determine within a macro which shape has been clicked?
I know how to get the current selected shape:
dim doc as object
doc = ThisComponent
someVar = doc.CurrentSelection...
But a shape when clicked is not getting selected and this method is not working.
I tried to add a parameter for the event object to the macro:
sub ChangeSize( oEvent )
But this produces a message about wrong number of parameters.
Is there a way to detect the caller of a macro in LO Basic? Or maybe another way to implement size changing with a mouse click?
P.S. One can use a separate button for calling the macro and click this button after selecting the needed shape, but this way is less convenient.
EDIT: As I guessed below in the comments, the described task can be solved via the mouse and shape coordinates. The key points for the solution I found here:
How to get Document-Coordinates from a Mouse Click in an OpenOffice BASIC Macro
Instead of detecting the caller, assign a different one-line macro for each shape clicked event.
Sub ShapeClickedA
ChangeSize("ShapeA")
End Sub
Sub ShapeClickedB
ChangeSize("ShapeB")
End Sub
Related: LibreOffice macro showing simple TextBox shape
P.S. After answering, I realized you asked the linked question as well. How is this different, and is the other answer not satisfactory?
I implemented various uimenus in my uitable but there appears a very annoying behaviour.
function createUItable
h = figure
...
uimenu(h,'Label','MenuButton','Callback',#someAction)
end
%---------
function someAction(~,~)
%some action
end
But after executing the callback function, the menu button remains pressed and highlighted and not even that, when I slide over the next menu button, this one is triggered also!
This behaviour was also described at Matlab Central, but without solution.
I tried the suggested:
function someAction(~,~)
%some action
set(gcbo,'Enable','off')
drawnow
set(gcbo,'Enable','on')
end
which does not change anything. set(gcbo,'Enable','off') alone would solve the sliding problem, but also disables the whole button, what I don't want.
I also tried to use the 'Checked','Visible' and 'Interuptible' property without success.
This problem must be known, any hints?
I also thought about using uicontrol instead of uimenu and use a pushbutton, but I don't get it work.
Edit: when I put my menubutton into a submenu it works perfect:
button = uimenu(h,'Label','MenuButton');
uimenu(button,'Label','MenuButton','Callback',#someAction)
Edit2:
A pushbutton works also, but how could I place it into the menubar?
I guess MATLAB implementation is this way, because setting a callback at the top-level menu is very odd.
Naturally in GUI's (not only MATLAB), when you click the top-level menu (like "File", "Edit", etc.) the standard behaviour is, that a submenu pops open rather than an immediate action being executed.
So you should only use the top-level callback to e.g. dynamically create/modify the associated submenus.
I think there are two alternatives to go:
1) If you'd like to stick to that manner (one, always-visible button-like element), then you should rather use the toolbar via a uipushtool:
hToolbar = uitoolbar(parentFigure);
uipushtool(hToolbar, 'ClickedCallback', #someAction);
This does not have the 'Label' property though, so you'll have to work with 'CData' and may be a 'TooltipString'.
2) Create a top-level menu that contains your actual action-menu:
topMenu = uimenu(parent, 'Label', 'Actions');
uimenu(topMenu, 'Label', 'MenuButton', 'callback', #someAction)
From the general point of view on GUI design, both alternatives have the benefit of being the more commonly used style, thus being more intuitive to any user.
I found an interesting work-around for this problem while keeping the callback in the TOP menu. Turns out that using the uistack function released focus from the menu item so in the top-level menu callback, I placed
uistack(hObj,'down');
uistack(hObj,'up');
drawnow;
Which does nothing to the actual ordering but releases the menu items' focus.
I need to know whether the user is holding down the ctrl key while clicking a button. Since it's a button and not a figure I cannot use 'selectionType' on the figure etc.
How about this:
modifiers = get(gcf,'currentModifier'); %(Use an actual figure number if known)
ctrlIsPressed = ismember('control',modifiers);
The figure class has a number of useful Current* properties which are useful when handling callbacks. This is how to retrieve current mouse position, selected graphics object, and (as here) pressed keys. These include: CurrentAxes, CurrentCharacter, CurrentKey, CurrentModifier, CurrentObject, and CurrentPosition.
Pressing the escape key reinitializes CurrentModifier. My solution so far has been to instruct my users (right in the GUI) to press the escape key to revert to default behavior.
Overall, Matlab's CurrentModifier behavior seems to be that the modifier key "sticks" until one of the following occurs: a different modifier is pressed, a different window is selected, or the escape key is pressed.