Permalink
Browse files

add new keyboard_mode property that can be 'global' or 'local'.

'local' will request the keyboard when a textarea / input[type=text] is focused.
+ (implement on_javascript_callback + on_external_host (not used))
-> 1.3 !
  • Loading branch information...
1 parent 74dc8e2 commit fa2d38c98fc5b0d122f48d82fdfcf0ff3e9d0638 @tito tito committed Feb 6, 2013
Showing with 238 additions and 36 deletions.
  1. +157 −14 berkelium/__init__.py
  2. +56 −4 berkelium/_berkelium.pyx
  3. +24 −17 berkelium/berkelium_wrapper.h
  4. +1 −1 setup.py
View
@@ -206,6 +206,16 @@ def onPaint(self):
print 'Wb(%x).onPaint()' % id(self)
self.impl.dispatch('on_paint')
+ def onJavascriptCallback(self, url, funcname):
+ if self.debug:
+ print 'Wb(%x).onJavascriptCallback()' % id(self)
+ self.impl.dispatch('on_javascript_callback', url, funcname)
+
+ def onExternalHost(self, message, origin, target):
+ if self.debug:
+ print 'Wb(%x).onExternalHost()' % id(self)
+ self.impl.dispatch('on_external_host', message, origin, target)
+
class Webbrowser(Widget):
'''Webbrowser class. See module documentation for more information.
@@ -241,6 +251,11 @@ class Webbrowser(Widget):
Fired when the Widget texture is updated
`on_paint`:
Fired when the texture is updated
+ `on_javascript_callback`:
+ Fired when a proxy function has been called (via
+ :meth:`add_bind_proxy_function_on_start_loading`)
+ `on_external_host`:
+ TBD
'''
#
@@ -356,12 +371,27 @@ def get_bk(self):
default to None.
'''
+ keyboard_mode = OptionProperty('global', options=('global', 'local'))
+ '''Keyboard mode to use.
+
+ The default behavior is "global": the global keyboard is binded to the
+ berkelium window. That's mean if you have 2 Berkelium widget, keys will be
+ used by both.
+
+ The other behavior is "local": the keyboard will be requested only when a
+ input[type="text"] will be focused. You can have more than one berkelium
+ window. If you're not in the input, no keys will works.
+
+ .. warning::
+ The keyboard_mode can be set only at the __init__() time. Any further
+ changes to the property will have no impact.
+ '''
+
def __init__(self, **kwargs):
_init_berkelium()
# Before doing anything, ensure the windows exist.
EventLoop.ensure_window()
- EventLoop.window.bind(on_keyboard=self.on_window_keyboard)
self._touches = []
self._bk = _WindowDelegate(self, self.width, self.height,
@@ -381,6 +411,8 @@ def __init__(self, **kwargs):
self.register_event_type('on_widget_move')
self.register_event_type('on_widget_paint')
self.register_event_type('on_paint')
+ self.register_event_type('on_javascript_callback')
+ self.register_event_type('on_external_host')
super(Webbrowser, self).__init__(**kwargs)
if self.url is not None:
self.open_url(self.url)
@@ -390,19 +422,11 @@ def __init__(self, **kwargs):
self._g_rect.tex_coords = (0, 1, 1, 1, 1, 0, 0, 0)
_install_berkelium_update(self)
- def on_window_keyboard(self, instance, key, scancode, text, modifiers):
- # handle first special keys
- if key in map(ord, ('\b', '\r', '\n', ' ')) or \
- ord('a') >= key <= ord('z') or \
- ord('A') >= key <= ord('Z'):
- vk_code = ord(chr(key).lower())
- vwmods = 0
- for modifier in modifiers:
- vwmods |= self._bk.modifiers.get(modifier, 0)
- self._bk.keyEvent(1, vwmods, vk_code, 0)
-
- if text is not None:
- self._bk.textEvent(text)
+ self._keyboard = None
+ if self.keyboard_mode == 'global':
+ EventLoop.window.bind(on_keyboard=self._on_global_keyboard)
+ else:
+ self._install_local_keyboard()
def on_size(self, instance, value):
w, h = map(int, value)
@@ -654,6 +678,29 @@ def execute_javascript(self, string):
'''
return self._bk.executeJavascript(string)
+ def bind_proxy_function(self, name, sync=False):
+ '''Bind a JS name as a function. You get the result in the
+ `on_javascript_callback`
+ '''
+ self._bk.bindProxyFunction(name, sync)
+
+ def add_bind_proxy_function_on_start_loading(self, name, sync=False):
+ '''Same as :meth:`bind_proxy_function`, except that it will be done
+ every page load
+ '''
+ self._bk.addBindProxyFunctionOnStartLoading(name, sync)
+
+ def add_eval_on_start_loading(self, script):
+ '''Add a script to eval every page
+ '''
+ self._bk.addEvalOnStartLoading(script)
+
+ def clear_start_loading(self):
+ '''Clear any previous work done via :meth:`add_eval_on_start_loading`
+ and :meth:`add_bind_proxy_function_on_start_loading`.
+ '''
+ self._bk.clearStartLoading()
+
# default handlers
def on_start_loading(self, url):
pass
@@ -713,6 +760,102 @@ def on_widget_paint(self, _id, texture):
def on_paint(self):
self.canvas.ask_update()
+ def on_javascript_callback(self, url, funcname):
+ pass
+
+ def on_external_host(self, message, origin, target):
+ pass
+
+
+ #
+ # Local keyboard handlers
+ #
+
+ def _install_local_keyboard(self):
+ def _on_javascript_callback(instance, url, func):
+ if func == 'bk_request_keyboard':
+ self._request_keyboard()
+ return True
+ if func == 'bk_release_keyboard':
+ self._release_keyboard()
+ return True
+ self.bind(on_javascript_callback=_on_javascript_callback)
+ self.add_bind_proxy_function_on_start_loading('bk_request_keyboard')
+ self.add_bind_proxy_function_on_start_loading('bk_release_keyboard')
+ self.add_eval_on_start_loading('''
+ var _keyboard_requested = false;
+ function _check_keyboard_needed() {
+ setTimeout('_check_keyboard_needed()', 200);
+ var obj = document.activeElement;
+ if ( !obj )
+ return;
+ if (
+ (obj.tagName == 'INPUT' && obj.type == 'text') ||
+ (obj.tagName == 'TEXTAREA')
+ ) {
+ if ( !_keyboard_requested ) {
+ bk_request_keyboard();
+ _keyboard_requested = true;
+ }
+ return;
+ }
+ if ( _keyboard_requested ) {
+ bk_release_keyboard();
+ _keyboard_requested = false;
+ }
+ }
+ _check_keyboard_needed();
+ ''')
+
+ def _request_keyboard(self):
+ self._keyboard = EventLoop.window.request_keyboard(self._on_keyboard_released, self)
+ self._keyboard.bind(on_key_down=self._on_local_keyboard)
+
+ def _release_keyboard(self):
+ if not self._keyboard:
+ return
+ self._keyboard.unbind(on_key_down=self._on_local_keyboard)
+ self._keyboard.release()
+
+ def _on_keyboard_released(self):
+ self._release_keyboard()
+
+ def _on_global_keyboard(self, instance, key, scancode, text, modifiers):
+ # handle first special keys
+ if key in map(ord, ('\b', '\r', '\n', ' ')) or \
+ ord('a') >= key <= ord('z') or \
+ ord('A') >= key <= ord('Z'):
+ vk_code = ord(chr(key).lower())
+ vwmods = 0
+ for modifier in modifiers:
+ vwmods |= self._bk.modifiers.get(modifier, 0)
+ self._bk.focus()
+ self._bk.keyEvent(1, vwmods, vk_code, 0)
+
+ if text is not None:
+ self._bk.textEvent(text)
+
+ def _on_local_keyboard(self, instance, key, text, modifiers):
+ if key[0] == 27:
+ self.unfocus()
+ self._keyboard.release()
+ return
+
+ if key[0] in map(ord, ('\b', '\r', '\n', ' ')) or \
+ ord('a') >= key <= ord('z') or \
+ ord('A') >= key <= ord('Z'):
+ vk_code = ord(chr(key[0]).lower())
+ vwmods = 0
+ for modifier in modifiers:
+ vwmods |= self._bk.modifiers.get(modifier, 0)
+ self._bk.keyEvent(1, vwmods, vk_code, 0)
+
+ # needed to make the enter key working.
+ if key[0] == 13:
+ text = '\r'
+
+ if text is not None:
+ self._bk.textEvent(text)
class WebbrowserChildWidget(Widget):
'''WebbrowserWidget class. See module documentation for more information.
View
@@ -52,6 +52,9 @@ cdef extern from "berkelium/StringUtil.hpp":
cdef extern from "berkelium/Window.hpp":
ctypedef char* const_wchar_ptr "const wchar_t*"
ctypedef char* wchar_t "wchar_t*"
+ cdef cppclass ScriptVariant "Script::Variant":
+ pass
+ ctypedef ScriptVariant ScriptVariantConst "const Script::Variant"
cdef cppclass Window "Berkelium::Window":
#int is_crashed()
void ShowRepostFormWarningDialog()
@@ -80,8 +83,14 @@ cdef extern from "berkelium/Window.hpp":
bool canGoForward()
void setTransparent(bool istrans)
void executeJavascript(WideString js)
+ void bind(WideString lvalue, ScriptVariantConst rvalue)
+ void addBindOnStartLoading(WideString lvalue, ScriptVariantConst rvalue)
+ void addEvalOnStartLoading(WideString script)
+ void clearStartLoading()
cdef Window *Window_create "Berkelium::Window::create"(Context *)
+ cdef ScriptVariant Script_Variant_bindFunction \
+ "Berkelium::Script::Variant::bindFunction" (WideString s, bool)
cdef extern from "berkelium/Widget.hpp":
ctypedef object _Rect "Rect"
@@ -136,6 +145,11 @@ cdef extern from "berkelium_wrapper.h":
ctypedef void (*tp_onWidgetPaint)(object obj, Window *win, Widget *wid, unsigned char * bitmap_in, Rect &bitmap_rect, size_t num_copy_rects, Rect *copy_rects, int dx, int dy, Rect &scroll_rect)
ctypedef void (*tp_onWidgetDestroyed)(object obj, Window *win, Widget *wid)
ctypedef void (*tp_onPaint)(object obj, Window *wini, unsigned char *bitmap_in, Rect &bitmap_rect, size_t num_copy_rects, Rect *copy_rects, int dx, int dy, Rect &scroll_rect)
+ ctypedef void (*tp_onJavascriptCallback)(object obj, Window *win, char *url,
+ int url_length, char *funcName, int funcName_length)
+ ctypedef void (*tp_onExternalHost)(object obj, Window *win, char *message,
+ int message_length, char *origin, int origin_length, char *target,
+ int target_length)
cdef cppclass CyWindowDelegate:
CyWindowDelegate(object obj)
@@ -161,8 +175,10 @@ cdef extern from "berkelium_wrapper.h":
tp_onWidgetResize impl_onWidgetResize
tp_onWidgetMove impl_onWidgetMove
tp_onWidgetPaint impl_onWidgetPaint
- tp_onWidgetDestroyed impl_onWidgetDestroyed
+ tp_onWidgetDestroyed impl_onWidgetDestroyed
tp_onPaint impl_onPaint
+ tp_onJavascriptCallback impl_onJavascriptCallback
+ tp_onExternalHost impl_onExternalHost
def init(bytes berkelium_path):
@@ -385,6 +401,8 @@ cdef class WindowDelegate:
self.impl.impl_onWidgetPaint = <tp_onWidgetPaint>self.impl_onWidgetPaint
self.impl.impl_onWidgetDestroyed = <tp_onWidgetDestroyed>self.impl_onWidgetDestroyed
self.impl.impl_onPaint = <tp_onPaint>self.impl_onPaint
+ self.impl.impl_onJavascriptCallback = <tp_onJavascriptCallback>self.impl_onJavascriptCallback
+ self.impl.impl_onExternalHost = <tp_onExternalHost>self.impl_onExternalHost
def __init__(self, int width, int height, int usetrans):
self.scroll_buffer = <char *>malloc(width*(height+1)*4)
@@ -577,6 +595,14 @@ cdef class WindowDelegate:
self.needs_full_refresh = 0
self.onPaint()
+ cdef void impl_onJavascriptCallback(self, Window *win, char *url, int
+ url_length, char *funcName, int funcName_length):
+ self.onJavascriptCallback(url[:url_length], funcName[:funcName_length])
+
+ cdef void impl_onExternalHost(self, Window *win, char *message, int message_length, char *origin, int origin_length, char *target, int target_length):
+ self.onExternalHost(message[:message_length], origin[:origin_length],
+ target[:target_length])
+
#
# Default Python handlers
# XXX This could be removed, since they are all already defined in the
@@ -643,6 +669,12 @@ cdef class WindowDelegate:
def onPaint(self):
pass
+ def onJavascriptCallback(self, url, func):
+ pass
+
+ def onExternalHost(self, message, origin, target):
+ pass
+
#
# Public methods
#
@@ -749,11 +781,31 @@ cdef class WindowDelegate:
self.impl.getWindow().setTransparent(is_trans)
def executeJavascript(self, js):
- cdef char *c_js = <bytes>js
- cdef UTF8String u1 = UTF8String().point_to(c_js, len(js))
- cdef WideString w1 = UTF8ToWide(u1)
+ cdef WideString w1 = self.createWideString(<bytes>js)
self.impl.getWindow().executeJavascript(w1)
+ def bindProxyFunction(self, name, sync=False):
+ cdef WideString w1 = self.createWideString(<bytes>name)
+ cdef ScriptVariant s1 = Script_Variant_bindFunction(w1, sync)
+ self.impl.getWindow().bind(w1, s1)
+
+ def addBindProxyFunctionOnStartLoading(self, name, sync=False):
+ cdef WideString w1 = self.createWideString(<bytes>name)
+ cdef ScriptVariant s1 = Script_Variant_bindFunction(w1, sync)
+ self.impl.getWindow().addBindOnStartLoading(w1, s1)
+
+ def addEvalOnStartLoading(self, script):
+ cdef WideString w1 = self.createWideString(<bytes>script)
+ self.impl.getWindow().addEvalOnStartLoading(w1)
+
+ def clearStartLoading(self):
+ self.impl.getWindow().clearStartLoading()
+
+ cdef WideString createWideString(self, bytes s):
+ cdef UTF8String u1 = UTF8String().point_to(s, len(s))
+ cdef WideString w1 = UTF8ToWide(u1)
+ return w1
+
property texture:
def __get__(self):
return self.fbo.texture
Oops, something went wrong.

0 comments on commit fa2d38c

Please sign in to comment.