Previous Thread
Next Thread
Print Thread
Page 9 of 80 1 2 7 8 9 10 11 79 80
Joined: Feb 2014
Posts: 1,135
Likes: 198
G
Very Senior Member
Very Senior Member
G Offline
Joined: Feb 2014
Posts: 1,135
Likes: 198
I was trying to wrap my head around the code of how mame does its UI Paste function (and also the lua does its emu.keypost()) because the text pasting in the apple2e driver seems to scramble the input.

Grep is pretty useful to scan the whole source tree because I couldn't figure out where things are:

-r is recursive
-i is ignore case

Code
grep -r -i "keypost" src/
src/frontend/mame/luaengine.cpp: * emu.keypost(keys) - post keys to natural keyboard
src/frontend/mame/luaengine.cpp:	emu["keypost"] = [this](const char *keys){ machine().ioport().natkeyboard().post_utf8(keys); };
src/frontend/mame/mame.cpp:		std::string val = std::string("emu.keypost('").append(cmd).append("')");


grep -r -i "post_utf8" src/
src/emu/natkeyboard.cpp://  post_utf8 - post a UTF-8 encoded string
src/emu/natkeyboard.cpp:void natural_keyboard::post_utf8(const char *text, size_t length, const attotime &rate)
src/emu/natkeyboard.h:	void post_utf8(const char *text, size_t length = 0, const attotime &rate = attotime::zero);
src/frontend/mame/ui/ui.cpp:		machine().ioport().natkeyboard().post_utf8(text);
src/frontend/mame/luaengine.cpp:	emu["keypost"] = [this](const char *keys){ machine().ioport().natkeyboard().post_utf8(keys); };


grep -r -i "paste" src/
...
src/frontend/mame/ui/ui.h:	bool can_paste();
src/frontend/mame/ui/ui.h:	void paste();
src/frontend/mame/ui/ui.cpp://  can_paste
src/frontend/mame/ui/ui.cpp:bool mame_ui_manager::can_paste()
src/frontend/mame/ui/ui.cpp://  paste - does a paste from the keyboard
src/frontend/mame/ui/ui.cpp:void mame_ui_manager::paste()
src/frontend/mame/ui/ui.cpp:		// paste command
src/frontend/mame/ui/ui.cpp:		if (machine().ui_input().pressed(IPT_UI_PASTE))
src/frontend/mame/ui/ui.cpp:			paste();


and the actual paste code in ui.cpp:

//-------------------------------------------------
//  paste - does a paste from the keyboard
//-------------------------------------------------

void mame_ui_manager::paste()
{
	// retrieve the clipboard text
	char *text = osd_get_clipboard_text();

	// was a result returned?
	if (text != nullptr)
	{
		// post the text
		machine().ioport().natkeyboard().post_utf8(text);

		// free the string
		free(text);
	}
}




So it uses the natural keyboard mapping, and what's interesting is if I launch mame with the -natural option, I lose a lot of keyboard functionality.

./mame64 apple2e -natural

Ctrl+C, Ctrl+F doesn't work, left and right arrow don't work, ESC key doesn't work, and the @ disappear and various symbols are shifted.

Also it seems that the keyboard has gotten a lot slower in the "natural mode", there's a bunch of latency and it can't keep up with fast typing.

Joined: Feb 2004
Posts: 2,608
Likes: 315
Very Senior Member
Very Senior Member
Joined: Feb 2004
Posts: 2,608
Likes: 315
Natural keyboard mode will never work particularly well, since it's a pretty much impossible set of requirements. It's supposed to translate host character input to emulated keystrokes. Not all keystrokes produce characters, some characters require multiple keystrokes to produce, and IME edit opens another whole can of worms. It kinda works for simple cases, but it's always going to be something that's nice if it works at best.

Joined: May 2009
Posts: 2,223
Likes: 387
J
Very Senior Member
Very Senior Member
J Offline
Joined: May 2009
Posts: 2,223
Likes: 387
Sounds like something that should be implemented or enabled on a per-driver basis, then. Otherwise it seems like exactly the sort of half-baked, user-hostile, anti-feature that MAME is infamous for. It violates the hell out of the rule of least surprise.

Joined: Feb 2004
Posts: 2,608
Likes: 315
Very Senior Member
Very Senior Member
Joined: Feb 2004
Posts: 2,608
Likes: 315
Natural keyboard mode isn't enabled by default, you have to use -natural on command line or go into the menu and switch it on. It works a lot better than it used to provided the PORT_CHAR declarations for the driver are done properly. It also performs a bit better in 0.190 than it did before, as I eliminated an O(n) lookup, but the speed at which it generates keystrokes is still pretty conservative, as it has to work with some slow systems.

