Detecting NSKeyUp of the Shift key - macos

I am using this to detect keystrokes on my app...
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown
handler:^NSEvent * (NSEvent * theEvent)
OK I can use theEvent to know what characters were typed and know if a shift was pressed using this:
NSString *typedKey = theEvent.charactersIgnoringModifiers;
BOOL shiftDetected = [theEvent modifierFlags] & NSShiftKeyMask;
My App has an interface displayed with some buttons and I am allowing the keyboard to be used instead of clicking on the buttons. This interface has 3 buttons in particular that has a second function.
For example: the first button has 2 functions, A and B but just the A label is displayed on that button. Lets say I specify that the letter Q is the keyboard shortcut for that button. If the user presses Q function A is executed. If the user presses Shift Q then function B is executed.
But this is the problem. I need to detect all presses or releases of the Shift, because the moment the user presses Shift I have to change the label of that button from A to B, so the user knows that now that button will lead to the execution of function B instead of A. Like a keyboard that will change from lowercase to uppercase while Shift is being hold and change back to lowercase the moment Shift is released.
How do I do that?

I created a simple project using addLocalMonitorForEvents function. Please check my code, it is Swift code but I think it should be as same as objective c.
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
NSEvent.addLocalMonitorForEvents(matching: [.flagsChanged, .keyDown]) { (theEvent) -> NSEvent? in
if theEvent.modifierFlags.contains(.shift) {
if theEvent.keyCode == 56 { // this is Shif key
print("Shift START!")
}
else {
print("Shift pressed with keycode \(theEvent.keyCode)")
}
}
else {
if theEvent.keyCode == 56 { // this is Shif key
print("Shift END!")
}
else {
print("Normal keycode \(theEvent.keyCode)")
}
}
return theEvent
}
}
This is Objective c:
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskFlagsChanged|NSEventMaskKeyDown handler:^NSEvent * (NSEvent * theEvent) {
if ([theEvent modifierFlags] & NSEventModifierFlagShift) {
if (theEvent.keyCode == 56) { // this is Shif key
NSLog(#"Shift START");
}
else {
NSLog(#"Shift pressed with keycode %d", theEvent.keyCode);
}
}
else {
if (theEvent.keyCode == 56) { // this is Shif key
NSLog(#"Shift END");
}
else {
NSLog(#"Normal keycode %d", theEvent.keyCode);
}
}
return theEvent;
}];
Just copy and paste this part to your AppDelegate for quick testing.

Related

How to solve, Keyboard hide automatically when we work with multiple view?

We have two search textbox that will dynamically showing. One for portrait view and second for landscape view. We handled input text using flag in ViewDidLayoutSubviews() method. We have written a keyboard hide notification method as KeyboardWillHide(NSNotification notification) for text value handling.
We are getting these issue. Please have a look
1. When we start typing ViewDidLayoutSubviews() method every time call on key press and reload textbox. So my keyboard unable to up. We have fixe this with checking a flag if keyboard will then return.
2. Now we are getting same issue that keyboard hide automatic when we press on mic for speak to write. KeyboardWillHide(NSNotification notification) method every time call and hide keyboard. Its also call when we touch on tableview. 
How to solve these issue ,Please help
private void KeyboardWillHide(NSNotification notification)
{
string orientation = this.InterfaceOrientation.ToString();
if ((orientation.ToString() == "Portrait" || orientation.ToString() == "PortraitUpsideDown") && KeyboardHideSameView == false )
{
SearchText= txtSearchKeywordLS.Text;
txtSearchKeyword.Text = txtSearchKeywordLS.Text;
}
else if ((orientation.ToString() == "LandscapeRight" || orientation.ToString() == "LandscapeLeft") && KeyboardHideSameView == false )
{
SearchText = txtSearchKeyword.Text;
txtSearchKeywordLS.Text = txtSearchKeyword.Text;
}
txtSearchKeyword.ResignFirstResponder();
txtSearchKeywordLS.ResignFirstResponder();
isKeyboardApear = false;
KeyboardHideSameView = false;
}
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
if (isKeyboardApear == true) return;
applyViewGradient();
var orientation = this.InterfaceOrientation;
if (orientation.ToString() == "Portrait" || orientation.ToString() == "PortraitUpsideDown")
{
PortraitConst(this.View.Bounds.Height, this.View.Bounds.Width);
this.vwLandscapeHead.Hidden = true;
this.vwPortraitHead.Hidden = false;
this.txtSearchKeyword.Text = SearchText;
txtSearchKeyword.ResignFirstResponder();
txtSearchKeywordLS.ResignFirstResponder();
}
else if (orientation.ToString() == "LandscapeRight" || orientation.ToString() == "LandscapeLeft")
{
//Console.WriteLine("Landscape Mode");
// this.addSubview(landscapeView, containerView);
LandscapeConst(UIScreen.MainScreen.Bounds.Height, UIScreen.MainScreen.Bounds.Width);
applyViewGradient();
this.vwPortraitHead.Hidden = true;
this.vwLandscapeHead.Hidden = false;
this.txtSearchKeywordLS.Text = SearchText;
txtSearchKeyword.ResignFirstResponder();
txtSearchKeywordLS.ResignFirstResponder();
}
// this.containerView.NeedsUpdateConstraints();
}
We have solved it logically by using flags.
We have declare a boolean flag isKeyboardAppear=false when view appear first. When keyboard appear we set this flag to true And we noticed ViewDidLayoutSubviews() method are calling on every key press, so we write this code
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
if (isKeyboardAppear == true)
{
return;
}
}
When we hide keyboard manually we reset flag isKeyboardAppear=false .

Handle two key event in as 2 ctrl + left click

I want to catch both the single left click and the ctrl + left click in as2.
I am using FlashDevelop and coded this (it works):
_mc._back.onRelease = function() :Void
{
var args:Array = new Array();
args.push((_root._xmouse - this._parent._posMiniMapX) * this._parent._ratio);
args.push((_root._ymouse - this._parent._posMiniMapY) * this._parent._ratio + this._parent._bpa / this._parent._ratio);
fscommand("MoveCameraMiniMap", args);
}
How can I handle the both event?
Thank you.
the approach that I've usually taken is to listen to keyboard events on the CTRL key then evaluate that onRelease to determine the correct action.
But you could simply check the key.isDown status within the onRelease
_mc._back.onRelease = function() :Void {
if(Key.isDown(17)) {
// do CTRL + mouse action
} else {
// do standard action
}
}

JavaFX: Right click on Mac (Control + Click) not being detected. Any fixes?

I have a list view with items that I am allowing to be double clicked and right clicked (to delete the item). Why does control clicking not work on a mac? Thanks in advance.
Edit: My code is
listview.setOnMouseClicked(new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent event)
{
if (event.getButton().equals(MouseButton.PRIMARY))
{
if (event.getClickCount() == 2)
{
System.out.println("Double clicked");
System.out.println("clicked on " + listview.getSelectionModel().getSelectedItem());
}
}
if(event.getButton().equals(MouseButton.SECONDARY))
{
System.out.println("Right click");
}
}
});
My trackpad is set up as secondary button with two finger tap.
For anyone else looking this up. It is correct that two finger clicking will register as a MouseButton.SECONDARY event, but I think you should also check for Ctrl + MouseButton.PRIMARY since holding the control key is a common method for emulating a right click. So the if statement should be :
if ( event.getButton() == MouseButton.SECONDARY || e.isControlDown() ) {
// DO RIGHT CLICK ACTION
}

