diff --git a/src/mp_app.c b/src/mp_app.c index 57f7df0..be7e588 100644 --- a/src/mp_app.c +++ b/src/mp_app.c @@ -129,23 +129,47 @@ bool mp_next_event(mp_event* event) // Input state updating //--------------------------------------------------------------- -static void mp_update_key_state(mp_key_state* key, bool down) +static void mp_update_key_state(mp_key_state* key, mp_key_action action) { u64 frameCounter = __mpApp.inputState.frameCounter; if(key->lastUpdate != frameCounter) { - key->transitionCounter = 0; - key->clicked = false; - key->doubleClicked = false; + key->transitionCount = 0; + key->repeatCount = 0; + key->sysClicked = false; + key->sysDoubleClicked = false; key->lastUpdate = frameCounter; } - if(key->down != down) + + switch(action) { - key->transitionCounter++; + case MP_KEY_PRESS: + { + if(!key->down) + { + key->transitionCount++; + } + key->down = true; + } break; + + case MP_KEY_REPEAT: + { + key->repeatCount++; + key->down = true; + } break; + + case MP_KEY_RELEASE: + { + if(key->down) + { + key->transitionCount++; + } + key->down = false; + } break; + + default: + break; } - - key->down = down; - } static void mp_update_mouse_move(f32 x, f32 y, f32 deltaX, f32 deltaY) @@ -204,107 +228,138 @@ static void mp_update_text(utf32 codepoint) // Input state polling //-------------------------------------------------------------------- -mp_key_state mp_input_get_key_state(mp_key_code key) +mp_key_state mp_key_get_state(mp_key_code key) { + mp_key_state state = {0}; if(key <= MP_KEY_COUNT) { - return(__mpApp.inputState.keyboard.keys[key]); - } - else - { - return((mp_key_state){0}); + state = __mpApp.inputState.keyboard.keys[key]; } + return(state); } -mp_key_state mp_input_get_mouse_button_state(mp_mouse_button button) + +mp_key_state mp_mouse_button_get_state(mp_mouse_button button) { + mp_key_state state = {0}; if(button <= MP_MOUSE_BUTTON_COUNT) { - return(__mpApp.inputState.mouse.buttons[button]); + state = __mpApp.inputState.mouse.buttons[button]; } - else + return(state); +} + +int mp_key_state_press_count(mp_key_state* key) +{ + int count = 0; + if(key->lastUpdate == __mpApp.inputState.frameCounter) { - return((mp_key_state){0}); + count = key->transitionCount / 2; + if(key->down) + { + //NOTE: add one if state is down transition count is odd + count += (key->transitionCount & 0x01); + } } + return(count); } -bool mp_input_check_key_transition(mp_key_state* key, bool pressed) +int mp_key_state_release_count(mp_key_state* key) { - bool res = ( (key->lastUpdate == __mpApp.inputState.frameCounter) - && key->transitionCounter - &&(key->down == pressed || key->transitionCounter > 1)); - return(res); + int count = 0; + if(key->lastUpdate == __mpApp.inputState.frameCounter) + { + count = key->transitionCount / 2; + if(!key->down) + { + //NOTE: add one if state is up and transition count is odd + count += (key->transitionCount & 0x01); + } + } + return(count); } -bool mp_input_key_down(mp_key_code key) +int mp_key_state_repeat_count(mp_key_state* key) { - mp_key_state state = mp_input_get_key_state(key); - return(state.down); -} -bool mp_input_key_pressed(mp_key_code key) -{ - mp_key_state state = mp_input_get_key_state(key); - bool res = mp_input_check_key_transition(&state, true); - return(res); + int count = 0; + if(key->lastUpdate == __mpApp.inputState.frameCounter) + { + count = key->repeatCount; + } + return(count); } -bool mp_input_key_released(mp_key_code key) +bool mp_key_down(mp_key_code key) { - mp_key_state state = mp_input_get_key_state(key); - bool res = mp_input_check_key_transition(&state, false); - return(res); -} - -bool mp_input_mouse_down(mp_mouse_button button) -{ - mp_key_state state = mp_input_get_mouse_button_state(button); + mp_key_state state = mp_key_get_state(key); return(state.down); } -bool mp_input_mouse_pressed(mp_mouse_button button) +int mp_key_pressed(mp_key_code key) { - mp_key_state state = mp_input_get_mouse_button_state(button); - bool res = mp_input_check_key_transition(&state, true); + mp_key_state state = mp_key_get_state(key); + int res = mp_key_state_press_count(&state); return(res); } -bool mp_input_mouse_released(mp_mouse_button button) +int mp_key_released(mp_key_code key) { - mp_key_state state = mp_input_get_mouse_button_state(button); - bool res = mp_input_check_key_transition(&state, false); + mp_key_state state = mp_key_get_state(key); + int res = mp_key_state_release_count(&state); return(res); } -bool mp_input_mouse_clicked(mp_mouse_button button) +int mp_key_repeated(mp_key_code key) { - mp_key_state state = mp_input_get_mouse_button_state(button); - bool clicked = state.clicked && (state.lastUpdate == __mpApp.inputState.frameCounter); + mp_key_state state = mp_key_get_state(key); + int res = mp_key_state_repeat_count(&state); + return(res); +} + +bool mp_mouse_down(mp_mouse_button button) +{ + mp_key_state state = mp_mouse_button_get_state(button); + return(state.down); +} + +int mp_mouse_pressed(mp_mouse_button button) +{ + mp_key_state state = mp_mouse_button_get_state(button); + int res = mp_key_state_press_count(&state); + return(res); +} + +int mp_mouse_released(mp_mouse_button button) +{ + mp_key_state state = mp_mouse_button_get_state(button); + int res = mp_key_state_release_count(&state); + return(res); +} + +bool mp_mouse_clicked(mp_mouse_button button) +{ + mp_key_state state = mp_mouse_button_get_state(button); + bool clicked = state.sysClicked && (state.lastUpdate == __mpApp.inputState.frameCounter); return(clicked); } -bool mp_input_mouse_double_clicked(mp_mouse_button button) +bool mp_mouse_double_clicked(mp_mouse_button button) { - mp_key_state state = mp_input_get_mouse_button_state(button); - if(state.lastUpdate == __mpApp.inputState.frameCounter) - { - return(state.doubleClicked); - } - else - { - return(false); - } + mp_key_state state = mp_mouse_button_get_state(button); + bool doubleClicked = state.sysClicked && (state.lastUpdate == __mpApp.inputState.frameCounter); + return(doubleClicked); } -mp_key_mods mp_input_key_mods() +mp_keymod_flags mp_key_mods() { return(__mpApp.inputState.keyboard.mods); } -vec2 mp_input_mouse_position() +vec2 mp_mouse_position() { return(__mpApp.inputState.mouse.pos); } -vec2 mp_input_mouse_delta() +vec2 mp_mouse_delta() { if(__mpApp.inputState.mouse.lastUpdate == __mpApp.inputState.frameCounter) { @@ -316,7 +371,7 @@ vec2 mp_input_mouse_delta() } } -vec2 mp_input_mouse_wheel() +vec2 mp_mouse_wheel() { if(__mpApp.inputState.mouse.lastUpdate == __mpApp.inputState.frameCounter) { diff --git a/src/mp_app.h b/src/mp_app.h index b907548..427fe6b 100644 --- a/src/mp_app.h +++ b/src/mp_app.h @@ -193,7 +193,7 @@ typedef enum { MP_KEYMOD_ALT = 0x01, MP_KEYMOD_SHIFT = 0x02, MP_KEYMOD_CTRL = 0x04, - MP_KEYMOD_CMD = 0x08 } mp_key_mods; + MP_KEYMOD_CMD = 0x08 } mp_keymod_flags; typedef enum { MP_MOUSE_LEFT = 0x00, @@ -207,7 +207,7 @@ typedef struct mp_key_event // keyboard and mouse buttons input { mp_key_action action; i32 code; - mp_key_mods mods; + mp_keymod_flags mods; char label[8]; u8 labelLen; int clickCount; @@ -226,7 +226,7 @@ typedef struct mp_move_event // mouse move/scroll f32 y; f32 deltaX; f32 deltaY; - mp_key_mods mods; + mp_keymod_flags mods; } mp_move_event; typedef struct mp_frame_event // window resize / move @@ -322,27 +322,27 @@ MP_API mp_rect mp_window_frame_rect_for_content_rect(mp_rect contentRect, mp_win //-------------------------------------------------------------------- // Input state polling //-------------------------------------------------------------------- -MP_API bool mp_input_key_down(mp_key_code key); -MP_API bool mp_input_key_pressed(mp_key_code key); -MP_API bool mp_input_key_released(mp_key_code key); -MP_API mp_key_mods mp_input_key_mods(void); -MP_API str8 mp_key_to_label(mp_key_code key); -MP_API mp_key_code mp_label_to_key(str8 label); +MP_API bool mp_key_down(mp_key_code key); +MP_API int mp_key_pressed(mp_key_code key); +MP_API int mp_key_released(mp_key_code key); +MP_API int mp_key_repeated(mp_key_code key); -MP_API bool mp_input_mouse_down(mp_mouse_button button); -MP_API bool mp_input_mouse_pressed(mp_mouse_button button); -MP_API bool mp_input_mouse_released(mp_mouse_button button); -MP_API bool mp_input_mouse_clicked(mp_mouse_button button); -MP_API bool mp_input_mouse_double_clicked(mp_mouse_button button); +MP_API bool mp_mouse_down(mp_mouse_button button); +MP_API int mp_mouse_pressed(mp_mouse_button button); +MP_API int mp_mouse_released(mp_mouse_button button); +MP_API bool mp_mouse_clicked(mp_mouse_button button); +MP_API bool mp_mouse_double_clicked(mp_mouse_button button); -MP_API vec2 mp_input_mouse_position(void); -MP_API vec2 mp_input_mouse_delta(void); -MP_API vec2 mp_input_mouse_wheel(void); +MP_API vec2 mp_mouse_position(void); +MP_API vec2 mp_mouse_delta(void); +MP_API vec2 mp_mouse_wheel(void); MP_API str32 mp_input_text_utf32(mem_arena* arena); MP_API str8 mp_input_text_utf8(mem_arena* arena); +MP_API mp_keymod_flags mp_key_mods(); + //-------------------------------------------------------------------- // Clipboard //-------------------------------------------------------------------- diff --git a/src/mp_app_internal.h b/src/mp_app_internal.h index 8489e70..cc570b8 100644 --- a/src/mp_app_internal.h +++ b/src/mp_app_internal.h @@ -35,17 +35,18 @@ typedef struct mp_key_utf8 typedef struct mp_key_state { u64 lastUpdate; - u32 transitionCounter; + u32 transitionCount; + u32 repeatCount; bool down; - bool clicked; - bool doubleClicked; + bool sysClicked; + bool sysDoubleClicked; } mp_key_state; typedef struct mp_keyboard_state { mp_key_state keys[MP_KEY_COUNT]; - mp_key_mods mods; + mp_keymod_flags mods; } mp_keyboard_state; typedef struct mp_mouse_state diff --git a/src/osx_app.m b/src/osx_app.m index e19d2bf..1d387e2 100644 --- a/src/osx_app.m +++ b/src/osx_app.m @@ -236,9 +236,9 @@ static int mp_convert_osx_key(unsigned short nsCode) } } -static mp_key_mods mp_convert_osx_mods(NSUInteger nsFlags) +static mp_keymod_flags mp_convert_osx_mods(NSUInteger nsFlags) { - mp_key_mods mods = MP_KEYMOD_NONE; + mp_keymod_flags mods = MP_KEYMOD_NONE; if(nsFlags & NSEventModifierFlagShift) { mods |= MP_KEYMOD_SHIFT; @@ -369,7 +369,7 @@ void mp_install_keyboard_layout_listener() object:nil]; } -static void mp_update_key_mods(mp_key_mods mods) +static void mp_update_key_mods(mp_keymod_flags mods) { __mpApp.inputState.keyboard.mods = mods; } @@ -384,6 +384,15 @@ static void mp_update_key_mods(mp_key_mods mods) @implementation MPApplication -(void)noOpThread:(id)object {} + +//This is necessary in order to receive keyUp events when we have a key combination with Cmd. +- (void)sendEvent:(NSEvent *)event { + if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSEventModifierFlagCommand)) + [[self keyWindow] sendEvent:event]; + else + [super sendEvent:event]; +} + @end @interface MPAppDelegate : NSObject @@ -791,101 +800,61 @@ static void mp_update_key_mods(mp_key_mods mods) } } -- (void)mouseDown:(NSEvent *)nsEvent +static void mp_process_mouse_button(NSEvent* nsEvent, mp_window_data* window, mp_mouse_button button, mp_key_action action) { mp_event event = {}; event.window = mp_window_handle_from_ptr(window); event.type = MP_EVENT_MOUSE_BUTTON; - event.key.action = MP_KEY_PRESS; - event.key.code = MP_MOUSE_LEFT; + event.key.action = action; + event.key.code = button; event.key.mods = mp_convert_osx_mods([nsEvent modifierFlags]); event.key.clickCount = [nsEvent clickCount]; - mp_update_key_state(&__mpApp.inputState.mouse.buttons[event.key.code], true); - if(event.key.clickCount >= 1) + mp_key_state* keyState = &__mpApp.inputState.mouse.buttons[event.key.code]; + mp_update_key_state(keyState, action); + if(action == MP_KEY_PRESS) { - __mpApp.inputState.mouse.buttons[event.key.code].clicked = true; + if(event.key.clickCount >= 1) + { + keyState->sysClicked = true; + } + if(event.key.clickCount >= 2) + { + keyState->sysDoubleClicked = true; + } } - if(event.key.clickCount >= 2) - { - - __mpApp.inputState.mouse.buttons[event.key.code].doubleClicked = true; - } - mp_queue_event(&event); +} +- (void)mouseDown:(NSEvent *)nsEvent +{ + mp_process_mouse_button(nsEvent, window, MP_MOUSE_LEFT, MP_KEY_PRESS); [window->osx.nsWindow makeFirstResponder:self]; } - (void)mouseUp:(NSEvent*)nsEvent { - mp_event event = {}; - event.window = mp_window_handle_from_ptr(window); - event.type = MP_EVENT_MOUSE_BUTTON; - event.key.action = MP_KEY_RELEASE; - event.key.code = MP_MOUSE_LEFT; - event.key.mods = mp_convert_osx_mods([nsEvent modifierFlags]); - event.key.clickCount = [nsEvent clickCount]; - - mp_update_key_state(&__mpApp.inputState.mouse.buttons[event.key.code], false); - - mp_queue_event(&event); + mp_process_mouse_button(nsEvent, window, MP_MOUSE_LEFT, MP_KEY_RELEASE); } - (void)rightMouseDown:(NSEvent*)nsEvent { - mp_event event = {}; - event.window = mp_window_handle_from_ptr(window); - event.type = MP_EVENT_MOUSE_BUTTON; - event.key.action = MP_KEY_PRESS; - event.key.code = MP_MOUSE_RIGHT; - event.key.mods = mp_convert_osx_mods([nsEvent modifierFlags]); - - mp_update_key_state(&__mpApp.inputState.mouse.buttons[event.key.code], true); - - mp_queue_event(&event); + mp_process_mouse_button(nsEvent, window, MP_MOUSE_RIGHT, MP_KEY_PRESS); } - (void)rightMouseUp:(NSEvent*)nsEvent { - mp_event event = {}; - event.window = mp_window_handle_from_ptr(window); - event.type = MP_EVENT_MOUSE_BUTTON; - event.key.action = MP_KEY_RELEASE; - event.key.code = MP_MOUSE_RIGHT; - event.key.mods = mp_convert_osx_mods([nsEvent modifierFlags]); - - mp_update_key_state(&__mpApp.inputState.mouse.buttons[event.key.code], false); - - mp_queue_event(&event); + mp_process_mouse_button(nsEvent, window, MP_MOUSE_RIGHT, MP_KEY_RELEASE); } - (void)otherMouseDown:(NSEvent*)nsEvent { - mp_event event = {}; - event.window = mp_window_handle_from_ptr(window); - event.type = MP_EVENT_MOUSE_BUTTON; - event.key.action = MP_KEY_PRESS; - event.key.code = [nsEvent buttonNumber]; - event.key.mods = mp_convert_osx_mods([nsEvent modifierFlags]); - - mp_update_key_state(&__mpApp.inputState.mouse.buttons[event.key.code], true); - - mp_queue_event(&event); + mp_process_mouse_button(nsEvent, window, [nsEvent buttonNumber], MP_KEY_PRESS); } - (void)otherMouseUp:(NSEvent*)nsEvent { - mp_event event = {}; - event.window = mp_window_handle_from_ptr(window); - event.type = MP_EVENT_MOUSE_BUTTON; - event.key.action = MP_KEY_RELEASE; - event.key.code = [nsEvent buttonNumber]; - event.key.mods = mp_convert_osx_mods([nsEvent modifierFlags]); - - mp_update_key_state(&__mpApp.inputState.mouse.buttons[event.key.code], false); - - mp_queue_event(&event); + mp_process_mouse_button(nsEvent, window, [nsEvent buttonNumber], MP_KEY_RELEASE); } - (void)mouseDragged:(NSEvent*)nsEvent @@ -946,10 +915,10 @@ static void mp_update_key_mods(mp_key_mods mods) mp_queue_event(&event); } - - - (void)keyDown:(NSEvent*)nsEvent { + mp_key_action action = [nsEvent isARepeat] ? MP_KEY_REPEAT : MP_KEY_PRESS; + mp_event event = {}; event.window = mp_window_handle_from_ptr(window); event.type = MP_EVENT_KEYBOARD_KEY; @@ -961,7 +930,7 @@ static void mp_update_key_mods(mp_key_mods mods) event.key.labelLen = label.len; memcpy(event.key.label, label.ptr, label.len); - mp_update_key_state(&__mpApp.inputState.keyboard.keys[event.key.code], true); + mp_update_key_state(&__mpApp.inputState.keyboard.keys[event.key.code], MP_KEY_PRESS); mp_queue_event(&event); @@ -977,7 +946,7 @@ static void mp_update_key_mods(mp_key_mods mods) event.key.code = mp_convert_osx_key([nsEvent keyCode]); event.key.mods = mp_convert_osx_mods([nsEvent modifierFlags]); - mp_update_key_state(&__mpApp.inputState.keyboard.keys[event.key.code], false); + mp_update_key_state(&__mpApp.inputState.keyboard.keys[event.key.code], MP_KEY_RELEASE); mp_queue_event(&event); } @@ -1092,7 +1061,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; { NSString* characters; NSEvent* nsEvent = [NSApp currentEvent]; - mp_key_mods mods = mp_convert_osx_mods([nsEvent modifierFlags]); + mp_keymod_flags mods = mp_convert_osx_mods([nsEvent modifierFlags]); if([string isKindOfClass:[NSAttributedString class]]) { @@ -2265,7 +2234,6 @@ int mp_alert_popup(const char* title, [alert setAlertStyle:NSAlertStyleWarning]; int result = count - ([alert runModal]-NSAlertFirstButtonReturn) - 1; - printf("result = %i, NSAlertFirstButtonReturn = %li\n", result, (long)NSAlertFirstButtonReturn); [keyWindow makeKeyWindow]; return(result); } diff --git a/src/ui.c b/src/ui.c index 41d9251..4b37da6 100644 --- a/src/ui.c +++ b/src/ui.c @@ -450,7 +450,7 @@ vec2 ui_mouse_position(void) { ui_context* ui = ui_get_context(); - vec2 mousePos = mp_input_mouse_position(); + vec2 mousePos = mp_mouse_position(); mousePos.y = ui->height - mousePos.y; return(mousePos); } @@ -458,7 +458,7 @@ vec2 ui_mouse_position(void) vec2 ui_mouse_delta(void) { ui_context* ui = ui_get_context(); - vec2 delta = mp_input_mouse_delta(); + vec2 delta = mp_mouse_delta(); delta.y *= -1.; return(delta); } @@ -466,7 +466,7 @@ vec2 ui_mouse_delta(void) vec2 ui_mouse_wheel(void) { ui_context* ui = ui_get_context(); - vec2 delta = mp_input_mouse_wheel(); + vec2 delta = mp_mouse_wheel(); delta.y *= -1.; return(delta); } @@ -642,30 +642,25 @@ ui_sig ui_box_sig(ui_box* box) { if(sig.hovering) { - if(mp_input_mouse_clicked(MP_MOUSE_LEFT)) - { - printf("clicked while hovering!\n"); - } - sig.pressed = mp_input_mouse_pressed(MP_MOUSE_LEFT); + sig.pressed = mp_mouse_pressed(MP_MOUSE_LEFT); if(sig.pressed) { box->dragging = true; } - - sig.clicked = mp_input_mouse_clicked(MP_MOUSE_LEFT); - sig.doubleClicked = mp_input_mouse_double_clicked(MP_MOUSE_LEFT); + sig.doubleClicked = mp_mouse_double_clicked(MP_MOUSE_LEFT); + sig.rightPressed = mp_mouse_pressed(MP_MOUSE_RIGHT); } - sig.released = mp_input_mouse_released(MP_MOUSE_LEFT); + sig.released = mp_mouse_released(MP_MOUSE_LEFT); if(sig.released) { if(box->dragging && sig.hovering) { - sig.triggered = true; + sig.clicked = true; } } - if(!mp_input_mouse_down(MP_MOUSE_LEFT)) + if(!mp_mouse_down(MP_MOUSE_LEFT)) { box->dragging = false; } @@ -1589,7 +1584,7 @@ void ui_menu_bar_begin(const char* name) ui_push_size(UI_AXIS_Y, UI_SIZE_TEXT, 0, 0); ui_sig sig = ui_box_sig(bar); - if(!sig.hovering && mp_input_mouse_released(MP_MOUSE_LEFT)) + if(!sig.hovering && mp_mouse_released(MP_MOUSE_LEFT)) { ui_box_deactivate(bar); } @@ -1725,11 +1720,8 @@ void ui_edit_copy_selection_to_clipboard(ui_context* ui, str32 codepoints) u32 start = minimum(ui->editCursor, ui->editMark); u32 end = maximum(ui->editCursor, ui->editMark); str32 selection = str32_slice(codepoints, start, end); - str8 string = utf8_push_from_codepoints(&ui->frameArena, selection); - printf("copying '%.*s' to clipboard\n", (int)string.len, string.ptr); - mp_clipboard_clear(); mp_clipboard_set_string(string); } @@ -1737,9 +1729,6 @@ void ui_edit_copy_selection_to_clipboard(ui_context* ui, str32 codepoints) str32 ui_edit_replace_selection_with_clipboard(ui_context* ui, str32 codepoints) { str8 string = mp_clipboard_get_string(&ui->frameArena); - - printf("pasting '%.*s' from clipboard\n", (int)string.len, string.ptr); - str32 input = utf8_push_to_codepoints(&ui->frameArena, string); str32 result = ui_edit_replace_selection_with_codepoints(ui, codepoints, input); return(result); @@ -1764,7 +1753,7 @@ typedef enum { typedef struct ui_edit_command { mp_key_code key; - mp_key_mods mods; + mp_keymod_flags mods; ui_edit_op operation; ui_edit_move move; @@ -2186,18 +2175,13 @@ ui_text_box_result ui_text_box(const char* name, mem_arena* arena, str8 text) } //NOTE handle shortcuts - mp_key_mods mods = mp_input_key_mods(); + mp_keymod_flags mods = mp_key_mods(); for(int i=0; ikey) && mods == command->mods) + if(mp_key_pressed(command->key) && mods == command->mods) { codepoints = ui_edit_perform_operation(ui, command->operation, command->move, command->direction, codepoints); break; @@ -2205,7 +2189,7 @@ ui_text_box_result ui_text_box(const char* name, mem_arena* arena, str8 text) } //NOTE(martin): text box focus shortcuts - if(mp_input_key_pressed(MP_KEY_ENTER)) + if(mp_key_pressed(MP_KEY_ENTER)) { //TODO(martin): extract in gui_edit_complete() (and use below) ui_box_deactivate(frame); diff --git a/src/ui.h b/src/ui.h index ab12bf2..9a45bd4 100644 --- a/src/ui.h +++ b/src/ui.h @@ -123,10 +123,10 @@ typedef struct ui_sig bool pressed; bool released; - bool triggered; bool clicked; bool doubleClicked; - bool rightClicked; + bool rightPressed; + bool dragging; bool hovering;