Ejemplo n.º 1
0
static bool MCConvertNativeFromUTF16(const uint16_t *p_chars, uint32_t p_char_count, uint8_t*& r_output, uint32_t& r_output_length)
{
	uint8_t *t_output;
	uint32_t t_output_length;
	if (!MCMemoryAllocate(p_char_count, t_output))
		return false;

	uint32_t t_index;
	t_index = 0;
	t_output_length = 0;
	while(t_index < p_char_count)
	{
		if (p_chars[t_index] < 128 && (t_index == p_char_count - 1 || p_chars[t_index + 1] < 128))
		{
			t_output[t_output_length++] = (char)p_chars[t_index];
			t_index += 1;
		}
		else
		{
			uint32_t t_start;
			t_start = t_index;
			
			uint32_t t_codepoint;
			t_codepoint = MCUnicodeCodepointAdvance((const uint2 *)p_chars, p_char_count, t_index);
			
			while(t_index < p_char_count)
			{
				uint4 t_old_index;
				t_old_index = t_index;
				
				t_codepoint = MCUnicodeCodepointAdvance((const uint2 *)p_chars, p_char_count, t_index);
				
				if (MCUnicodeCodepointIsBase(t_codepoint))
				{
					t_index = t_old_index;
					break;
				}
			}

			uint8_t t_char;
			if (!MCUnicodeMapToNative(p_chars + t_start, t_index - t_start, t_char))
				t_char = '?';
			
			t_output[t_output_length++] = t_char;
		}
	}

	MCMemoryReallocate(t_output, t_output_length, t_output);

	r_output = t_output;
	r_output_length = t_output_length;

	return true;
}
Ejemplo n.º 2
0
static bool MCConvertNativeFromISO8859_1(const uint8_t *p_input, uint32_t p_input_length, uint8_t*& r_output, uint32_t& r_output_length)
{
	uint8_t *t_output;
	if (!MCMemoryAllocate(p_input_length, t_output))
		return false;

	for(uint32_t i = 0; i < p_input_length; i++)
	{
		uint2 t_input_char;
		t_input_char = MCUnicodeMapFromNative_MacRoman(p_input[i]);
		if (!MCUnicodeMapToNative(&t_input_char, 1, t_output[i]))
			t_output[i] = '?';
	}

	r_output = t_output;
	r_output_length = p_input_length;

	return true;
}
Ejemplo n.º 3
0
// MW-2014-06-25: [[ Bug 12370 ]] Map an input keyCode and mapped codepoint to
//   engine keysym and char. The engine expects keyCode to be the mapped key
//   if an ascii character and the raw keycode if not.
static void map_key_to_engine(MCPlatformKeyCode p_key_code, codepoint_t p_mapped_codepoint, codepoint_t p_unmapped_codepoint, MCPlatformKeyCode& r_key_code, MCStringRef &r_native_char)
{
    if (p_mapped_codepoint <= 0xffff)
	{
        uint16_t t_unicode_char;
        char_t t_native_char;

        // MW-2014-08-05: [[ Bug 13042 ]] This was a mis-merge from an updated fix to bug 12747
        //   (the code previously was using unmapped codepoint).
        t_unicode_char = p_mapped_codepoint & 0xffff;
		
		if (MCUnicodeMapToNative(&t_unicode_char, 1, t_native_char))
		{
            /* UNCHECKED */ MCStringCreateWithNativeChars(&t_native_char, 1, r_native_char);
            
            // MW-2014-06-25: [[ Bug 12370 ]] The engine expects keyCode to be the mapped key whenever
            //   the mapped key is ASCII. If the mapped key is not ASCII then the keyCode reflects
            //   the raw (US English) keycode.
            // SN-2014-12-08: [[ Bug 14067 ]] Avoid to use the native char instead of the key code
            // the numeric keypad keys.
            if (isascii(t_native_char) && (p_key_code < kMCPlatformKeyCodeKeypadSpace || p_key_code > kMCPlatformKeyCodeKeypadEqual))
                r_key_code = t_native_char;
            else
                r_key_code = p_key_code;
            
            return;
        }
        // SN-2014-12-05: [[ Bug 14162 ]] We can have unicode chars being typed.
        // We keep the given keycode (the codepoint) as the key code in these conditions.
        else
        {
            /* UNCHECKED */ MCStringCreateWithChars(&t_unicode_char, 1, r_native_char);
            r_key_code = p_key_code;
            
            return;
        }
    }
    
    r_native_char = MCValueRetain(kMCEmptyString);
    r_key_code = p_key_code;
}
Ejemplo n.º 4
0
static void MCEventQueueDispatchEvent(MCEvent *p_event)
{
	MCEvent *t_event;
	t_event = p_event;

	MCObject *t_menu;
	t_menu = MCdispatcher -> getmenu();

	switch(t_event -> type)
	{
	case kMCEventTypeNotify:
		t_event -> notify . callback(t_event -> notify . state, true);
		break;

	case kMCEventTypeWindowReshape:
		// IM-2014-02-14: [[ HiDPI ]] update view backing scale
		t_event -> window . stack -> view_setbackingscale(t_event->window.scale);
		t_event -> window . stack -> view_configure(true);
		break;
			
	case kMCEventTypeMouseFocus:
		if (t_event -> mouse . focus . inside)
		{
			if (MCmousestackptr != t_event -> mouse . stack)
			{
			MCmousestackptr = t_event -> mouse . stack;
				MCmousestackptr -> enter();
			}

			if (t_menu == nil)
				MCmousestackptr -> mfocus(MCmousex, MCmousey);
			else
				t_menu -> mfocus(MCmousex, MCmousey);
		}
		else if (MCmousestackptr == t_event -> mouse . stack)
		{
			MCmousestackptr -> munfocus();
			MCmousestackptr = nil;
		}
		break;

	case kMCEventTypeMousePress:
		if (MCmousestackptr == t_event -> mouse . stack || t_menu != nil)
		{
			if (t_event -> mouse . press . state == kMCMousePressStateDown)
				MCbuttonstate |= (1 << t_event -> mouse . press . button);
			else
				MCbuttonstate &= ~(1 << t_event -> mouse . press . button);

			if (t_event -> mouse . press . state == kMCMousePressStateDown)
			{
				if (t_event -> mouse . time - s_click_time < MCdoubletime &&
					MCU_abs(MCclicklocx - MCmousex) < MCdoubledelta &&
					MCU_abs(MCclicklocy - MCmousey) < MCdoubledelta)
					s_click_count += 1;
				else
					s_click_count = 0;
			}
			else
				s_click_time = t_event -> mouse . time;

			MCeventtime = t_event -> mouse . time;
			MCmodifierstate = t_event -> mouse . press . modifiers;
			MCclicklocx = MCmousex;
			MCclicklocy = MCmousey;
			MCclickstackptr = MCmousestackptr;

			MCObject *t_target;
			t_target = t_menu != nil ? t_menu : MCclickstackptr;

			if (t_event -> mouse . press . state == kMCMousePressStateDown)
			{
				tripleclick = s_click_count == 2;

				if (s_click_count != 1)
					t_target -> mdown(t_event -> mouse . press . button + 1);
				else
					t_target -> doubledown(t_event -> mouse . press . button + 1);
			}
			else if (t_event -> mouse . press . state == kMCMousePressStateUp)
			{
				if (s_click_count != 1)
					t_target -> mup(t_event -> mouse . press . button + 1);
				else
					t_target -> doubleup(t_event -> mouse . press . button + 1);
			}
			else
			{
				s_click_count = 0;
				tripleclick = False;
			
				// If the press was 'released' i.e. cancelled then we stop messages, mup then
				// dispatch a mouseRelease message ourselves.
                
                // FG-2013-10-09 [[ Bugfix 11208 ]]
                // CS_NO_MESSAGES only applies to the target and not the controls it contains
                // so the mouse up message (on mouseUp) sets sent when it isn't desired
                // Hopefully nobody depends on the old behaviour...
            
                //t_target -> setstate(True, CS_NO_MESSAGES);
				//t_target -> mup(t_event -> mouse . press . button + 1);
				//t_target -> setstate(False, CS_NO_MESSAGES);
                
                bool old_lock = MClockmessages;
                MClockmessages = true;
                t_target -> mup(t_event -> mouse . press . button + 1);
                MClockmessages = old_lock;
				
				t_target -> message_with_args(MCM_mouse_release, t_event -> mouse . press . button + 1);
			}
		}
		break;

	case kMCEventTypeMouseWheel:
		// Notice that we recompute mfocused twice - this is because calling the key handler
		// could invalidate mfocused in between.
		if (MCmousestackptr == t_event -> mouse . stack)
		{
			MCObject *mfocused;
			
			mfocused = MCmousestackptr->getcard()->getmfocused();
			if (mfocused == NULL)
				mfocused = MCmousestackptr -> getcard();
			if (mfocused == NULL)
				mfocused = MCmousestackptr;
			
			MCeventtime = t_event -> mouse . time;
			MCmodifierstate = t_event -> mouse . wheel . modifiers;
			if (t_event -> mouse . wheel . dv != 0)
				mfocused -> kdown("", t_event -> mouse . wheel . dv < 0 ? XK_WheelUp : XK_WheelDown);
			
			mfocused = MCmousestackptr->getcard()->getmfocused();
			if (mfocused == NULL)
				mfocused = MCmousestackptr -> getcard();
			if (mfocused == NULL)
				mfocused = MCmousestackptr;
			
			if (t_event -> mouse . wheel . dh != 0)
				mfocused -> kdown("", t_event -> mouse . wheel . dh < 0 ? XK_WheelLeft : XK_WheelRight);
		}
		break;

	case kMCEventTypeMousePosition:
		if (MCmousestackptr == t_event -> mouse . stack || t_menu != nil)
		{
			MCeventtime = t_event -> mouse . time;
			MCmodifierstate = t_event -> mouse . position . modifiers;

			MCObject *t_target;
			t_target = t_menu != nil ? t_menu : MCmousestackptr;
			
			// IM-2013-09-30: [[ FullscreenMode ]] Translate mouse location to stack coords
			MCPoint t_mouseloc;
			t_mouseloc = MCPointMake(t_event->mouse.position.x, t_event->mouse.position.y);
			
			// IM-2013-10-03: [[ FullscreenMode ]] Transform mouseloc based on the mousestack
			t_mouseloc = MCmousestackptr->view_viewtostackloc(t_mouseloc);
			
			MCmousex = t_mouseloc.x;
			MCmousey = t_mouseloc.y;

			t_target -> mfocus(t_mouseloc . x, t_mouseloc . y);
		}
		break;

	case kMCEventTypeKeyFocus:
		if (t_event -> key . focus . owner)
			t_event -> key . stack -> kfocus();
		else
			t_event -> key . stack -> kunfocus();
		break;

	case kMCEventTypeKeyPress:
		{
			MCObject *t_target;
			t_target = t_menu != nil ? t_menu : t_event -> key . stack;

			MCmodifierstate = t_event -> key . press . modifiers;

			// If 'char_code' is 0, then this key press has not generated a
			// character.
			if (t_event -> key . press . char_code == 0)
			{
				t_target -> kdown(MCnullstring, t_event -> key . press . key_code);
				t_target -> kup(MCnullstring, t_event -> key . press . key_code);
				break;
			}

			// Otherwise 'char_code' is the unicode codepoint, so first map to
			// UTF-16 (not done properly yet...)
			uint2 t_unichar;
			t_unichar = (uint2)t_event -> key . press . char_code;

			// If we successfully map to native, then we can dispatch as a normal kdown
			uint1 t_char;
			if (MCUnicodeMapToNative(&t_unichar, 1, t_char))
			{
				char t_buffer[2];
				t_buffer[0] = t_char;
				t_buffer[1] = '\0';
				t_target -> kdown(t_buffer, t_event -> key . press . key_code);
				t_target -> kup(t_buffer, t_event -> key . press . key_code);
				break;
			}

			// Otherwise we dispatch in a unicode way...
			if (!t_target -> kdown(MCnullstring, t_event -> key . press . key_code))
				if (MCactivefield != nil)
				{
					MCString t_unibuffer;
					t_unibuffer . set((char *)&t_unichar, 2);

					// MW-2012-02-13: [[ Block Unicode ]] Use the new 'finsert' method in
					//   unicode mode.
					MCactivefield -> finsertnew(FT_IMEINSERT, t_unibuffer, LCH_UNICODE, true);
				}
			t_target -> kup(MCnullstring, t_event -> key . press . key_code);
		}
		break;

	case kMCEventTypeImeCompose:
		{
			if (!MCactivefield)
				break;

			if (t_event -> ime . compose . enabled)
				MCactivefield -> startcomposition();
			else
				MCactivefield -> stopcomposition(True, False);

			MCactivefield -> setcompositioncursoroffset(t_event -> ime . compose . offset * 2);

			MCString t_unichars;
			t_unichars . set((const char *)t_event -> ime . compose . chars, t_event -> ime . compose . char_count * sizeof(uint16_t));
			
			// MW-2012-02-13: [[ Block Unicode ]] Use the new 'finsert' method in
			//   unicode mode.
			MCactivefield -> finsertnew(FT_IMEINSERT, t_unichars, LCH_UNICODE, true);
			if (t_event -> ime . compose . enabled)
			{
				MCRectangle r;
				MCactivefield -> getcompositionrect(r, -1);
				MCModeConfigureIme(MCactivefield -> getstack(), true, r . x, r . y + r . height);
			}
		}
		break;
		
#ifdef _MOBILE
	case kMCEventTypeTouch:
		handle_touch(t_event -> touch . stack, t_event -> touch . phase, t_event -> touch . id, t_event -> touch . taps, t_event -> touch . x, t_event -> touch . y);
		break;
		
	case kMCEventTypeMotion:
		{
			MCNameRef t_message;
			const char *t_motion;
			switch(t_event -> motion . type)
			{
				case kMCEventMotionShakeBegan:
					t_motion = "shake";
					t_message = MCM_motion_start;
					break;
				case kMCEventMotionShakeEnded:
					t_motion = "shake";
					t_message = MCM_motion_end;
					break;
				case kMCEventMotionShakeCancelled:
					t_motion = "shake";
					t_message = MCM_motion_release;
					break;
			}
			
			MCdefaultstackptr -> getcurcard() -> message_with_args(t_message, t_motion);
		}
		break;
		
	case kMCEventTypeAcceleration:
		{
			char t_value[64 * 4 + 4];
			sprintf(t_value, "%.6f,%.6f,%.6f,%f", t_event -> acceleration . x, t_event -> acceleration . y, t_event -> acceleration . z, t_event -> acceleration . t);
			MCdefaultstackptr -> getcurcard() -> message_with_args(MCM_acceleration_changed, t_value);
		}
		break;
		
	case kMCEventTypeOrientation:
		MCdefaultstackptr -> getcurcard() -> message(MCM_orientation_changed);
		break;
		
	case kMCEventTypeLocation:
		MCdefaultstackptr -> getcurcard() -> message(t_event -> location . error == nil ? MCM_location_changed : MCM_location_error);
		break;
		
	case kMCEventTypeHeading:
		MCdefaultstackptr -> getcurcard() -> message(t_event -> location . error == nil ? MCM_heading_changed : MCM_heading_error);
		break;
		
	case kMCEventTypeCustom:
		t_event -> custom . event -> Dispatch();
		break;
#endif
	}
}
Ejemplo n.º 5
0
void MCPlatformHandleTextInputInsertText(MCPlatformWindowRef p_window, unichar_t *p_chars, uindex_t p_char_count, MCRange p_replace_range, MCRange p_selection_range, bool p_mark)
{
	if (!MCactivefield)
		return;
	
    // SN-2014-12-04: [[ Bug 14152 ]] Locking the screen here doesn't allow the screen to refresh after
    //  text input, inside an MCWait loop
//	MCRedrawLockScreen();
	
	int32_t t_r_si, t_r_ei;
	t_r_si = 0;
	t_r_ei = INT32_MAX;
	MCactivefield -> resolvechars(0, t_r_si, t_r_ei, p_replace_range . offset, p_replace_range . length);
	
    // SN-2014-09-15: [[ Bug 13423 ]] t_was_compositing now used further in the function
    bool t_was_compositing;
    t_was_compositing = false;
	if (!p_mark)
	{
        // MW-2014-08-05: [[ Bug 13098 ]] If we have been compositing, then don't synthesise a
        //   keyDown / keyUp.
		int4 si, ei;
		if (MCactivefield -> getcompositionrange(si, ei))
		{
			if (si < t_r_si)
				t_r_si -= MCMin(t_r_si - si, ei - si);
			if (si < t_r_ei)
				t_r_ei -= MCMin(t_r_ei - si, ei - si);
			
			MCactivefield -> stopcomposition(True, False);
            
            t_was_compositing = true;
		}
        else
            t_was_compositing = false;
		
		// If the char count is 1 and the replacement range matches the current selection,
		// the char is native and the requested selection is after the char, then synthesis a
		// keydown/up pair.        
        // MW-2014-06-25: [[ Bug 12370 ]] If the char is ascii then map appropriately so we get
        //   the keycodes the engine expects.
		char_t t_char;

		if (!t_was_compositing &&
            p_char_count == 1 &&
			MCUnicodeMapToNative(p_chars, 1, t_char) &&
			p_selection_range . offset == p_replace_range . offset + 1 &&
			p_selection_range . length == 0)
		{
			int32_t t_s_si, t_s_ei;
			MCactivefield -> selectedmark(False, t_s_si, t_s_ei, False);
			if (t_s_si == t_r_si &&
				t_s_ei == t_r_ei)
			{

                // SN-2014-09-15: [[ Bug 13423 ]] Send the messages for all the characters typed
                while (s_pending_key_down != nil)
                {
                    // MW-2014-04-15: [[ Bug 12086 ]] Pass the keycode from the last event that was
                    //   passed to the IME.
                    MCAutoStringRef t_mapped_char;
                    MCPlatformKeyCode t_mapped_key_code;

                    map_key_to_engine(s_pending_key_down -> key_code, s_pending_key_down -> mapped_codepoint, s_pending_key_down -> unmapped_codepoint, t_mapped_key_code, &t_mapped_char);
                    
                    // SN-2014-11-03: [[ Bug 13832 ]] Enqueue the event, instead of firing it now (we are still in the NSApplication's keyDown).
                    // PM-2015-05-15: [[ Bug 15372]] call MCKeyMessageAppend before wkdown to prevent a crash if 'wait with messages' is used (since s_pending_key_down might become nil after wkdown
                    MCKeyMessageAppend(s_pending_key_up, s_pending_key_down -> key_code, s_pending_key_down -> mapped_codepoint, s_pending_key_down -> unmapped_codepoint);
                    
                    MCdispatcher -> wkdown(p_window, *t_mapped_char, t_mapped_key_code);
                    
                    MCKeyMessageNext(s_pending_key_down);
                
                }
				return;
			}
		}
	}
	else
	{
		if (p_char_count == 0)
			MCactivefield -> stopcomposition(True, False);
		else
		{
			int4 si, ei;
			if (MCactivefield -> getcompositionrange(si, ei))
			{
				if (si < t_r_si)
					t_r_si -= MCMin(t_r_si - si, ei - si);
				if (si < t_r_ei)
					t_r_ei -= MCMin(t_r_ei - si, ei - si);
				
				MCactivefield -> stopcomposition(True, False);
			}
		}
	}
	
    // SN-2014-09-14: [[ Bug 13423 ]] MCPlatformHandleRawKeyDown gets the US mac layout key, without any modifier included.
    // We need to update the elements:
    // if the key pressed leads to an actual char:
    //    this wrong key is replaced by this new 'combined' char
    // if the key pressed fails to generate a char:
    //    this wrong key is replaced by the dead-key char
    // SN-2015-04-10: [[ Bug 14205 ]] When using the dictation, there is no
    //  pending key down, but the composition was still on though.
    // SN-2015-06-23: [[ Bug 3537 ]] We should not cast p_char as a uint1 if it
    //  is not a native char.
    uint1 t_char[2];
    bool t_is_native_char;
    t_is_native_char = MCUnicodeMapToNative(p_chars, 1, t_char[0]);
    t_char[1] = 0;
    
    if (t_was_compositing && s_pending_key_down && t_is_native_char)
    {
        s_pending_key_down -> key_code = (uint1)*t_char;
        s_pending_key_down -> mapped_codepoint = (uint1)*t_char;
        s_pending_key_down -> unmapped_codepoint = (uint1)*t_char;
        
        // SN-2015-05-18: [[ Bug 15385 ]] Enqueue the first char in the sequence
        //  here - that will be the same as keyDown.
        // SN-2015-06-23: [[ Bug 3537 ]] In this only case, we don't want this
        //  nativised char to be mapped again in MCPlatformHandleKeyUp.
        MCKeyMessageAppend(s_pending_key_up, (uint1)*t_char, (uint1)*t_char, (uint1)*t_char, false);
    }
    
	// Set the text.	
	MCactivefield -> seltext(t_r_si, t_r_ei, False);
	
	if (p_mark)
		MCactivefield -> startcomposition();
    
    // SN-2014-09-15: [[ Bug 13423 ]] If the character typed is not Unicode and follows a dead key character, then we send
    // [Raw]KeyDown/Up and remove the first character from the sequence of keys typed.
    // If the character successfully combined with the dead char before it in a native char, we don't use finsert
    // Otherwise, we have the dead char in p_chars, we need to remove the one stored first in the sequence
    MCAutoStringRef t_string;
    
    // SN-2015-01-20: [[ Bug 14406 ]] If we have a series of pending keys, we have two possibilities:
    //   - typing IME characters: the characters are native, so we use the finsertnew
    //   - typing dead characters: the character, if we arrive here, is > 127
    // SN-2015-04-13: [[ Bug 14205 ]] Ensure that s_pending_key_down is not nil
    if (*p_chars > 127 && s_pending_key_down && s_pending_key_down -> next
            && t_is_native_char)
    {
        MCStringCreateWithNativeChars((const char_t *)t_char, 1, &t_string);
        MCdispatcher -> wkdown(p_window, *t_string, *t_char);
        
        MCKeyMessageNext(s_pending_key_down);
    }
    else
    {
        MCStringCreateWithChars(p_chars, p_char_count, &t_string);
        
        // SN-2014-12-05: [[ Bug 14162 ]] In case the character is a Unicode alphanumeric char,
        // then that's not a combining char - and it deserves its (raw)Key(Down|Up) messages
        uint32_t t_codepoint;
        t_codepoint = MCStringGetCodepointAtIndex(*t_string, 0);
        
        // SN-2015-05-18: [[ Bug 3537 ]] Use p_mark to determine whether we are
        //  in an IME state
        // SN-2015-05-05: [[ Bug 15305 ]] Check that s_pending_key_down is not
        //  nil before trying to use it, and use IME only if p_mark says so.
        if (s_pending_key_down && !p_mark)
        {
            MCAutoStringRef t_mapped_char;
            MCPlatformKeyCode t_mapped_key_code;

            map_key_to_engine(s_pending_key_down -> key_code, s_pending_key_down -> mapped_codepoint, s_pending_key_down -> unmapped_codepoint, t_mapped_key_code, &t_mapped_char);

            MCdispatcher -> wkdown(p_window, *t_string, *p_chars);

            // SN-2015-05-18: [[ Bug 3537 ]] If we were compositing, then we want
            //  to send the same message for keyUp and keyDown - which might be
            //  seeveral character-long
            if (t_was_compositing)
                MCdispatcher -> wkup(p_window, *t_string, *p_chars);
            else
                MCKeyMessageAppend(s_pending_key_up, *p_chars, s_pending_key_down -> mapped_codepoint, s_pending_key_down -> unmapped_codepoint);
            
            MCKeyMessageNext(s_pending_key_down);
        }
        else
            MCactivefield -> finsertnew(FT_IMEINSERT, *t_string, True);
    }
	
	// And update the selection range.
	int32_t t_s_si, t_s_ei;
	t_s_si = 0;
	t_s_ei = INT32_MAX;
	MCactivefield -> resolvechars(0, t_s_si, t_s_ei, p_selection_range . offset, p_selection_range . length);
	MCactivefield -> setcompositioncursoroffset(t_s_si - t_r_si);
	MCactivefield -> seltext(t_s_si, t_s_ei, True);
	
    // SN-2014-12-04: [[ Bug 14152 ]] Locking the screen here doesn't allow the screen to refresh after
    //  text input, inside an MCWait loop
//	MCRedrawUnlockScreen();
}