Repository: godotengine/godot
File: editor/plugins/node_3d_editor_plugin.cpp (C++)

Code before:

	if (k.is_valid()) {
		if (!k->is_pressed()) {
			return;
		}

		if (_edit.instant) {
			// In a Blender-style transform, numbers set the magnitude of the transform.
			// E.g. pressing g4.5x means "translate 4.5 units along the X axis".
			// Use the Unicode value because we care about the text, not the actual keycode.
			// This ensures numbers work consistently across different keyboard language layouts.
			bool processed = true;
			Key key = k->get_physical_keycode();
			char32_t unicode = k->get_unicode();
			if (unicode >= '0' && unicode <= '9') {
				uint32_t value = uint32_t(unicode - Key::KEY_0);
				if (_edit.numeric_next_decimal < 0) {
					_edit.numeric_input = _edit.numeric_input + value * Math::pow(10.0, _edit.numeric_next_decimal--);
				} else {
					_edit.numeric_input = _edit.numeric_input * 10 + value;
				}
				update_transform_numeric();
			} else if (unicode == '-') {
				_edit.numeric_negate = !_edit.numeric_negate;
				update_transform_numeric();
			} else if (unicode == '.' || unicode == ',') {
				if (_edit.numeric_next_decimal == 0) {
					_edit.numeric_next_decimal = -1;
				}
			} else if (key == Key::ENTER || key == Key::KP_ENTER || key == Key::SPACE) {
				commit_transform();
			} else {
				processed = false;
			}

			if (processed) {
				// Ignore mouse inputs once we receive a numeric input.
				set_process_input(false);
				accept_event();
				return;
			}
		}

		if (EDITOR_GET("editors/3d/navigation/emulate_numpad")) {
			const Key code = k->get_physical_keycode();
			if (code >= Key::KEY_0 && code <= Key::KEY_9) {
				k->set_keycode(code - Key::KEY_0 + Key::KP_0);
			}
		}

		if (_edit.mode == TRANSFORM_NONE) {

Review comment (suggestion):
The comment above says:
```
// Use the Unicode value because we care about the text, not the actual keycode.
// This ensures numbers work consistently across different keyboard language layouts.
```
But I think that's a misunderstanding of the API, you shoudl use `get_keycode()` instead of `get_physical_keycode()` to get the keycode from the user's keyboard mapping.

And then for period specifically, using `get_physical_keycode()` to check that it's the en_US `KP_PERIOD` should also work I expect.

Code after:

	if (k.is_valid()) {
		if (!k->is_pressed()) {
			return;
		}

		if (_edit.instant) {
			// In a Blender-style transform, numbers set the magnitude of the transform.
			// E.g. pressing g4.5x means "translate 4.5 units along the X axis".
			bool processed = true;
			Key keycode = k->get_keycode();
			Key physical_keycode = k->get_physical_keycode();

			// Use physical keycode for main keyboard numbers (for non-QWERTY layouts like AZERTY)
			// but regular keycode for numpad numbers.
			if ((physical_keycode >= Key::KEY_0 && physical_keycode <= Key::KEY_9) || (keycode >= Key::KP_0 && keycode <= Key::KP_9)) {
				uint32_t value;
				if (physical_keycode >= Key::KEY_0 && physical_keycode <= Key::KEY_9) {
					value = uint32_t(physical_keycode - Key::KEY_0);
				} else {
					value = uint32_t(keycode - Key::KP_0);
				}

				if (_edit.numeric_next_decimal < 0) {
					_edit.numeric_input = _edit.numeric_input + value * Math::pow(10.0, _edit.numeric_next_decimal--);
				} else {
					_edit.numeric_input = _edit.numeric_input * 10 + value;
				}
				update_transform_numeric();
			} else if (keycode == Key::MINUS || keycode == Key::KP_SUBTRACT) {
				_edit.numeric_negate = !_edit.numeric_negate;
				update_transform_numeric();
			} else if (keycode == Key::PERIOD || physical_keycode == Key::KP_PERIOD) {
				// Use physical keycode for KP_PERIOD to ensure numpad period works consistently
				// across different keyboard layouts (like nordic keyboards).
				if (_edit.numeric_next_decimal == 0) {
					_edit.numeric_next_decimal = -1;
				}
			} else if (keycode == Key::ENTER || keycode == Key::KP_ENTER || keycode == Key::SPACE) {
				commit_transform();
			} else {
				processed = false;
			}

			if (processed) {
				// Ignore mouse inputs once we receive a numeric input.
				set_process_input(false);
				accept_event();
				return;
			}
		}