NSDatePicker action method not firing

Scenario:
The user is entering a date in an NSDatePicker in its textual form with no stepper (on OS X), and when they hit return on the keyboard, I'd like a message to be sent to the controller.
In an NSTextField, I would just hook the action up in Interface Builder, or set it from code, and when the user hits enter, the action message is sent to the target.
The date picker allows to set an action message and a target, but I can't get the action to fire. When I hit enter in the date picker, the action message does not get called.
Am I doing something wrong, or is there a workaround that I have to use? I would not be adverse to subclassing any of the classes involved, if that is what it takes.
An NSDatePicker will not handle or forward key events triggered by the Return or Enter key.
The solution is to subclass NSDatePicker to get the desired behavior in keyDown:
#import "datePickerClass.h"
#implementation datePickerClass
- (void)keyDown:(NSEvent *)theEvent{
unsigned short n = [theEvent keyCode];
if (n == 36 || n == 76) {
NSLog(#"Return key or Enter key");
// do your action
//
} else {
[super keyDown:theEvent];// normal behavior
}
}
#end
That's it.
Edit : also you can use NSCarriageReturnCharacter and NSEnterCharacter
NSString* const s = [theEvent charactersIgnoringModifiers];
unichar const key = [s characterAtIndex:0];
if (key == NSCarriageReturnCharacter || key == NSEnterCharacter) {

Inputs in SDL (on key pressed)

I would like to know how can I detect the press of a key or release of a key in a while loop in SDL. Now, I know you can get the events with SDL like OnKeyPressed, OnKeyReleased, OnKeyHit, etc, but I want to know how to build functions like 'KeyPressed' that returns a boolean, instead of being an event. Example:
while not KeyHit( KEY_ESC )
{
//Code here
}
I know you have already selected an answer.. but here is some actual code of how I typically do it with one array. :)
first define this somewhere.
bool KEYS[322]; // 322 is the number of SDLK_DOWN events
for(int i = 0; i < 322; i++) { // init them all to false
KEYS[i] = false;
}
SDL_EnableKeyRepeat(0,0); // you can configure this how you want, but it makes it nice for when you want to register a key continuously being held down
Then later, create a keyboard() function which will register keyboard input
void keyboard() {
// message processing loop
SDL_Event event;
while (SDL_PollEvent(&event)) {
// check for messages
switch (event.type) {
// exit if the window is closed
case SDL_QUIT:
game_state = 0; // set game state to done,(do what you want here)
break;
// check for keypresses
case SDL_KEYDOWN:
KEYS[event.key.keysym.sym] = true;
break;
case SDL_KEYUP:
KEYS[event.key.keysym.sym] = false;
break;
default:
break;
}
} // end of message processing
}
Then when you actually want to use the keyboard input i.e. a handleInput() function, it may look something like this:
void handleInput() {
if(KEYS[SDLK_LEFT]) { // move left
if(player->x - player->speed >= 0) {
player->x -= player->speed;
}
}
if(KEYS[SDLK_RIGHT]) { // move right
if(player->x + player->speed <= screen->w) {
player->x += player->speed;
}
}
if(KEYS[SDLK_UP]) { // move up
if(player->y - player->speed >= 0) {
player->y -= player->speed;
}
}
if(KEYS[SDLK_DOWN]) { // move down
if(player->y + player->speed <= screen->h) {
player->y += player->speed;
}
}
if(KEYS[SDLK_s]) { // shoot
if(SDL_GetTicks() - player->lastShot > player->shotDelay) {
shootbeam(player->beam);
}
}
if(KEYS[SDLK_q]) {
if(player->beam == PLAYER_BEAM_CHARGE) {
player->beam = PLAYER_BEAM_NORMAL;
} else {
player->beam = PLAYER_BEAM_CHARGE;
}
}
if(KEYS[SDLK_r]) {
reset();
}
if(KEYS[SDLK_ESCAPE]) {
gamestate = 0;
}
}
And of course you can easily do what you're wanting to do
while(KEYS[SDLK_s]) {
// do something
keyboard(); // don't forget to redetect which keys are being pressed!
}
**Updated version on my website: **
For the sake of not posting a lot of source code, you can view a complete SDL Keyboard class in C++ that supports
Single Key Input
Simultaneous Key Combos (Keys all pressed in any order)
Sequential Key Combonations (Keys all pressed in specific order)
http://kennycason.com/posts/2009-09-20-sdl-simple-space-shooter-game-demo-part-i.html (if you have any problems, let me know)
There is an SDL function for this: SDL_GetKeyboardState
Example to check whether left or right CTRL key is pressed:
const Uint8* state = SDL_GetKeyboardState(nullptr);
if (state[SDL_SCANCODE_LCTRL] || state[SDL_SCANCODE_RCTRL]) {
std::cerr << "ctrl pressed" << std::endl;
}
I had this problem in LuaJIT with FFI, this is how I solved it:
Global:
KEYS = {}
Event code:
ev = ffi.new("SDL_Event[1]")
function event()
while sdl.SDL_PollEvent(ev) ~= 0 do
local e = ev[0]
local etype = e.type
if etype == sdl.SDL_QUIT then
return false -- quit
-- os.exit() -- prevents interactive mode
elseif etype == sdl.SDL_KEYDOWN then
if e.key.keysym.sym == sdl.SDLK_ESCAPE then
return false -- quit
-- os.exit()
end
print("Pressed: ", e.key.keysym.scancode, "\n")
KEYS[tonumber(e.key.keysym.sym)] = true
-- print("Pressed: ", (e.key.keysym.sym == sdl.SDLK_w), "\n");
elseif etype == sdl.SDL_KEYUP then
KEYS[tonumber(e.key.keysym.sym)] = false
elseif etype == sdl.SDL_VIDEORESIZE then
-- print("video resize W:".. e.resize.w .. " H:" .. e.resize.h)
width = e.resize.w
height = e.resize.h
onResize()
end
end
return true -- everything ok
end
Update function:
if KEYS[sdl.SDLK_w] == true then
rot = rot + 1
end
Most time i wasted on this:
KEYS[tonumber(e.key.keysym.sym)] = false
Because FFI is returning a CData object, which was used as the array-key, but it needs the integer.
You should have 2 tables of booleans for keys. One table, in which you set keys true or false based on the SDL keydown/keyup events, and another one, that you initialize with false. When checking keyPressed, you just compare the second table key with the first table key, and if different, if second table key is false, then it was pressed, else it was released. After that, you do secondTable[key] := not secondTable[key]. Works!

Resources