I had a quick look at the apple2e driver and it seems to have the wrong PORT_CHAR for a few keys, as though it was quickly copy/pasted from the Apple II+ and not fully updated (Apple II+ uses a "bitshift" style layout, while Apple IIe uses a "typewriter shift" style layout). I'm not going to mess with trying to make control keys work in natural mode, as that's problematic, but I've tried to at least fix the shifted digits and arrow keys in natural keyboard mode with 64ac8e4. I've only tried fixing the US Apple IIe and variants, not the UK, French and Spanish versions.

Note that the Apple II drivers are set up to translate uppercase letters to unshifted letter keys for natural keyboard/UI paste/keypost. If you type/paste/post lowercase letters, it will press the emulated shift key when typing each one.

Joined: Feb 2014
Posts: 1,135
Likes: 198
G
Very Senior Member
Very Senior Member
G Offline
Joined: Feb 2014
Posts: 1,135
Likes: 198
Thanks Vas,

I just gave it a try and the missing characters type properly now in a paste. Yay!


Joined: Feb 2014
Posts: 1,135
Likes: 198
G
Very Senior Member
Very Senior Member
G Offline
Joined: Feb 2014
Posts: 1,135
Likes: 198
I really wanted to have a proper "delay after a CR" during a paste so that after a CR, you'd have a delay while the computer would process the line of input.

If you have a key pressed too long on the Apple2e, it starts to auto repeat. So you want your delay AFTER the CR has been pressed and released.

Calling m_timer->adjust(choose_delay(m_buffer[m_bufbegin])); doesn't really give you a proper delay amount, especially since this function gets executed at least twice for each keypress/release.

I wrestled mightily with the function natural_keyboard::timer to get a delay that was "long" without triggering the autorepeat.

This function actually first "presses" all of the fields for a given keycode, then it releases them one by one each time it gets called after that. It seems really counter-intuitive. One of the things that really threw me for a loop is that it does things "reversed" like field->set_value(!m_status_keydown). m_status_keydown comes in as false, it sets all the fields, then it flips the m_status_keydown.

I haven't tested this very much, but it seems to work for the couple of pastes I've thrown at it.


Code
void natural_keyboard::timer(void *ptr, int param)
{

attotime next_delay = attotime::from_msec(20);  
	if (!m_queue_chars.isnull())
	{
		// the driver has a queue_chars handler
		while (!empty() && m_queue_chars(&m_buffer[m_bufbegin], 1))
		{
			m_bufbegin = (m_bufbegin + 1) % m_buffer.size();
			if (m_current_rate != attotime::zero)
				break;
		}
	}
	else
	{
		// the driver does not have a queue_chars handler

		// loop through this character's component codes
		const keycode_map_entry *const code = find_code(m_buffer[m_bufbegin]);
		bool advance;
		if (code)
		{
			do
			{
				assert(m_fieldnum < ARRAY_LENGTH(code->field));
				ioport_field *const field = code->field[m_fieldnum];
				if (field)
				{
					// special handling for toggle fields
					if (!field->live().toggle)
						field->set_value(!m_status_keydown);
					else if (!m_status_keydown)
						field->set_value(!field->digital_value());
				}
			}
			while (code->field[m_fieldnum] && (++m_fieldnum < ARRAY_LENGTH(code->field)) && m_status_keydown);
			advance = (m_fieldnum >= ARRAY_LENGTH(code->field)) || !code->field[m_fieldnum];

// if we're at a CR then let's set the next delay for 5 seconds
 if (m_status_keydown && (m_buffer[m_bufbegin] == '\r') && (advance)) next_delay = attotime::from_msec(5000);
		}
		else
		{
			advance = true;
		}

		if (advance)
		{
			m_fieldnum = 0;
			m_status_keydown = !m_status_keydown;

			// proceed to next character when keydown expires
			if (!m_status_keydown)
				m_bufbegin = (m_bufbegin + 1) % m_buffer.size();

		}
	}

       // m_status_keydown has already been flipped for the next invocation
	// need to make sure timerproc is called again if buffer not empty
	if (!empty())
m_timer->adjust(next_delay);

}

Joined: Mar 2001
Posts: 17,239
Likes: 263
R
Very Senior Member
Very Senior Member
R Offline
Joined: Mar 2001
Posts: 17,239
Likes: 263
Originally Posted by Just Desserts
Sounds like something that should be implemented or enabled on a per-driver basis, then. Otherwise it seems like exactly the sort of half-baked, user-hostile, anti-feature that MAME is infamous for. It violates the hell out of the rule of least surprise.

On the contrary, it's exactly the sort of user-friendliness you advocate: it changes the keyboard emulation from matching the layout of the original at the expense of what's actually marked on your PC keyboard to (attempting to) make it so e.g. shift-2 on a US keyboard is always @, even on machines where shift-2 is " or a UK pound sign or whatever. I would argue that having keys on your PC keyboard *not* generate the same thing on the emulated system is actually the major violation of least-surprise here. In particular, pretty much all other computer emulators *only* have an equivalent of natural keyboard mode.

Joined: May 2004
Posts: 1,772
Likes: 34
H
Very Senior Member
Very Senior Member
H Offline
Joined: May 2004
Posts: 1,772
Likes: 34
it's user unfriendly when it doesn't work for games etc. because it never really seems to register keys as held down, only 'pressed once' especially if they're shifted keys or whatever else..

while the idea is good in concept, the implementation of it is definitely horrible and acts in completely unexpected ways and how you toggle it on / off at runtime doesn't seem to be common knowledge either.



Last edited by Haze; 10/09/17 01:32 PM.
Joined: Mar 2001
Posts: 17,239
Likes: 263
R
Very Senior Member
Very Senior Member
R Offline
Joined: Mar 2001
Posts: 17,239
Likes: 263
Yes, we all agree the implementation sucks; it should hold down the keys on the emulated keyboard for the same amount of time that the user holds down the original key(s) etc. But the concept is pretty much industry-standard.

Joined: Feb 2004
Posts: 2,608
Likes: 315
Very Senior Member
Very Senior Member
Joined: Feb 2004
Posts: 2,608
Likes: 315
What are all the PC emulators doing "natural keyboard' translation? It definitely isn't VirtualBox or VMware - both of those map keys directly. DOSbox kind of does for DOS itself by virtue of the fact that it's HLE'ing the character input function, but when a program accesses the keyboard directly it reads the keys that are down directly.

It's impossible to hold the same amount of time, because there isn't a 1:1 correspondence between keys and characters. It's also impossible to "translate" modifiers since it's all over the shop with whether something uses a modifier or not. Let's use some real-world examples of why you can't do perfect translation.

Emulated system has a JIS "bitshift" keyboard, host system has a US "typewriter" layout keyboard:
  • User presses Right Shift
  • User presses 2 (on host this types an '@' character)
  • User releases 2
  • User releases RIght Shift


On the emulated system, typing '@' does not involve the shift key at all - it's the key to the right of P unshifted (this key has '[' on the host keyboard). So if you're trying to translate modifiers, what do you do? Press the emulated shift key, then release it for some amount of time before pressing the @ key, then press it again after releasing the emulated @ key?

Same emulated and host configurations:
  • User presses ' (on host this types a "single straight quote")
  • User releases '


The emulated system requires you to type Shift-7 to type a ' character. You're going to need to press the emulated shift key, wait long enough to ensure matrix scanning can detect it, press the emulated 7 key, and then release both keys.

It gets even messier with dead keys. Emulated system had a German DIN keyboard, host has Windows US International layout:
  • User presses Left Shift
  • User presses ' (on host system this initiates a dead key sequence)
  • User releases '
  • User releases Left Shift
  • User presses U (on host system this types ΓΌ because of the current dead key state)
  • User releases U


On the emulated system, this is a single keystroke - the key to the right of P, with no modifiers at all. You can't translate all the keystrokes leading up to the character being typed, because they don't actually produce characters.

What about a failed dead key sequence? Same emulated and host configurations:
  • User presses Left Shift
  • User presses ' (on host system this initiates a dead key sequence)
  • User releases '
  • User releases Left Shift
  • User presses X (on host system this types "x because there's no mapping for X in the current dead key state)
  • User releases X


You can't press the emulated keys for the " (shift-2) when the user starts the dead key sequence, because you can't anticipate the next character they'll type. You need to do the whole sequence when they press X.

You have no way of knowing whether the emulated system is running a game or other program that processes raw keystrokes and works best with everything passed through based on position, or it's running something accepting character input and you should translate characters to keystrokes. And what if it's both? You could be typing into a text editor while some other program is snooping the keyboard directly.

Also, if you want to be able to hold the key for a corresponding amount of time, you need to be doing key translation yourself. You don't get information on when a key is pressed/released from character input events. To be able to pass that through to the emulated system (assuming you had correspondence between keystrokes on both sides to begin with), you'd need to load the host system's keyboard layout, do translation from keystrokes to characters yourself, including dead key mapping, etc. and then pass it through. This would be a big mess of OS-dependent code, and it would have no chance of working at all for languages with IME edit.

If I'm completely missing something that makes this simple, please point it out to me. But I'm really sick of people saying natural keyboard is best and should work properly, when decades of dealing with multiple language support across operating systems tells me it's impossible to do in a satisfactory way, and what we've got now is about the best compromise we're going to get.

Page 9 of 80 1 2 7 8 9 10 11 79 80

Link Copied to Clipboard
Who's Online Now
0 members (), 80 guests, and 6 robots.
Key: Admin, Global Mod, Mod
ShoutChat
Comment Guidelines: Do post respectful and insightful comments. Don't flame, hate, spam.
Forum Statistics
Forums9
Topics9,331
Posts122,197
Members5,077
Most Online1,283
Dec 21st, 2022
Our Sponsor
These forums are sponsored by Superior Solitaire, an ad-free card game collection for macOS and iOS. Download it today!

Superior Solitaire
Powered by UBB.threads™ PHP Forum Software 8.0.0